Kubernetes之StatefulSet

StatefulSet介绍

从1.9 GA版本开始,StatefulSet成为kubernetes的稳定特性。StatefulSet是一种副本控制器,管理pod的部署、缩放等。与ReplicaSet、Deployment不同的是,它对集合中的pod提供顺序、唯一性保证。StatefulSet为集合中的每个pod分配唯一、持久的pod名称、DNS解析、持久化存储,并且负责将这些标识粘在pod上,无论pod调度到任何节点上。

什么时候需要使用StatefulSet

当应用的需求,与下述中的一条或者多条相符时,使用StatefulSet就会有价值:

  • 唯一、稳定的网络标识(pod原本没有网络标识,service有)。
  • 稳定、持久化存储。
  • 多个副本有序、优雅的部署与缩放。
  • 多个副本有序、优雅的部署与缩放。
  • 多个副本有序、优雅的自动滚动升级。

StatefulSe限制

  • StatefulSet特性,1.5之前的版本不可用,1.9之前的版本不稳定。
  • 必需为pod提供持久化存储。
  • 删除或者缩容StatefulSet时,出于数据安全的目的,不会自动删除与pod相关的持久化存储,需要手动处理。
  • 当前StatefulSet需要通过无头服务为其所管理的pod提供网络标识,或者说DNS条目,用户需手动创建无头服务。

唯一、稳定pod名称

StatefulSet中的pod名称由StatefulSet配置中的name加上表示序号的整数,整数从0开始取值,最大值为副本数量减1.

唯一、稳定网络ID

StatefulSet通过与其相关的无头服务为每个pod提供DNS解析条目。假如无头服务的DNS条目为:
"$(service name).$(namespace).svc.cluster.local",
那么pod的解析条目就是"$(pod name).$(service name).$(namespace).svc.cluster.local",每个pod name也是唯一的。

稳定持久存储

通过 PersistentVolume 提供持久化存储。

创建StatefulSet

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/

你可能感兴趣的:(kubernetes)