通过前面教程的学习,我们已经可以将容器化的应用程序在 Kubernetes 中运行起来,并且发布到 Kubernetes 内/外的网络上。
通常,Docker 使用一种 host-private
的联网方式,在此情况下,只有两个容器都在同一个节点(主机)上时,一个容器才可以通过网络连接另一个容器。为了使 Docker 容器可以跨节点通信,必须在宿主节点(主机)的 IP 地址上分配端口,并将该端口接收到的网络请求转发(或代理)到容器中。这意味着,用户必须非常小心地为容器分配宿主节点(主机)的端口号,或者端口号可以自动分配。
在一个集群中,多个开发者之间协调分配端口号是非常困难的。Kubernetes 认为集群中的两个 Pod 应该能够互相通信,无论他们各自在哪个节点上。每一个 Pod 都被分配自己的 “cluster-private-IP”,因此,您无需在 Pod 间建立连接,或者将容器的端口映射到宿主机的端口。因此:
创建文件 run-my-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
kubectl apply -f ./run-my-nginx.yaml
kubectl get pods -l run=my-nginx -o wide
输出结果:
NAME READY STATUS RESTARTS AGE IP NODE
my-nginx-3800858182-jr4a2 1/1 Running 0 13s 10.244.3.4 kubernetes-minion-905m
my-nginx-3800858182-kna2y 1/1 Running 0 13s 10.244.2.5 kubernetes-minion-ljyd
kubectl get pods -l run=my-nginx -o yaml | grep podIP
, 检查 Pod 的 IP 地址,输出结果如下:cni.projectcalico.org/podIP: 10.244.84.185/32
cni.projectcalico.org/podIPs: 10.244.84.185/32
podIP: 10.244.84.185
podIPs:
cni.projectcalico.org/podIP: 10.244.14.61/32
cni.projectcalico.org/podIPs: 10.244.14.61/32
podIP: 10.244.14.61
podIPs:
在集群中的任意节点上,您可以执行curl 10.244.84.185或
curl 10.244.14.61 获得 nginx 的响应。
这意味着,您可以
同 Docker 一样,Kubernets 中,仍然可以将 Pod 的端口映射到宿主节点的网络地址上(使用 nodePort),但是使用 Kubernetes 的网络模型时,这类需求已经大大减少了。
上面的步骤中,我们已经创建了 nginx Pod,运行在集群的 IP 地址空间。您可以直接通过 Pod 的地址访问其端口,但是如果某一个 Pod 终止了该怎么办?Pod 因为故障或其他原因终止后,Deployment Controller 将创建一个新的 Pod 以替代该 Pod,但是 IP 地址将发生变化。Kubernetes Service 解决了这样的问题。
Kubernetes Service:
执行命令 kubectl expose deployment/my-nginx
可以为上面的两个 nginx Pod 创建 Service,输出结果如下所示:
service/my-nginx exposed
该命令等价于 kubectl apply -f nginx-svc.yaml
,其中 nginx-svc.yaml 文件的内容如下所示:
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
run: my-nginx
该 yaml 文件将创建一个 Service:
run: my-nginx
标签的 Pod 作为后端 Podspec.ports[*].port
)spec.ports[*].targetPort
)端口上,支持负载均衡执行命令 kubectl get svc my-nginx
,输出结果如下
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx ClusterIP 10.100.223.157 80/TCP 75s
Service 的后端 Pod 实际上通过 Endpoints
来暴露。Kubernetes 会持续检查 Service 的 label selector spec.selector
,并将符合条件的 Pod 更新到与 Service 同名(my-nginx)的 Endpoints 对象。如果 Pod 终止了,该 Pod 将被自动从 Endpoints 中移除,新建的 Pod 将自动被添加到该 Endpoint。
执行命令 kubectl describe svc my-nginx
,输出结果如下,请注意 Endpoints 中的 IP 地址与上面获得的 Pod 地址相同:
Name: my-nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: run=my-nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.100.223.157
IPs: 10.100.223.157
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.14.61:80,10.244.84.185:80
Session Affinity: None
Events: <none>
执行命令 kubectl get ep my-nginx
,输出结果
NAME ENDPOINTS AGE
my-nginx 10.244.14.61:80,10.244.84.185:80 8m37s
此时,您可以在集群的任意节点上执行curl 10.100.223.157:80
,通过 Service 的 ClusterIP:Port 访问 nginx。
Kubernetes 支持两种方式发现服务:
针对每一个有效的 Service,kubelet 在创建 Pod 时,向 Pod 添加一组环境变量。这种做法引发了一个 Pod 和 Service 的顺序问题。例如,
kubectl exec my-nginx-df7bbf6f5-87hqg -- printenv | grep SERVICE
(您的 Pod 名字可能不一样),输出结果如下KUARD_SERVICE_PORT=80
KUBERNETES_SERVICE_PORT_HTTPS=443
KUARD_SERVICE_HOST=10.110.143.73
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
Kubernetes 提供了一个 DNS cluster addon,可自动为 Service 分配 DNS name。
查看该 addon 在您的集群上是否可用
kubectl get services kube-dns --namespace=kube-system
输出结果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 140d
可以从集群中任何 Pod 中按 Service 的名称访问该 Service。
kubectl run curl --image=radial/busyboxplus:curl -i --tty
获得 busyboxplus 容器的命令行终端,该命令输出结果If you don't see a command prompt, try pressing enter.
[ root@curl:/ ]$
nslookup my-nginx
,输出结果如下所示:[ root@curl:/ ]$ nslookup my-nginx
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: my-nginx
Address 1: 10.100.223.157 my-nginx.default.svc.cluster.local
curl my-nginx:80
,可获得 Nginx 的响应。[ root@curl:/ ]$ curl my-nginx:80
Welcome to nginx!
Welcome to nginx!
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
For online documentation and support please refer to
nginx.org.
Commercial support is available at
nginx.com.
Thank you for using nginx.
exit
可推出该容器的命令行kubectl delete deployment curl
可删除刚才创建的 curl
测试容器