kubernetes——StatefulSet詳解

概述

RC、Deployment、DaemonSet都是面向無(wú)狀態(tài)的服務(wù),它們所管理的Pod的IP、名字,啟停順序等都是隨機(jī)的,而StatefulSet是什么?顧名思義,有狀態(tài)的集合,管理所有有狀態(tài)的服務(wù),比如MySQL、MongoDB集群等。
StatefulSet本質(zhì)上是Deployment的一種變體,在v1.9版本中已成為GA版本,它為了解決有狀態(tài)服務(wù)的問(wèn)題,它所管理的Pod擁有固定的Pod名稱,啟停順序,在StatefulSet中,Pod名字稱為網(wǎng)絡(luò)標(biāo)識(shí)(hostname),還必須要用到共享存儲(chǔ)。

在Deployment中,與之對(duì)應(yīng)的服務(wù)是service,而在StatefulSet中與之對(duì)應(yīng)的headless service,headless service,即無(wú)頭服務(wù),與service的區(qū)別就是它沒(méi)有Cluster IP,解析它的名稱時(shí)將返回該Headless Service對(duì)應(yīng)的全部Pod的Endpoint列表。

除此之外,StatefulSet在Headless Service的基礎(chǔ)上又為StatefulSet控制的每個(gè)Pod副本創(chuàng)建了一個(gè)DNS域名,這個(gè)域名的格式為:

$(podname).(headless server name)
FQDN: $(podname).(headless server name).namespace.svc.cluster.local

StatefulSet示例

接下來(lái)看一些示例,演示下上面所說(shuō)的特性,以加深理解

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:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx"  #聲明它屬于哪個(gè)Headless Service.
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx:1.20.1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:   #可看作pvc的模板
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "gluster-heketi"  #存儲(chǔ)類名,改為集群中已存在的
      resources:
        requests:
          storage: 1Gi

通過(guò)該配置文件,可看出StatefulSet的三個(gè)組成部分:

  • Headless Service:名為nginx,用來(lái)定義Pod網(wǎng)絡(luò)標(biāo)識(shí)( DNS domain)。
  • StatefulSet:定義具體應(yīng)用,名為Nginx,有三個(gè)Pod副本,并為每個(gè)Pod定義了一個(gè)域名。
  • volumeClaimTemplates: 存儲(chǔ)卷申請(qǐng)模板,創(chuàng)建PVC,指定pvc名稱大小,將自動(dòng)創(chuàng)建pvc,且pvc必須由存儲(chǔ)類供應(yīng)。

為什么需要 headless service 無(wú)頭服務(wù)?
在用Deployment時(shí),每一個(gè)Pod名稱是沒(méi)有順序的,是隨機(jī)字符串,因此是Pod名稱是無(wú)序的,但是在statefulset中要求必須是有序 ,每一個(gè)pod不能被隨意取代,pod重建后pod名稱還是一樣的。而pod IP是變化的,所以是以Pod名稱來(lái)識(shí)別。pod名稱是pod唯一性的標(biāo)識(shí)符,必須持久穩(wěn)定有效。這時(shí)候要用到無(wú)頭服務(wù),它可以給每個(gè)Pod一個(gè)唯一的名稱 。

為什么需要volumeClaimTemplate?
對(duì)于有狀態(tài)的副本集都會(huì)用到持久存儲(chǔ),對(duì)于分布式系統(tǒng)來(lái)講,它的最大特點(diǎn)是數(shù)據(jù)是不一樣的,所以各個(gè)節(jié)點(diǎn)不能使用同一存儲(chǔ)卷,每個(gè)節(jié)點(diǎn)有自已的專用存儲(chǔ),但是如果在Deployment中的Pod template里定義的存儲(chǔ)卷,是所有副本集共用一個(gè)存儲(chǔ)卷,數(shù)據(jù)是相同的,因?yàn)槭腔谀0鍋?lái)的 ,而statefulset中每個(gè)Pod都要自已的專有存儲(chǔ)卷,所以statefulset的存儲(chǔ)卷就不能再用Pod模板來(lái)創(chuàng)建了,于是statefulSet使用volumeClaimTemplate,稱為卷申請(qǐng)模板,它會(huì)為每個(gè)Pod生成不同的pvc,并綁定pv, 從而實(shí)現(xiàn)各pod有專用存儲(chǔ)。這就是為什么要用volumeClaimTemplate的原因。

創(chuàng)建:

$ kubectl create -f nginx.yaml 
service "nginx" created
statefulset "web" created

