一、Statefulset控制器

StatefulSet是为了管理有状态服务的问题而设计的

pod名称是唯一不能更改的,或者pod中运行的服务需要做数据持久化,比如MySQL主从、redis集群等都可称为有状态的服务,而这种有状态服务的pod就需要使用

StatefulSet控制器进行管理。


Statefulset 字段详情可通过如下命令进行查看

kubectl explain sts     (Statefulset 可简写为sts)

k8s使用Statefulset控制器进行配置pod的独享数据存储及Statefulset管理pod的扩容、缩容及滚动更新_nginx

1.1 Statefulset编写yaml创建pod

使用Statefulset控制器进行yaml文件的编写,创建两个pod,并挂载存储pvc,使两个pod独享存储。


ps:下方yaml文件中使用的volumeClaimTemplates(存储卷申请模板)定义的nfs存储类,可根据如下链接中“4.2 ~ 4.2.6”标题中的步骤进行部署,然后引用即可(存储类的名称切记不要写错,要与下方yaml文件中storageClassName字段定义的要保持一致)

 点我直达 参考标题 4.2 ~ 4.2.6

[root@k8s-master ~]# vim sts.yaml

apiVersion: v1        ###创建service
kind: Service
metadata:
  name: svc-01        #定义servic的名称
  labels:             #定义service的标签
    sevice: svc-02
spec:
  ports:
  - port: 80          #这里定义端口,要与关联的pod中容器运行的服务端口一致
    name: nginx-web-01
  clusterIP: None     #表示创建的service没有IP(不定义该行,创建时会自动生成一个service的IP)
  selector:           #定义关联pod的标签
    svc: nginx
---                   ###分割:创建statefulset控制器管理pod服务
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sts
spec:
  replicas: 2         #定义管理的pod副本数
  selector:           #定义标签选择器
    matchLabels:
      svc: nginx      #匹配模板的标签,与下方模板中定义的标签要匹配
  serviceName: svc-01 #使用StatefulSet控制器时,必须要定义一个service,写上方需要关联的service的名称
  template:           #定义模板
    metadata:
      labels:         #定义模板的标签
        svc: nginx
    spec:
      containers:     #定义运行容器的信息
      - name: mynginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80  #声明容器的端口
          name: nginx-web    #定义端口的别名
        volumeMounts:        #定义存储卷挂载的路径(写挂载到容器内的路径)
        - mountPath: /usr/share/nginx/html
          name: volume       #定义卷申请模板的名称(要匹配到它才能使用并挂载到容器内)
  volumeClaimTemplates:      #定义存储卷申请模板(在StatefulSet下创建可不用写apiversion及kind)
  - metadata:
      name: volume                #定义卷申请模板名称
    spec:
      accessModes:                #定义访问模式
      - ReadWriteOnce             #单路读写模式
      storageClassName: nfs       #定义存储类,这里写创建的存储类storageclass的名称(kubectl get storageclass 查看)
      resources:                  #定义存储大小
        requests:
          storage: 1G
          
          
#创建
[root@k8s-master ~]# kubectl apply -f sts.yaml 
service/svc-01 created
statefulset.apps/sts created

#查看创建pod信息,pod名称是以yaml文件中定义的statefulset控制器指定的名称命名,并有序命名(sts-0\sts-1)
[root@k8s-master ~]# kubectl get pods -owide
NAME                                 READY   STATUS    RESTARTS      AGE   IP              NODE          NOMINATED NODE   READINESS GATES
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   1 (20h ago)   21h   10.244.126.1    k8s-worker2   <none>           <none>
sts-0                                1/1     Running   0             15s   10.244.194.66   k8s-worker1   <none>           <none>
sts-1                                1/1     Running   0             4s    10.244.126.4    k8s-worker2   <none>           <none>

