k8s之StatefulSet

StatefulSet(狀態集)

1,什麼是StatefulSet ?
StatefulSet又叫PetSet(以前的名稱),它和RS,RC,Deployment等同樣,都是pod控制器。
StatefulSet是爲了解決有狀態服務的問題(對應於deoloyment和RS,RC,ReplicaSet都是爲無狀態服務而設計的)。html

什麼是無狀態服務?
在生產環境中,pod的名稱是隨機的,擴縮容的是時候沒有規律,每個pod均可以被新生成的pod代替。nginx

2,StatefulSet的應用場景包括:web

  • 穩定的持久化存儲:即pod從新調度後仍是可以訪問到相同的持久化數據,基於PVC來實現。
  • 穩定的網絡標誌:即pod從新調度後其pod名稱和host名稱不變,基於Headless Service(即沒有cluster ip的service)來實現。
  • 有序部署,有序擴展:即pod是由順序的,在部署或者擴展的時候要依據定義的順序依次進行(即從0到N-1, 在下一個Pod運行以前全部以前的Pod必須都是Running和Ready狀態),基於init containers來實現。
  • 有序收縮,有序刪除:(即N-1到0)

從上面的引用場景能夠發現,statefulset由如下幾個部分組成:
1)headless Service:無頭服務。用來定義pod的網絡標識的(域名解析)。
2)statefulSet:定義具體的應用
3)volumeClaimTemplate:該模板自動爲每個pod建立pvc。vim

對比無狀態服務,總結StatefulSet特色:pod的名稱不變,每一個副本啓停有順序,持久化存儲,每一個pod中的數據不一樣,根據定義的模板自動建立pvc。api

3,接下來經過例子來實踐statefulset資源的使用
部署nginx服務,經過storage class和statefulset實現有狀態服務的數據持久化及其餘操做。安全

操做流程以下:
1)經過nfs服務部署storage class(建立pv)
2)建立statefulset資源對象(建立pvc)
3)測試數據持久化
4)replicas擴容與縮容
5)分區更新

1)經過nfs部署storage class
如下直接進行部署,具體信息及參數解釋請參考上章博文 k8s之StatefulSet
#開啓nfs:服務器

[root@master yaml]# yum -y install nfs-utils
[root@master yaml]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash)
[root@master yaml]# mkdir /nfsdata
[root@master yaml]# systemctl start rpcbind
[root@master yaml]# systemctl start nfs-server
[root@master yaml]# systemctl enable nfs-server
[root@master yaml]# showmount -e
Export list for master:
/nfsdata *

#建立rbac權限:網絡

[root@master yaml]# vim rbac-rolebind.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-provisioner-runner
  namespace: default
rules:
   -  apiGroups: [""]
      resources: ["persistentvolumes"]
      verbs: ["get", "list", "watch", "create", "delete"]
   -  apiGroups: [""]
      resources: ["persistentvolumeclaims"]
      verbs: ["get", "list", "watch", "update"]
   -  apiGroups: ["storage.k8s.io"]
      resources: ["storageclasses"]
      verbs: ["get", "list", "watch"]
   -  apiGroups: [""]
      resources: ["events"]
      verbs: ["watch", "create", "update", "patch"]
   -  apiGroups: [""]
      resources: ["services", "endpoints"]
      verbs: ["get","create","list", "watch","update"]
   -  apiGroups: ["extensions"]
      resources: ["podsecuritypolicies"]
      resourceNames: ["nfs-provisioner"]
      verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

運行yaml文件。
#建立nfs-Deployment:app

[root@master yaml]# vim nfs-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
          volumeMounts:
            - name: nfs-client-root
              mountPath:  /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: nfs-deploy    #供給方的名稱(自定義)
            - name: NFS_SERVER
              value: 172.16.1.30     #nfs服務器的ip地址
            - name: NFS_PATH
              value: /nfsdata      #nfs共享的目錄
      volumes:  
        - name: nfs-client-root
          nfs:
            server: 172.16.1.30
            path: /nfsdata

#建立storage class:less

[root@master yaml]# vim sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: statefu-nfs
  namespace: default
provisioner: nfs-deploy  
reclaimPolicy: Retain
//運行yaml文件後,查看sc的信息:
[root@master yaml]# kubectl  get sc
NAME          PROVISIONER   AGE
statefu-nfs   nfs-deploy    48s

2)建立statefulset資源:

[root@master yaml]# vim statefulset.yaml
apiVersion: v1
kind: Service   
metadata:
  name: headless-svc   #定義無頭服務,須要定義標籤
  labels:
    app: headless-svc
spec:
  ports:
  - name: testweb
    port: 80
  clusterIP: None    #須要將cluster ip定義爲none
  selector:
    app: nginx  #此處指定的標籤須要在後邊進行定義
---
apiVersion: apps/v1
kind: StatefulSet   
metadata:
  name: sfs-web  
spec:
  serviceName: headless-svc  #此處選擇的服務名爲上邊定義的無頭服務名
  replicas: 3
  selector:
    matchLabels:
      app: nginx    #選擇標籤 
  template:
    metadata:
      labels:
        app: nginx   #定義標籤
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:   #定義數據持久化
        - name: test-nginx
          mountPath: /usr/share/nginx/html  #掛載到容器內的路徑
  volumeClaimTemplates:  #經過該字段(模板)爲每一個pod建立pvc
  - metadata:
      name: test-nginx
      annotations:  
        volume.beta.kubernetes.io/storage-class: statefu-nfs #此處選擇以前建立的storage class,名稱要一致
    spec:
      accessModes:
        - ReadWriteOnce   #採用ReadWriteOnce的訪問模式
      resources:
        requests:
          storage: 100Mi   #請求100M的空間
