kubernetes StatefulSet sts
StatfulSet具备一下几个特点:
1、稳定且唯一的网络标识符
2、稳定且持久的存储
3、有序平滑的部署和扩展
4、有序平滑地删除
5、有序的滚动更新
StatfulSet控制器三个组件:headless service,StatfulSet、volumeClaimTemplate
有状态应用需要存储的数据是不同的,如redis集群中各个节点的存储不能共享同一个持久存储。每个节点都要有自己专用的存储卷。volumeClaimTemplate 会为每一个Pod创建pvc并各自绑定pv。
StatfulSet必选字段:
replicas <integer>
selector <Object> -required-
serviceName<string> -required-
template <Object> -required-
volumeClaimTemplates<[]Object>
headless service 文件:
apiVersion: v1 kind: Service metadata: labels: app: myapp name: myapp spec: clusterIP: None ports: - name: redis port: 6379 selector: app: myapp-redis type: ClusterIP
StatfulSet 文件:
apiVersion: apps/v1 kind: StatefulSet metadata: name: redis spec: serviceName: myapp-redis replicas: 2 selector: matchLabels: app: myapp-redis template: metadata: labels: app: myapp-redis spec: containers: - name: redis image: redis:4.0 ports: - name: http containerPort: 6379 volumeMounts: - name: redis-data mountPath: /data volumeClaimTemplates: # pvc模板,自动创建pvc - metadata: name: redis-data spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi
使用到的PV:
可以简单的使用hostPath方式来创建PV,如果想用StorageClass 来动态创建PV则要在statefulset 中定义 volumeClaimTemplates.spec.storageClassName 字段即可,下面的PV就不用创建了。
volumeClaimTemplates: - metadata: name: redis-data spec: accessModes: - ReadWriteMany storageClassName: "gluster-dynamic" resources: requests: storage: 1Gi
hostPath方式:
apiVersion: v1 kind: PersistentVolume metadata: name: pv001 spec: persistentVolumeReclaimPolicy: Recycle accessModes: - ReadWriteMany capacity: storage: 1Gi hostPath: path: /data/data1 type: DirectoryOrCreate --- apiVersion: v1 kind: PersistentVolume metadata: name: pv002 spec: persistentVolumeReclaimPolicy: Recycle accessModes: - ReadWriteMany capacity: storage: 1Gi hostPath: path: /data/data2 type: DirectoryOrCreate
创建和删除的特点:
删除和创建statefulset都是按照顺序来的,创建是正序创建,删除是倒序删除。删除后重新创建还会绑定到原来的pv上。使用describe查看Pod中的ClaimName 删除后再创建始终会绑定到同一个ClaimName;Pod的名称且可以被解析。
在pvc的名称中包含Pod的名称:
kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE redis-data-redis-0 Bound pv001 1Gi RWX 52m redis-data-redis-1 Bound pv002 1Gi RWX 52m
对statefulset扩容:
kubectl scale --replicas=3 statefulset redis
更新镜像:
StatefulSet中可以定义partition的值来自定义更新sts.spec.updateStrategy.rollingUpdate.partition,在statefulset中Pod的后缀是有序数字,partition值是用来定义更新范围的,规则为 partition>= N 的将被更新。如 partition=3 那么 redis-3、redis-4 ... 之后的所有Pod的都会被更新。
并行更新:
如果想并行更新Pod可以设置 spec.podManagermentPolicy 来实现。
spec: podManagermentPolicy: OrderedReady # Parallel无顺序停启, OrderedReady 按顺序停启
注意:
更新镜像要注意应用之间的不同版本数据可能不兼容而导致更新后出现 Error 或 CrashLoopBackOff,如redis在更新版本的时候4.0和5.0之间数据是不兼容的,直接更新镜像是不行的。
更新步骤:
修改partition的值:
kubectl patch sts redis --patch='{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
或:
kubectl edit statefulsets.apps redis
更新:
kubectl set image statefulset redis redis=redis:4.0.14 --record
再次修改partition的值:将其值改为0,这样其他的Pod就会更新到刚刚set image设置的版本了。
kubectl patch sts redis --patch='{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}'
设置partition的更新过程类似于金丝雀发布的效果,先更新一个Pod到最新版本,如果不行就回滚到旧版本。
kubectl set image sts redis redis=redis:4.0.14 --record
DNS解析后端服务:
通过service name解析到的是后端所有的Pod IP,通过Pod_name.service_name 可以解析到Pod IP。
]# kubectl exec -it test-pod -- sh # 解析service / # nslookup nginx-sts-svc Server: 10.96.0.10 Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local Name: nginx-sts-svc Address 1: 10.244.2.106 nginx-sts-1.nginx-sts-svc.default.svc.cluster.local Address 2: 10.244.1.181 nginx-sts-0.nginx-sts-svc.default.svc.cluster.local # 解析Pod name / # nslookup nginx-sts-0.nginx-sts-svc Server: 10.96.0.10 Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local Name: nginx-sts-0.nginx-sts-svc Address 1: 10.244.1.181 nginx-sts-0.nginx-sts-svc.default.svc.cluster.local
删除某个Pod后StatefulSet会重建该Pod,并且Pod name不会发生变化,但是Pod IP是会变的,通过解析Pod name可以观察到。客户端直接使用 Pod_name.service_name 进行请求。
删除Pod后并不会删除存储,除非用户手动删除,且重建的Pod依然会被关联到以前的那个PVC上。
同其他控制器一样删除StatefulSet默认也是级联删除,即:删除控制器连同该控制器之下的Pod一起删除,如果不使用级联可以设置--cascade=false 参数来设置。