StatefulSet和Deployment控制器的区别
- statefulSet下的Pod有DNS地址,通过解析Pod的DNS可以返回Pod的IP
- deployment下的Pod没有DNS
通过StatefulSet和headless service部署的服务效果

为什么要用headless service+statefulSet部署有状态应用?
使用headless service+statefulSet可以实现
- StatefulSet会为关联的Pod保持一个不变的Pod Name,其hostname格式为
$(StatefulSet name)-$(序号【从0开始】) - StatefulSet关联到的每一个Pod分配一个dnsName
$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local - headless service会为关联的statefulSet分配一个域,通过dns解析该域能获取到每个pod的ip+port
<service name>.$<namespace name>.svc.cluster.local
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| --- apiVersion: v1 kind: PersistentVolume metadata: name: pv001 spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: rs-storage hostPath: path: /tmp/data --- apiVersion: v1 kind: Service metadata: name: nginx spec: publishNotReadyAddresses: true ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: nginx replicas: 2 updateStrategy: rollingUpdate: partition: 0 maxUnavailable: 1 type: RollingUpdate selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: cnych/nginx-slim:0.8 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: storageClassName: rs-storage accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
|
查看结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| [root@k3s-master2 ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE www-web-0 Bound pvc-30abfb58-55b2-4632-afc0-c2b5c2f97558 1Gi RWO local-path 114s www-web-1 Bound pvc-0789bbd0-d61f-4c4a-897b-c9f9ce1f8a5f 1Gi RWO local-path 92s
# ------------------------查看存储卷------------------------ [root@k3s-master2 ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 1Gi RWO Retain Available 2m37s pvc-30abfb58-55b2-4632-afc0-c2b5c2f97558 1Gi RWO Delete Bound default/www-web-0 local-path 2m47s pvc-0789bbd0-d61f-4c4a-897b-c9f9ce1f8a5f 1Gi RWO Delete Bound default/www-web-1 local-path 2m3s
# ------------------------查看pod------------------------ [root@k3s-master2 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 3m1s web-1 1/1 Running 0 2m39s
# ------------------------查看statefulsets------------------------ [root@k3s-master2 ~]# kubectl get statefulsets.apps NAME READY AGE web 2/2 3m32s
# ------------------------查看hostname------------------------ [root@k8s-master ~]# kubectl exec web-0 -- hostname web-0 [root@k8s-master ~]# kubectl exec web-1 -- hostname web-1
# ------------------------查看pv和pvc------------------------ [root@VM-33-122-centos ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE www-web-0 Bound pvc-4a24ab1c-9cd2-4460-b8d2-ff773d562f48 1Gi RWO local-path 4m10s www-web-1 Bound pvc-becd76fa-4199-441b-bdf6-9a8c63133e9d 1Gi RWO local-path 4m3s [root@VM-33-122-centos ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-4a24ab1c-9cd2-4460-b8d2-ff773d562f48 1Gi RWO Delete Bound default/www-web-0 local-path 7m31s pvc-becd76fa-4199-441b-bdf6-9a8c63133e9d 1Gi RWO Delete Bound default/www-web-1 local-path 7m26s
# ------------------------查看解析service的结果------------------------ / # nslookup nginx Server: 10.96.0.10 Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: nginx Address 1: 10.244.1.175 web-1.nginx.default.svc.cluster.local Address 2: 10.244.4.83 web-0.nginx.default.svc.cluster.local / # ping nginx PING nginx (10.244.1.175): 56 data bytes 64 bytes from 10.244.1.175: seq=0 ttl=62 time=1.076 ms 64 bytes from 10.244.1.175: seq=1 ttl=62 time=1.029 ms 64 bytes from 10.244.1.175: seq=2 ttl=62 time=1.075 ms
# 我们直接解析 Headless Service 的名称,可以看到得到的是两个 Pod 的解析记录,但实际上如果我们通过nginx这个 DNS 去访问我们的服务的话,并不会随机或者轮询背后的两个 Pod,而是访问到一个固定的 Pod,所以不能代替普通的 Service
|
特点总结
每个pod的hostname是固定的:<statefulset名称>-<序号>
每个pod有一个独立的DNS:<statefulset名称-序号>.<headless-service-name>.<namespace>.svc.cluster.local
当以此格式访问时不会提供负载效果:<headless-service-name>.<namespace>.svc.cluster.local
之前的service会自动的帮你填充cluster ip,这里将字段设置为none,不会分配,和deployment不同,deployment都是提供相同的统一的入口。有状态的都是提供独立的访问。
对于一个拥有 N 个副本的 StatefulSet 来说,Pod 在部署时按照 {0 …… N-1} 的序号顺序创建的,而删除的时候按照逆序逐个删除
主机名是固定的,即使pod被删除掉了,重新启动也是这个名称上面体现了稳定的主机名
当 Pod 所在的节点发生故障导致 Pod 飘移到其他节点上,或者 Pod 因故障被删除重建,Pod 的 IP 都会发生变化,但是 Pod 的域名不会有任何变化,这也就意味着服务间可以通过不变的 Pod 域名来保障通信稳定,而不必依赖 Pod IP。
spec.serviceName这个字段,保证了 StatefulSet 关联的 Pod 可以有稳定的网络身份标识,即 Pod 的序号、主机名、DNS 记录名称等。
对有状态的服务来说,每个副本可能都会用到持久化存储,且各自使用的数据是不一样的。每个独立的Pod都有独立的pv(利用volumeClaimTemplates)
删除pod的时候,pv pvc不会被删除,并且删除重建之后还是可以读取之前的数据。当pod被重建之后,k8s还是根据pod编号找对应的pvc进行挂载