#查看pvc 创建了两个,以yaml文件中的指定的存储卷名称+pod名称命名
[root@k8s-master ~]# kubectl get pvc
NAME           STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc       Bound    pvc-e6f251e2-c8d5-4f7e-ba20-951ba0eaa1ff   1G         RWX            nfs            21h
volume-sts-0   Bound    pvc-0a03784a-a584-40f8-b345-3390f52d9c09   1G         RWO            nfs            116s
volume-sts-1   Bound    pvc-31da41f7-5601-4d22-89e5-e79de4b6e04a   1G         RWO            nfs            105s

#pv是自动生成的
[root@k8s-master ~]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS   REASON   AGE
pvc-0a03784a-a584-40f8-b345-3390f52d9c09   1G         RWO            Delete           Bound    default/volume-sts-0   nfs                     112s
pvc-31da41f7-5601-4d22-89e5-e79de4b6e04a   1G         RWO            Delete           Bound    default/volume-sts-1   nfs                     107s
pvc-e6f251e2-c8d5-4f7e-ba20-951ba0eaa1ff   1G         RWX            Delete           Bound    default/test-pvc       nfs                     21h

#查看nfs共享目录(pv)是否生成(已生成)
[root@k8s-master ~]# ls /nfs/test001/
default-volume-sts-1-pvc-31da41f7-5601-4d22-89e5-e79de4b6e04a
default-volume-sts-0-pvc-0a03784a-a584-40f8-b345-3390f52d9c09

#查看servic信息,yaml文件中指定servic的IP为none,所以IP为空
[root@k8s-master ~]# kubectl get svc | grep svc
svc-01       ClusterIP   None         <none>        80/TCP    5m35s

#查看service的Endpoints,它所关联的两个ip就是sts-0 sts-1pod所在node节点的IP
[root@k8s-master ~]# kubectl describe svc svc-01
Name:              svc-01
Namespace:         default
Labels:            sevice=svc-02
Annotations:       <none>
Selector:          svc=nginx
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                None
IPs:               None
Port:              nginx-web-01  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.126.4:80,10.244.194.66:80
Session Affinity:  None
Events:            <none>

1.2 测试pod独享数据目录

测试俩个pod独享的数据目录是否成功

#在sts-0的pv中创建一个文件并写入数据
[root@k8s-master ~]# echo test000 >> /nfs/test001/default-volume-sts-0-pvc-0a03784a-a584-40f8-b345-3390f52d9c09/test.txt

#进入sts-0 pod中查看
[root@k8s-master ~]# kubectl exec -it sts-0 -- /bin/bash
root@sts-0:/# cat /usr/share/nginx/html/test.txt             //宿主机上绑定的pv已共享进pod容器中
test000
root@sts-0:/# exit 
exit

#退出sts-0 进入sts-1 查看验证数据是否共享,无则创建一个并验证
[root@k8s-master ~]# kubectl exec -it sts-1 -- /bin/bash
root@sts-1:/# ls /usr/share/nginx/html/                     //该路径下为空(sts-0的pv未共享到sts-1)
root@sts-1:/# 
root@sts-1:/# touch /usr/share/nginx/html/test-01.txt       //创建测试文件
root@sts-1:/# exit 
exit

#退出sts-1 pod后查看宿主机上sts-1的pv路径下进行验证,(该pv与sts-1 pod中容器已完成共享)
[root@k8s-master ~]# ls /nfs/test001/default-volume-sts-1-pvc-31da41f7-5601-4d22-89e5-e79de4b6e04a/
test-01.txt


PS:与deploymen控制不同的是,使用Statefulset控制器进行管理创建的pod,
    可以使用volumeClaimTemplates字段做到每个pod中的容器(服务)拥有独立存储,且pod名称是有序且唯一的,
    也就是说sts-0 pod删除在由statefulset控制器重新自动创建后,pod名称还是sts-0
    另外就是创建statefulset资源的时候,必须要先创建一个service
    由statefulset控制器创建的pod是含有域名的(域名命名格式为:pod名称.servic名称.所在命名空间名称.svc.cluster.local)
    如:sts-0.svc-01.default.svc.cluster.local

关于deployment控制器的使用可以参考如下链接:

点我直达,标题二 Deployment

