从1.9 GA版本开始,StatefulSet成为kubernetes的稳定特性。StatefulSet是一种副本控制器,管理pod的部署、缩放等。与ReplicaSet、Deployment不同的是,它对集合中的pod提供顺序、唯一性保证。StatefulSet为集合中的每个pod分配唯一、持久的pod名称、DNS解析、持久化存储,并且负责将这些标识粘在pod上,无论pod调度到任何节点上。
当应用的需求,与下述中的一条或者多条相符时,使用StatefulSet就会有价值:
StatefulSet中的pod名称由StatefulSet配置中的name加上表示序号的整数,整数从0开始取值,最大值为副本数量减1.
StatefulSet通过与其相关的无头服务为每个pod提供DNS解析条目。假如无头服务的DNS条目为:
"$(service name).$(namespace).svc.cluster.local",
那么pod的解析条目就是"$(pod name).$(service name).$(namespace).svc.cluster.local",每个pod name也是唯一的。
通过 PersistentVolume 提供持久化存储。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
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: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
上述文件包含两个对象,前边名为nginx的service,其clusterIP为None,所以它是无头服务。下边为名web的StatefulSet,其.spec.serviceName的值为nginx,指明通过上边的nginx无头服务提供DNS解析功能功。.spec.volumeClaimTemplates表示持久化存储。将以上内容保存在web.yaml文件中。
执行创建命令:
kubectl create -f web.yaml
service "nginx" created
statefulset "web" created
确认结果:
kubectl get service nginx
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx None 80/TCP 12s
kubectl get statefulset web
NAME DESIRED CURRENT AGE
web 2 1 20s
如果从另一个终端监控StatefulSet创建过程,会看到如下内容:
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 18s
两个pod,web-0与web-1按序创建,web-0必须先创建并且处于就绪状态后才可以创建web-1。
创建完成后,执行如下命令确认pod名称:
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 1m
web-1 1/1 Running 0 1m
运行如下命令检查pod的名称在集群内是否可以解析:
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.6
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.6
测试pod名称、DNS解析条目的粘性。先将pod删除,然后StatefulSet自动恢复缺失副本,再对比新pod与已删除pod的标识是否一致。
kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted
在另一个终端中监控StatefulSet自动恢复过程:
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 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 34s
运行如下命令:
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1
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.8
可以看到新pod的名称、主机名称、DNS解析条目都没有变,这些标识被粘在新pod上。但是pod的IP地址变了,所以当在集群中访问pod时,不要直接通过不稳定的IP。
运行如下命令查看持久化存储:
kubectl get pvc -l app=nginx
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 48s
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 48s
首先需要配置好集群内的持久化存储功能,以上几个volume在创建 StatefulSet时自动创建、命名、绑定到pod。默认情况下nginx的"/usr/share/nginx/html/index.html"位于以上的持久存储中。运行如下代码修改index.html文件:
for i in 0 1; do kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1
再一次删除pod,确认持久存储是否生效,在旧pod中写入index.html的内容是否被保留到新pod中。删除、监控过程不表,直接确认结果:
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1
结果证明文件内容没有丢失。
StatefulSet的扩容、缩容、滚动升级、删除操作与Deployment、ReplicaSet相似,不同之处是StatefulSet保证pod被按顺序操作。
参考:https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/