九. k8s--statefulset控制器

爲何要用statefulset控制器

RC、Deployment、DaemonSet都是面向無狀態的服務,它們所管理的Pod的IP、名字,啓停順序等都是隨機的,而StatefulSet是什麼?顧名思義,有狀態的集合,管理全部有狀態的服務,好比MySQL、MongoDB集羣等。

StatefulSet本質上是Deployment的一種變體,在v1.9版本中已成爲GA版本,它爲了解決有狀態服務的問題,它所管理的Pod擁有固定的Pod名稱,啓停順序,在StatefulSet中,Pod名字稱爲網絡標識(hostname),還必需要用到共享存儲。

在Deployment中,與之對應的服務是service,而在StatefulSet中與之對應的headless service,headless service,即無頭服務,與service的區別就是它沒有Cluster IP,解析它的名稱時將返回該Headless Service對應的所有Pod的Endpoint列表。

除此以外,StatefulSet在Headless Service的基礎上又爲StatefulSet控制的每一個Pod副本建立了一個DNS域名,這個域名的格式爲:
$(podname).(headless server name)   
FQDN: $(podname).(headless server name).namespace.svc.cluster.local

statefulset控制器應用

statefulset要知足一下幾點

  • 穩定且惟一的網絡標識符;nginx

    如: Redis集羣, 在Redis集羣中,它是經過槽位來存儲數據的,假如:第一個節點是0~1000,第二個節點是1001~2000,第三個節點2001~3000...等等,這就使得Redis集羣中每一個節點要經過ID來標識本身,如: 第二個節點宕機了,重建後它必須還叫第二個節點,或者說第二個節點叫R2,它必須還叫R2,這樣在獲取1001~2000槽位的數據時,才能找到數據,不然Redis集羣將沒法找到這段數據。web

  • 穩定且持久的存儲api

  • 有序、平滑的部署和擴展安全

    如 MySQL集羣,要先啓動主節點, 若從節點沒有要求,則可一塊兒啓動,若從節點有啓動順序要求,可先啓動第一個從節點,接着第二從節點等;這個過程就是有順序,平滑安全的啓動。網絡

  • 有序、平滑的終止和刪除app

    即: 咱們先終止從節點,若從節點是有啓動順序的,那麼關閉時,也要按照逆序終止,即啓動時是從S1~S4以此啓動,則關閉時,則是先關閉S4,而後時S3,依次關閉,最後在關閉主節點。less

  • 有序的滾動更新ide

    MySQL在更新時,應該先更新從節點,所有的從節點都更新完了,最後在更新主節點,由於新版本通常可兼容老版本,可是必定要注意,若新版本不兼容老版本就很很麻煩spa

statefulset組成

  • Headless Service 用於定義網絡標識(DNS)
  • volumeClaimTemplates 用於建立PV
  • StatefulSet 用於定義具體應用

建立一個statefulset

apiVersion: v1
kind: Service
metadata:
  name: myapp-sts
  labels:
    app: myapp-sts
spec:
  ports:
  - port: 80
    name: web
  clusterIP: "None"
  selector:
    app: myapp-pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: myapp
spec:
  serviceName: myapp-sts #聲明它屬於哪一個Headless Service.
  replicas: 2
  selector:
    matchLabels:
      app: myapp-pod
  template:
    metadata:
      labels:
        app: myapp-pod
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: myappdata
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: myappdata
    spec:
      accessModes: ["ReadWriteOnce"]
      #storageClassName: "rook-ceph-block"
      resources:
        requests:
          storage: 1Gi

能夠正確解析到ip

[root@master statfulset]# nslookup myapp-1.myapp-sts.default.svc.cluster.local 10.96.0.10
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   myapp-1.myapp-sts.default.svc.cluster.local
Address: 10.244.1.30

[root@master statfulset]# nslookup myapp-0.myapp-sts.default.svc.cluster.local 10.96.0.10
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   myapp-0.myapp-sts.default.svc.cluster.local
Address: 10.244.1.29

擴容和縮容

#擴容至三個pod
kubectl scale sts myapp --replicas=3
#而後從新縮容至兩個pod
kubectl scale sts myapp --replicas=2