1.3 Statefulset 扩容、缩容、更新

使用Statefulset控制器管理pod进行pod的扩容、缩容及更新

1.3.1 扩容

修改sts.yaml文件,将replicas字段指定的副本数修改为要扩容的目标数

#修改为3sts.yaml文件,将replicas字段指定的副本数修改为要扩容的目标数(我这里修改为3)
[root@k8s-master ~]# cat sts.yaml | grep replicas 
  replicas: 3         #定义管理的pod副本数


#创建(已成功创建一个pod,按照序号从小到大进行扩容创建)
[root@k8s-master ~]# kubectl get pods 
NAME                                 READY   STATUS    RESTARTS       AGE
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   3 (3m6s ago)   2d18h
sts-0                                1/1     Running   0              7m
sts-1                                1/1     Running   0              6m51s
sts-2                                1/1     Running   0              106s

1.3.2 缩容

同理 修改replicas字段指定的副本数即可

#修改为2
[root@k8s-master ~]# cat sts.yaml | grep replicas 
  replicas: 2         #定义管理的pod副本数
  

#创建(已成功删除一个pod,按照序号从大到小进行缩容删除)
[root@k8s-master ~]# kubectl get pods 
NAME                                 READY   STATUS    RESTARTS        AGE
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   3 (7m18s ago)   2d18h
sts-0                                1/1     Running   0               11m
sts-1                                1/1     Running   0               11m

1.3.3 滚动更新

实现Statefulset的滚动更新需要使用到updateStrategy字段,该字段在sts.spec下,可以通过如下命令进行查看

该字段下有两种更新类型如:rollingUpdate及type类型的Ondelete

kubectl explain sts.spec.updateStrategy.rollingUpdate

kubectl explain sts.spec.updateStrategy.type

1.3.3.1 rollingUpdate 字段更新
#修改sts.yaml文件 在spec下方增加更新字段如下,更新pod还需要更新镜像(我这里将nginx镜像更新成为了httpd)
[root@k8s-master ~]# cat sts.yaml  | grep -C 6 updateStrategy

---                   ###分割:创建statefulset控制器管理pod服务
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sts
spec:
  updateStrategy:     #定义pod更新策略
    rollingUpdate:    #定义更新字段
      partition: 1    #这里定义的数字表示更新的pod根据序号选择大于的,如sts-1、sts-2 就是更新大于等于带1数字的pod
      maxUnavailable: 0 #这里写0表示更新的时候最少要有1个pod
  replicas: 2         #定义管理的pod副本数
  selector:           #定义标签选择器
    matchLabels:

#更新镜像字段
[root@k8s-master ~]# cat sts.yaml  | grep image:
        image: httpd



#更新
[root@k8s-master ~]# kubectl get pods -w
NAME                                 READY   STATUS    RESTARTS      AGE
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   3 (20m ago)   2d18h
sts-0                                1/1     Running   0             24m
sts-1                                1/1     Running   0             24m
sts-1                                1/1     Terminating   0             30m   //更新时,这里删除了sts-1 pod
sts-1                                1/1     Terminating   0             30m
sts-1                                0/1     Terminating   0             30m
sts-1                                0/1     Terminating   0             30m
sts-1                                0/1     Terminating   0             30m
sts-1                                0/1     Pending       0             0s
sts-1                                0/1     Pending       0             0s
sts-1                                0/1     ContainerCreating   0             0s   //然后重新创建sts-1 pod
sts-1                                0/1     ContainerCreating   0             1s
sts-1                                1/1     Running             0             2s
sts-1                                1/1     Running             0             49s

#查看所更新pod信息
[root@k8s-master ~]# kubectl get pods -owide
NAME                                 READY   STATUS    RESTARTS      AGE     IP              NODE          NOMINATED NODE   READINESS GATES
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   3 (27m ago)   2d18h   10.244.126.1    k8s-worker2   <none>           <none>
sts-0                                1/1     Running   0             31m     10.244.194.66   k8s-worker1   <none>           <none>
sts-1                                1/1     Running   0             38s     10.244.126.4    k8s-worker2   <none>           <none>

