一、StatefulSet
1、什么是StatefulSet?
2、StatefulSet设计
1、拓扑状态
2、存储状态
3、StatefulSet 的核心功能
二、Headless Service
1、什么是Headless Service?
2、Headless Service如何被访问?
1、以 Service 的 VIP方式
2、以DNS记录暴露代理方式
第一种处理方法,是 Normal Service。这种情况下,你访问“my-svc.my-namespace.svc.cluster.local”解析到的,正是 my-svc 这个 Service 的 VIP,后面的流程就跟 VIP 方式一致了。
第二种处理方法,正是 Headless Service。这种情况下,你访问“my-svc.my-namespace.svc.cluster.local”解析到的,直接就是 my-svc 代理的某一个 Pod 的 IP 地址。
3、两种访问方式的区别
4、那么,这样的设计又有什么作用呢?
想要回答这个问题,我们需要从 Headless Service 的定义方式看起。
下面是一个标准的 Headless Service 对应的 YAML 文件:
apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx
当你按照这样的方式创建了一个 Headless Service 之后,它所代理的所有 Pod 的 IP 地址,都会被绑定一个这样格式的 DNS 记录,如下所示:
<pod-name>.<svc-name>.<namespace>.svc.cluster.local
这个 DNS 记录,正是 Kubernetes 项目为 Pod 分配的唯一的“可解析身份”(Resolvable Identity)。
有了这个“可解析身份”,只要你知道了一个 Pod 的名字,以及它对应的 Service 的名字,你就可以非常确定地通过这条 DNS 记录访问到 Pod 的 IP 地址。
三、StatefulSet 又是如何使用这个 DNS 记录来维持 Pod 的拓扑状态的呢?
1、可解析身份
为了回答这个问题,现在我们就来编写一个 StatefulSet 的 YAML 文件,如下所示:
apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: "nginx" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.9.1 ports: - containerPort: 80 name: web
注意事项
$ kubectl create -f svc.yaml $ kubectl get service nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP None <none> 80/TCP 10s $ kubectl create -f statefulset.yaml $ kubectl get statefulset web NAME DESIRED CURRENT AGE web 2 1 19s
备注:如果手不够快的话,Pod 很快就创建完了。不过,你依然可以通过这个 StatefulSet 的 Events 看到这些信息。
$ kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s web-0 0/1 ContainerCreating 0 0s web-0 1/1 Running 0 19s web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 20s
四、编号规则
1、编码规则是
通过上面这个 Pod 的创建过程,我们不难看到,StatefulSet 给它所管理的所有 Pod 的名字,进行了编号,编号规则是:-。
比如
我们使用 kubectl exec 命令进入到容器中查看它们的 hostname:
$ kubectl exec web-0 -- sh -c 'hostname' web-0 $ kubectl exec web-1 -- sh -c 'hostname' web-1
2、以 DNS 的方式,访问一下这个 Headless Service:
可以看到,这两个 Pod 的 hostname 与 Pod 名字是一致的,都被分配了对应的编号。接下来,我们再试着以 DNS 的方式,访问一下这个 Headless Service:
$ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
$ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh $ nslookup web-0.nginx Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.nginx Address 1: 10.244.1.7 $ nslookup web-1.nginx Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.nginx Address 1: 10.244.2.7
nslookup 输出结果
这时候,如果你在另外一个 Terminal 里把这两个“有状态应用”的 Pod 删掉
$ kubectl delete pod -l app=nginx pod "web-0" deleted pod "web-1" deleted
3、会发现一个有趣的现象:
然后,再在当前 Terminal 里 Watch 一下这两个 Pod 的状态变化,就会发现一个有趣的现象:
$ kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 0/1 ContainerCreating 0 0s NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 2s web-1 0/1 Pending 0 0s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 32s
可以看到
4、StatefulSet 如何保证 Pod 网络标识的稳定性
所以,如果我们再用 nslookup 命令,查看一下这个新 Pod 对应的 Headless Service 的话:
$ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh $ nslookup web-0.nginx Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.nginx Address 1: 10.244.1.8 $ nslookup web-1.nginx Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.nginx Address 1: 10.244.2.8
1、按照 Pod 的“名字 + 编号”的方式固定了下来
2、固定并且唯一的访问入口
3、“有状态应用”实例的访问
五、小结
1、用一句话总结
2、Headless Service
实际上,在部署“有状态应用”的时候,应用的每个实例拥有唯一并且稳定的“网络标识”,是一个非常重要的假设。