apiVersion: apps/v1
kind: Deployment
metadata: name: httpd-deployment
spec:selector:matchLabels:app: httpd # 通过标签选择被控制的podreplicas: 3template:metadata:labels:app: httpd # 给pod打上标签,Service、Deployment 将会用这个 label 来挑选 Podspec:containers:- name: httpdimage: httpdports:- containerPort: 80 # 转发到后端pod的端口号 Pod分配了各自的IP地址,但这些IP只能被Kubernetes Cluster中的容器与节点访问。
apiVersion: v1
kind: Service
metadata:name: httpd-service # 必填,service名称
spec:selector:app: httpd # 必填,在selector字段中指定了为哪一个标签的app进行负载均衡ports: # 将 Service 的 8080 端口映射到 Pod 的 80 端口,使用 TCP 协议- protocol: TCPport: 8080 # service监听端口targetPort: 80 # 转发到后端pod的端口号 httpd-service分配到一个CLUSTER-IP,可以通过该IP访问后端的httpd Pod。
除了我们创建的 httpd-svc,还有一个 Service kubernetes,Cluster 内部通过这个 Service 访问 kubernetes API Server。
kubectl describe service httpd-service 查看service与Pod的对应关系:
$ sudo iptables-save | grep '10.98.165.152'
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.98.165.152/32 -p tcp -m comment --comment "default/httpd-service cluster IP" -m tcp --dport 8080 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.98.165.152/32 -p tcp -m comment --comment "default/httpd-service cluster IP" -m tcp --dport 8080 -j KUBE-SVC-EHNHZY2AA2RZYURI 这两条规则的含义:
1、若Cluster内的Pod(源地址来自10.244.0.0/16)要访问httpd-service,则允许; 2、其他源地址访问httpd-service(10.98.165.152/32),跳转到规则KUBE-SVC-EHNHZY2AA2RZYURI。 KUBE-SVC-EHNHZY2AA2RZYURI规则如下:-A KUBE-SVC-EHNHZY2AA2RZYURI -m comment --comment "default/httpd-service" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-RWFU5RJRM7QIVQGD
-A KUBE-SVC-EHNHZY2AA2RZYURI -m comment --comment "default/httpd-service" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CX4QANADYSW4JX2E
-A KUBE-SVC-EHNHZY2AA2RZYURI -m comment --comment "default/httpd-service" -j KUBE-SEP-HGKXYQ3Y7I7MLDXP -A KUBE-SEP-RWFU5RJRM7QIVQGD -s 10.244.1.13/32 -m comment --comment "default/httpd-service" -j KUBE-MARK-MASQ
-A KUBE-SEP-RWFU5RJRM7QIVQGD -p tcp -m comment --comment "default/httpd-service" -m tcp -j DNAT --to-destination 10.244.1.13:80
-A KUBE-SEP-CX4QANADYSW4JX2E -s 10.244.1.14/32 -m comment --comment "default/httpd-service" -j KUBE-MARK-MASQ
-A KUBE-SEP-CX4QANADYSW4JX2E -p tcp -m comment --comment "default/httpd-service" -m tcp -j DNAT --to-destination 10.244.1.14:80
-A KUBE-SEP-HGKXYQ3Y7I7MLDXP -s 10.244.2.5/32 -m comment --comment "default/httpd-service" -j KUBE-MARK-MASQ
-A KUBE-SEP-HGKXYQ3Y7I7MLDXP -p tcp -m comment --comment "default/httpd-service" -m tcp -j DNAT --to-destination 10.244.2.5:80 即将请求分别转发到后端的三个 Pod。 通过上面的分析,我们得到如下结论: iptables 将访问 Service 的流量转发到后端 Pod,而且使用类似轮询的负载均衡策略。 Cluster的每个节点都配置了相同的iptables规则,这样就确保了Cluster都能通过Service的Cluster IP访问Service。
coredns是个DNS服务器,每当有新的Service被创建,coredns会添加该Service的DNS记录。
Cluster中的Pod可通过
用 nslookup 查看 httpd-service 的 DNS 的信息:
DNS服务器是httpd-service.default.svc.cluster.local,这实际上就是coredns组件,本身部署在kube-system namespace中的一个service。
httpd-service.default.svc.cluster.local是http-service的完整域名。
apiVersion: apps/v1
kind: Deployment
metadata:name: httpd2-deploymentnamespace: kube-public # 指定命名空间
spec:selector: # 通过标签选择被控制的podmatchLabels:app: httpd2replicas: 2template:metadata:labels:app: httpd2 # 给pod打上标签,Service、Deployment 将会用这个 label 来挑选 Podspec:containers:- name: httpd2image: httpdports:- containerPort: 80 # 转发到后端pod的端口号--- # 多个资源可以在一个 YAML 文件中定义,用 --- 分割
apiVersion: v1
kind: Service
metadata:name: httpd2-servicenamespace: kube-public # 指定命名空间
spec:selector:app: httpd2ports: # 将 Service 的 8080 端口映射到 Pod 的 80 端口,使用 TCP 协议- protocol: TCPport: 8080 # service监听端口targetPort: 80 # 转发到后端pod的端口号 
ClusterIP: Service通过Cluster内部的IP对外提供服务,只有Cluster内部的节点跟Pod可以访问。 NodePort: Service通过Cluster节点的静态端口对外提供服务。Cluster外部可以通过: 访问Service。 LoadBalancer: Service利用cloud provider特有的load balancer对外提供服务,cloud provider 负责将 load balancer 的流量导向 Service。 目前支持的 cloud provider 有 GCP、AWS、Azur 等。
apiVersion: apps/v1
kind: Deployment
metadata:name: httpd3-deploymentnamespace: kube-public # 指定命名空间
spec:selector: # 通过标签选择被控制的podmatchLabels:app: httpd3replicas: 1template:metadata:labels:app: httpd3 # 给pod打上标签,Service、Deployment 将会用这个 label 来挑选 Podspec:containers:- name: httpd3image: httpdports:- containerPort: 80 # 转发到后端pod的端口号--- # 多个资源可以在一个 YAML 文件中定义,用 --- 分割
apiVersion: v1
kind: Service
metadata:name: httpd3-servicenamespace: kube-public # 指定命名空间
spec:type: NodePort # 添加NodePort类型的Serviceselector:app: httpd3ports: # 将 Service 的 8080 端口映射到 Pod 的 80 端口,使用 TCP 协议- protocol: TCPport: 8080 # service监听端口targetPort: 80 # 转发到后端pod的端口号
httpd3-service的TYPE为 NodePort,表示可通过 Cluster 每个节点自身的 IP 访问 Service。
PORT(S)为 8080:30150/TCP,8080是ClusterIp监听的端口,30150是节点上监听的端口,Kubernetes会从 30000-32767 中分配一个可用的端口,每个节点都会监听此端口并将请求转发给 Service。
测试 NodePort 是否正常工作:通过三个节点 IP + 端口都能够访问 httpd3-service
$ sudo iptables-save | grep 'httpd3-service'
-A KUBE-NODEPORTS -p tcp -m comment --comment "kube-public/httpd3-service" -m tcp --dport 30150 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "kube-public/httpd3-service" -m tcp --dport 30150 -j KUBE-SVC-X5MD3Z6GVRFIQV4Q 规则的含义:访问当前节点30150端口的请求会被应用规则KUBE-SVC-X5MD3Z6GVRFIQV4Q
KUBE-SVC-X5MD3Z6GVRFIQV4Q规则如下:-A KUBE-SVC-X5MD3Z6GVRFIQV4Q -m comment --comment "kube-public/httpd3-service" -j KUBE-SEP-CA4JWI7MMTWMJLYK KUBE-SEP-CA4JWI7MMTWMJLYK规则如下: -A KUBE-SEP-CA4JWI7MMTWMJLYK -s 10.244.1.27/32 -m comment --comment "kube-public/httpd3-service" -j KUBE-MARK-MASQ
-A KUBE-SEP-CA4JWI7MMTWMJLYK -p tcp -m comment --comment "kube-public/httpd3-service" -m tcp -j DNAT --to-destination 10.244.1.27:80 NodePort默认的是从 30000-32767 中随机分配一个可用的端口,但我们可以用nodePort指定某个特定的端口:
# 编辑httpd3.yamlapiVersion: apps/v1
kind: Deployment
metadata:name: httpd3-deploymentnamespace: kube-public # 指定命名空间
spec:selector: # 通过标签选择被控制的podmatchLabels:app: httpd3replicas: 1template:metadata:labels:app: httpd3 # 给pod打上标签,Service、Deployment 将会用这个 label 来挑选 Podspec:containers:- name: httpd3image: httpdports:- containerPort: 80 # 转发到后端pod的端口号--- # 多个资源可以在一个 YAML 文件中定义,用 --- 分割
apiVersion: v1
kind: Service
metadata:name: httpd3-servicenamespace: kube-public # 指定命名空间
spec:type: NodePort # 添加NodePort类型的Serviceselector:app: httpd3ports: # 将 Service 的 8080 端口映射到 Pod 的 80 端口,使用 TCP 协议- protocol: TCPport: 8080 # Service(Cluster IP)上监听端口targetPort: 80 # 转发到后端pod的监听端口号、nodePort: 30150 # 节点上监听的端口 最终,Node 和 ClusterIP 在各自端口上接收到的请求都会通过 iptables 转发到 Pod 的 targetPort。