看下這三個(gè)Pod創(chuàng)建過(guò)程:

#第一個(gè)是創(chuàng)建web-0
$ kubectl get pod
web-0                     1/1       ContainerCreating   0          51s

#待web-0 running且ready時(shí),創(chuàng)建web-1
$ kubectl get pod
web-0                     1/1       Running             0          51s
web-1                     0/1       ContainerCreating   0          42s

#待web-1 running且ready時(shí),創(chuàng)建web-2
$ kubectl get pod
web-0                     1/1       Running             0          1m
web-1                     1/1       Running             0          45s
web-2                     1/1       ContainerCreating   0          36s

#最后三個(gè)Pod全部running且ready
$ kubectl get pod
NAME                      READY     STATUS    RESTARTS   AGE
web-0                     1/1       Running   0          4m
web-1                     1/1       Running   0          3m
web-2                     1/1       Running   0          1m

根據(jù)volumeClaimTemplates自動(dòng)創(chuàng)建的PVC

$ kubectl get pvc
NAME              STATUS    VOLUME                                  CAPACITY   ACCESS MODES   STORAGECLASS     AGE
www-web-0         Bound     pvc-ecf003f3-828d-11e8-8815-000c29774d39   2G        RWO          gluster-heketi   7m
www-web-1         Bound     pvc-0615e33e-828e-11e8-8815-000c29774d39   2G        RWO          gluster-heketi   6m
www-web-2         Bound     pvc-43a97acf-828e-11e8-8815-000c29774d39   2G        RWO          gluster-heketi   4m

如果集群中沒(méi)有StorageClass的動(dòng)態(tài)供應(yīng)PVC的機(jī)制,也可以提前手動(dòng)創(chuàng)建多個(gè)PV、PVC,手動(dòng)創(chuàng)建的PVC名稱必須符合之后創(chuàng)建的StatefulSet命名規(guī)則:(volumeClaimTemplates.name)-(pod_name)

Statefulset名稱為web 三個(gè)Pod副本: web-0,web-1,web-2,volumeClaimTemplates名稱為:www,那么自動(dòng)創(chuàng)建出來(lái)的PVC名稱為www-web[0-2],為每個(gè)Pod創(chuàng)建一個(gè)PVC。

規(guī)律總結(jié):

匹配Pod name(網(wǎng)絡(luò)標(biāo)識(shí))的模式為:(statefulset名稱)-(序號(hào)),比如上面的示例:web-0,web-1,web-2。

StatefulSet為每個(gè)Pod副本創(chuàng)建了一個(gè)DNS域名,這個(gè)域名的格式為: $(podname).(headless server name),也就意味著服務(wù)間是通過(guò)Pod域名來(lái)通信而非Pod IP,因?yàn)楫?dāng)Pod所在Node發(fā)生故障時(shí),Pod會(huì)被飄移到其它Node上,Pod IP會(huì)發(fā)生變化,但是Pod域名不會(huì)有變化。

StatefulSet使用Headless服務(wù)來(lái)控制Pod的域名,這個(gè)域名的FQDN為:(service name).(namespace).svc.cluster.local,其中,“cluster.local”指的是集群的域名。

根據(jù)volumeClaimTemplates,為每個(gè)Pod創(chuàng)建一個(gè)pvc,pvc的命名規(guī)則匹配模式:(volumeClaimTemplates.name)-(pod_name),比如上面的volumeMounts.name=www, Pod name=web-[0-2],因此創(chuàng)建出來(lái)的PVC是www-web-0、www-web-1、www-web-2。

刪除Pod不會(huì)刪除其pvc,手動(dòng)刪除pvc將自動(dòng)釋放pv。
關(guān)于Cluster Domain、headless service名稱、StatefulSet 名稱如何影響StatefulSet的Pod的DNS域名的示例:

Cluster Domain Service (ns/name) StatefulSet (ns/name) StatefulSet Domain Pod DNS Pod Hostname
cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..N-1}.nginx.default.svc.cluster.local web-{0..N-1}
cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..N-1}.nginx.foo.svc.cluster.local web-{0..N-1}
kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0..N-1}.nginx.foo.svc.kube.local web-{0..N-1}

Statefulset的啟停順序:

  • 有序部署:部署StatefulSet時(shí),如果有多個(gè)Pod副本,它們會(huì)被順序地創(chuàng)建(從0到N-1)并且,在下一個(gè)Pod運(yùn)行之前所有之前的Pod必須都是Running和Ready狀態(tài)。

  • 有序刪除:當(dāng)Pod被刪除時(shí),它們被終止的順序是從N-1到0。

  • 有序擴(kuò)展:當(dāng)對(duì)Pod執(zhí)行擴(kuò)展操作時(shí),與部署一樣,它前面的Pod必須都處于Running和Ready狀態(tài)