#创建完成之后 验证更新的pod中容器服务已变成了httpd的主页面
[root@k8s-master ~]# curl 10.244.126.4:80
<html><body><h1>It works!</h1></body></html>
1.3.3.2 Ondelete 字段更新

使用 该字段进行更新pod,需要删除原有的pod才会自动更新创建新的pod

#修改sts.yaml文件添加type更新字段并删除rollingUpdate的更新字段,且修改镜像httpd为nginx 如下:
[root@k8s-master ~]# cat sts.yaml | grep -B 7 type
---                   ###分割:创建statefulset控制器管理pod服务
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sts
spec:
  updateStrategy:     #定义pod更新策略
    type: OnDelete

#修改镜像为nginx
[root@k8s-master ~]# cat sts.yaml | grep image:
        image: nginx


#创建更新
[root@k8s-master ~]# kubectl apply -f sts.yaml 
service/svc-01 unchanged
statefulset.apps/sts configured

#创建时动态查看pod更新信息
#使用ondelete字段进行更新时,不会直接进行更新 需要删除pod重新创建,如下:
[root@k8s-master ~]# kubectl get pods -w
NAME                                 READY   STATUS    RESTARTS      AGE
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   3 (48m ago)   2d19h
sts-0                                1/1     Running   0             52m
sts-1                                1/1     Running   0             21m

#删除pod 重新创建
[root@k8s-master ~]# kubectl delete pod sts-0
pod "sts-0" deleted
[root@k8s-master ~]# kubectl delete pod sts-1
pod "sts-1" deleted

#删除pod时同台查看pod状态信息
[root@k8s-master ~]# kubectl get pods -w
NAME                                 READY   STATUS    RESTARTS      AGE
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   3 (48m ago)   2d19h
sts-0                                1/1     Running   0             52m
sts-1                                1/1     Running   0             21m
sts-0                                1/1     Terminating   0             59m          //sts-0 删除
sts-0                                1/1     Terminating   0             59m
sts-0                                0/1     Terminating   0             59m
sts-0                                0/1     Terminating   0             59m
sts-0                                0/1     Terminating   0             59m
sts-0                                0/1     Pending       0             0s
sts-0                                0/1     Pending       0             0s
sts-0                                0/1     ContainerCreating   0             0s     //sts-0 创建
sts-0                                0/1     ContainerCreating   0             1s
sts-0                                1/1     Running             0             2s
sts-1                                1/1     Terminating         0             28m    //sts-1 删除
sts-1                                0/1     Terminating         0             28m
sts-1                                0/1     Terminating         0             28m
sts-1                                0/1     Terminating         0             28m
sts-1                                0/1     Pending             0             0s
sts-1                                0/1     Pending             0             0s
sts-1                                0/1     ContainerCreating   0             0s     //sts-1 创建
sts-1                                0/1     ContainerCreating   0             0s
sts-1                                0/1     ContainerCreating   0             1s
sts-1                                1/1     Running             0             2s
sts-0                                1/1     Running             0             27s

#查看pod所在节点IP并验证
[root@k8s-master ~]# kubectl get pods -owide
NAME                                 READY   STATUS    RESTARTS      AGE     IP              NODE          NOMINATED NODE   READINESS GATES
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   3 (57m ago)   2d19h   10.244.126.1    k8s-worker2   <none>           <none>
sts-0                                1/1     Running   0             2m3s    10.244.194.67   k8s-worker1   <none>           <none>
sts-1                                1/1     Running   0             117s    10.244.126.5    k8s-worker2   <none>           <none>

#验证(宿主机共享了nfs的路径给到pod中nginx容器的首页路径下,写入内容访问测试)
[root@k8s-master ~]# echo How are you >> /nfs/test001/default-volume-sts-1-pvc-8f712ce4-712c-4a4e-8689-1af681269294/index.html
[root@k8s-master ~]# curl 10.244.126.5:80
How are you