[root@master yaml]# kubectl apply -f statefulset.yaml 
service/headless-svc unchanged
statefulset.apps/sfs-web created

//運行成功後,查看建立的headless service和statefulset的狀態:
k8s之StatefulSet
k8s之StatefulSet
//查看svc的詳細信息:
k8s之StatefulSet
//查看建立的pod:(確保正常運行)
k8s之StatefulSet
能夠看到每一個pod都是有序的,它們的名稱(域名)會以0,1,2....依次排序。

#根據上面咱們說到的,經過sc會建立pv,以及經過sts中的模板會自動建立pvc,咱們進行查看集羣中的pv和pvc:
k8s之StatefulSet

咱們能夠看到pv和pvc建立成功,狀態已是Bound了,訪問模式是RWO(在sc中定義的模式),回收策略Delete ,都是經過sc和sts動態建立的,而並非咱們手動建立。

3)測試數據持久化
#查看掛載到nfs服務器上是否會生成每一個pvc的共享目錄:
k8s之StatefulSet

#進入某個pod目錄下建立測試網頁文件:

[root@master yaml]# cd /nfsdata/default-test-nginx-sfs-web-0-pvc-4ef5e77e-1198-4ccc-81a7-db48d8a75023/
[root@master default-test-nginx-sfs-web-0-pvc-4ef5e77e-1198-4ccc-81a7-db48d8a75023]# echo "<h1>hello world</h1>" > index.html
[root@master default-test-nginx-sfs-web-0-pvc-4ef5e77e-1198-4ccc-81a7-db48d8a75023]# ll
total 4
-rw-r--r-- 1 root root 21 Jan 12 17:13 index.html

#咱們進入到pod中,查看文件是否掛載成功:
k8s之StatefulSet

#接下來咱們將該pod刪除掉:
k8s之StatefulSet
驗證從新生成的pod是否被替換,數據是否丟失?
k8s之StatefulSet

經過上面的測試結果,咱們能夠得知有狀態的服務不一樣於無狀態服務,從新生成的pod名稱不會發生改變,即使刪除後也不會被新生成的pod覆蓋,且原有pod中的數據也一併會存在。

4)replicas的擴容與縮容:
(1)擴容操做:
[root@master yaml]# vim statefulset.yaml
k8s之StatefulSet
//從新運行yaml文件,查看新生成的pod:
k8s之StatefulSet
(2)縮容操做:(以倒序的方式依次縮減)
k8s之StatefulSet
//從新運行服務,查看pod狀態:
k8s之StatefulSet

經過上面的擴縮容操做,咱們能夠得知statefulset資源在生產環境中可以實現有序部署,即有序擴展,有序收縮,且pod的啓停都是有必定順序的。

5)分區更新操做:
分區更新的主要目的是爲pod進行一個分區,爲了使咱們對某個應用全部pod中的某一部分或者有選擇性的pod進行更新操做。

#在更新以前,咱們先來查看更新的參數:

[root@master yaml]#  kubectl  explain  sts.spec.updateStrategy.rollingUpdate 
KIND:     StatefulSet
VERSION:  apps/v1

RESOURCE: rollingUpdate <Object>

DESCRIPTION:
     RollingUpdate is used to communicate parameters when Type is
     RollingUpdateStatefulSetStrategyType.

     RollingUpdateStatefulSetStrategy is used to communicate parameter for
     RollingUpdateStatefulSetStrategyType.

FIELDS:
   partition    <integer>
     Partition indicates the ordinal at which the StatefulSet should be
     partitioned. Default value is 0.

#根據以上參數,咱們對pod進行分區,而且對指定分區的pod進行版本升級:
k8s之StatefulSet

咱們將replicas的數量設置爲8個,且定義分區更新,表示從第四個pod(分區)開始(包括第四個分區)進行更新,以前的pod是不會進行更新操做的。
注意:若是不指定分區,則默認分區從0開始。

#版本升級就不進行測試了,只需將鏡像更改成新的nginx版本,從新運行服務後,能夠看到從第四個pod開始(包括第四個)以後的pod鏡像版本將會進行升級,而以前分區的pod,版本不會發生改變。

4,StatefulSet限制

1)該資源對象還在beta(測試)狀態,須要kubernetes v1.5版本以上才支持。
2)全部pod的volume必須使用pv或者是管理員事先建立好的。
3)爲了保證數據安全,刪除statefulset時不會刪除volume。
4)statefulset須要一個Headless Service服務來定義DNS domin,須要在statefulset以前建立好。
5)目前statefulset功能還還沒有完善,好比上面的更新操做還須要手動解決。

以上就是statefulset資源的理解與實踐,若是應用程序不須要任何穩定的標識符,有序部署,刪除和scale,則使用Deployment或RS等無狀態控制器來部署。反之在生產中使用statefulset控制器爲保證pod與volume的關係不會斷開,即便pod掛了後還能使用以前掛載的磁盤

相關文章
相關標籤/搜索