擴容當中出現了一個問題, 新建立的pod處於pending狀態, describe看到是mount的問題, 原來是以前pod掛載的pv變成了released狀態, 並無變成available狀態, 通過查找發現最關鍵的是PV的spec.claimRef字段,該字段記錄着原來PVC的綁定信息,刪除綁定信息,便可從新釋放PV從而達到Available。

statefulset管理pod的啓停順序

  • 有序部署:部署StatefulSet時,若是有多個Pod副本,它們會被順序地建立(從0到N-1)而且,在下一個Pod運行以前全部以前的Pod必須都是Running和Ready狀態。
  • 有序刪除:當Pod被刪除時,它們被終止的順序是從N-1到0。
  • 有序擴展:當對Pod執行擴展操做時,與部署同樣,它前面的Pod必須都處於Running和Ready狀態

statefulset管理策略

  • OrderedReady:上述的啓停順序,默認設置。

    spec:
      podManagementPolicy: OrderedReady
  • Parallel:告訴StatefulSet控制器並行啓動或終止全部Pod,而且在啓動或終止另外一個Pod以前不等待前一個Pod變爲Running and Ready或徹底終止。

    spec:
      podManagementPolicy: Parallel

statefulSet的更新策略:

kubectl explain sts.spec.updateStrategy.rollingUpdate

partition: 這種更新策略的含義是, 若當前statefulSet的副本數爲5個,則Pod名爲pod-0~pod-4,那麼此時定義partition=4, 就意味着我要更新大於等於4的Pod,而只有pod-4的ID 4 是大於等於4的,因此只有pod-4會被更新,其它不會,這就是金絲雀更新。若後期發現pod-4更新後,工做一切正常,那麼就能夠調整partition=0,這樣只要大於等於0的pod ID都將被更新。

金絲雀更新

修改滾動更新策略,查看效果

kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
#修改statefulset的image
kubectl set image sts/myapp myapp=ikubernetes/myapp:v2

#查看已經修改爲功了
[root@master statfulset]# kubectl get sts myapp -o wide
NAME    READY   AGE   CONTAINERS   IMAGES
myapp   4/4     16h   myapp        ikubernetes/myapp:v2

由於策略寫的是從第二個容器開始更新

經過命令kubectl get pod myapp-1 -o yaml能夠看到2以前的image沒有改變

經過命令kubectl get pod myapp-2 -o yaml能夠看到2以後的image都已經改變了

#再從新把partition改成0, 則把以前的pod的image都修改生效了
kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
這種方式就能夠模擬金絲雀發佈
[root@master statfulset]# kubectl get pods -l app=myapp-pod -o custom-columns=NAME:metadata.name,IMAGE:spec.containers[0].image
NAME      IMAGE
myapp-0   ikubernetes/myapp:v2
myapp-1   ikubernetes/myapp:v2
myapp-2   ikubernetes/myapp:v2
myapp-3   ikubernetes/myapp:v2

暫存更新操做

分區更新操做
將spec.updateStrategy.rollingUpdate.partition設置爲Pod副本數量時,即意味着全部Pod資源都不會處於可直接更新的分區內,直到partition小於Pod數時,纔會開始更新

此時,即使刪除某Pod,也會按舊版本進行重建,即暫存狀態的更新對全部Pod資源均不產生影響

使用go-template自定義資源輸出信息

kubectl get pod myapp-1 -o go-template --template='{{.status.podIP}}'
[root@master statfulset]# kubectl get pod myapp-1 -o go-template --template='{{range .spec.containers}}{{.image}}{{end}}'
ikubernetes/myapp:v2

由於這裏查看containers的image信息是一個列表信息, 因此要用到range

關於更多的go-template的使用方法, 能夠參考這位老哥寫的博客: https://www.bbsmax.com/A/gAJGgjX3JZ/

參考連接

https://www.cnblogs.com/wn1m/p/11289079.html

https://www.cnblogs.com/tylerzhou/p/11027559.html

https://www.cnblogs.com/xzkzzz/p/9871837.html

https://pdf.us/2019/03/15/3013.html

相關文章
相關標籤/搜索