Statefulset Pod管理策略:

在v1.7以后,通過(guò)允許修改Pod排序策略,同時(shí)通過(guò).spec.podManagementPolicy字段確保其身份的唯一性。

  • OrderedReady:上述的啟停順序,默認(rèn)設(shè)置。
  • Parallel:告訴StatefulSet控制器并行啟動(dòng)或終止所有Pod,并且在啟動(dòng)或終止另一個(gè)Pod之前不等待前一個(gè)Pod變?yōu)镽unning and Ready或完全終止。

StatefulSet使用場(chǎng)景:

  • 穩(wěn)定的持久化存儲(chǔ),即Pod重新調(diào)度后還是能訪問(wèn)到相同的持久化數(shù)據(jù),基于PVC來(lái)實(shí)現(xiàn)。

  • 穩(wěn)定的網(wǎng)絡(luò)標(biāo)識(shí)符,即Pod重新調(diào)度后其PodName和HostName不變。

  • 有序部署,有序擴(kuò)展,基于init containers來(lái)實(shí)現(xiàn)。

  • 有序收縮。

更新策略

在Kubernetes 1.7及更高版本中,通過(guò).spec.updateStrategy字段允許配置或禁用Pod、labels、source request/limits、annotations自動(dòng)滾動(dòng)更新功能。

  • OnDelete:通過(guò).spec.updateStrategy.type 字段設(shè)置為OnDelete,StatefulSet控制器不會(huì)自動(dòng)更新StatefulSet中的Pod。用戶必須手動(dòng)刪除Pod,以使控制器創(chuàng)建新的Pod。

  • RollingUpdate:通過(guò).spec.updateStrategy.type 字段設(shè)置為RollingUpdate,實(shí)現(xiàn)了Pod的自動(dòng)滾動(dòng)更新,如果.spec.updateStrategy未指定,則此為默認(rèn)策略。

StatefulSet控制器將刪除并重新創(chuàng)建StatefulSet中的每個(gè)Pod。它將以Pod終止(從最大序數(shù)到最小序數(shù))的順序進(jìn)行,一次更新每個(gè)Pod。在更新下一個(gè)Pod之前,必須等待這個(gè)Pod Running and Ready。

  • Partitions:通過(guò)指定 .spec.updateStrategy.rollingUpdate.partition 來(lái)對(duì) RollingUpdate 更新策略進(jìn)行分區(qū),如果指定了分區(qū),則當(dāng) StatefulSet 的 .spec.template 更新時(shí),具有大于或等于分區(qū)序數(shù)的所有 Pod 將被更新。
    具有小于分區(qū)的序數(shù)的所有 Pod 將不會(huì)被更新,即使刪除它們也將被重新創(chuàng)建。如果 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition 大于其 .spec.replicas,則其 .spec.template 的更新將不會(huì)傳播到 Pod。在大多數(shù)情況下,不需要使用分區(qū)。

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

https://www.cnblogs.com/buyicoding/p/12591259.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述 RC、Deployment、DaemonSet都是面向無(wú)狀態(tài)的服務(wù),它們所管理的Pod的IP、名字,啟停順序...
    小波同學(xué)閱讀 2,422評(píng)論 0 1
  • Statefulset控制器:概念、原理解讀StatefulSet是為了管理有狀態(tài)服務(wù)的問(wèn)題而設(shè)計(jì)的 有狀態(tài)服務(wù)?...
    菜頭_355f閱讀 2,491評(píng)論 0 0
  • 概述 RC、Deployment、DaemonSet都是面向無(wú)狀態(tài)的服務(wù),它們所管理的Pod的IP、名字,啟停順序...
    沉淪2014閱讀 11,627評(píng)論 1 5
  • 一、前言 上一文《從零開(kāi)始搭建Kubernetes集群(五、搭建K8S Ingress)》[https://www...
    宅楠軍閱讀 56,317評(píng)論 43 63
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險(xiǎn)厭惡者,不喜歡去冒險(xiǎn),但是人生放棄了冒險(xiǎn),也就放棄了無(wú)數(shù)的可能。 ...
    yichen大刀閱讀 8,169評(píng)論 0 4

友情鏈接更多精彩內(nèi)容