k8s編排之StatefulSet知識點詳解二
StatefulSet 對存儲狀態(tài)的管理機制
這個機制,主要使用的是一個叫作 Persistent Volume Claim 的功能。
要在一個 Pod 里聲明 Volume,只要在 Pod 里加上 spec.volumes 字段即可。然后,你就可以在這個字段里定義一個具體類型的 Volume 了,比如:hostPath。
可是,你有沒有想過這樣一個場景:如果你并不知道有哪些 Volume 類型可以用,要怎么辦呢?
更具體地說,作為一個應(yīng)用開發(fā)者,我可能對持久化存儲項目(比如 Ceph、GlusterFS 等)一竅不通,也不知道公司的 Kubernetes 集群里到底是怎么搭建出來的,我也自然不會編寫它們對應(yīng)的 Volume 定義文件。
這些關(guān)于 Volume 的管理和遠(yuǎn)程持久化存儲的知識,不僅超越了開發(fā)者的知識儲備,還會有暴露公司基礎(chǔ)設(shè)施秘密的風(fēng)險。
比如,下面這個例子,就是一個聲明了 Ceph RBD 類型 Volume 的 Pod:
apiVersion: v1 kind: Pod metadata: name: rbd spec: containers: - image: kubernetes/pause name: rbd-rw volumeMounts: - name: rbdpd mountPath: /mnt/rbd volumes: - name: rbdpd rbd: monitors: - '10.16.154.78:6789' - '10.16.154.82:6789' - '10.16.154.83:6789' pool: kube image: foo fsType: ext4 readOnly: true user: admin keyring: /etc/ceph/keyring imageformat: "2" imagefeatures: "layering"
其一,如果不懂得 Ceph RBD 的使用方法,那么這個 Pod 里 Volumes 字段,你十有八九也完全看不懂。其二,這個 Ceph RBD 對應(yīng)的存儲服務(wù)器的地址、用戶名、授權(quán)文件的位置,也都被輕易地暴露給了全公司的所有開發(fā)人員,這是一個典型的信息被“過度暴露”的例子。
這也是為什么,在后來的演化中,Kubernetes 項目引入了一組叫作 Persistent Volume Claim(PVC)和 Persistent Volume(PV)的 API 對象,大大降低了用戶聲明和使用持久化 Volume 的門檻。
舉個例子,有了 PVC 之后,一個開發(fā)人員想要使用一個 Volume,只需要簡單的兩步即可。
第一步:定義一個 PVC,聲明想要的 Volume 的屬性
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pv-claim spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
可以看到,在這個 PVC 對象里,不需要任何關(guān)于 Volume 細(xì)節(jié)的字段,只有描述性的屬性和定義。比如,storage: 1Gi,表示我想要的 Volume 大小至少是 1 GiB;accessModes: ReadWriteOnce,表示這個 Volume 的掛載方式是可讀寫,并且只能被掛載在一個節(jié)點上而非被多個節(jié)點共享。
第二步:在應(yīng)用的 Pod 中,聲明使用這個 PVC
apiVersion: v1 kind: Pod metadata: name: pv-pod spec: containers: - name: pv-container image: nginx ports: - containerPort: 80 name: "http-server" volumeMounts: - mountPath: "/usr/share/nginx/html" name: pv-storage volumes: - name: pv-storage persistentVolumeClaim: claimName: pv-claim
可以看到,在這個 Pod 的 Volumes 定義中,我們只需要聲明它的類型是 persistentVolumeClaim,然后指定 PVC 的名字,而完全不必關(guān)心 Volume 本身的定義。
這時候,只要我們創(chuàng)建這個 PVC 對象,Kubernetes 就會自動為它綁定一個符合條件的 Volume??墒?,這些符合條件的 Volume 又是從哪里來的呢?
答案是,它們來自于由運維人員維護的 PV(Persistent Volume)對象。
常見的 PV 對象的 YAML 文件
kind: PersistentVolume apiVersion: v1 metadata: name: pv-volume labels: type: local spec: capacity: storage: 10Gi rbd: monitors: - '10.16.154.78:6789' - '10.16.154.82:6789' - '10.16.154.83:6789' pool: kube image: foo fsType: ext4 readOnly: true user: admin keyring: /etc/ceph/keyring imageformat: "2" imagefeatures: "layering"
可以看到,這個 PV 對象的 spec.rbd 字段,正是我們前面介紹過的 Ceph RBD Volume 的詳細(xì)定義。而且,它還聲明了這個 PV 的容量是 10 GiB。這樣,Kubernetes 就會為我們剛剛創(chuàng)建的 PVC 對象綁定這個 PV。
所以,Kubernetes 中 PVC 和 PV 的設(shè)計,實際上類似于“接口”和“實現(xiàn)”的思想。開發(fā)者只要知道并會使用“接口”,即:PVC;而運維人員則負(fù)責(zé)給“接口”綁定具體的實現(xiàn),即:PV。
這種解耦,就避免了因為向開發(fā)者暴露過多的存儲系統(tǒng)細(xì)節(jié)而帶來的隱患。此外,這種職責(zé)的分離,往往也意味著出現(xiàn)事故時可以更容易定位問題和明確責(zé)任,從而避免“扯皮”現(xiàn)象的出現(xiàn)。
而 PVC、PV 的設(shè)計,也使得 StatefulSet 對存儲狀態(tài)的管理成為了可能。
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: nginx:1.9.1 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
這次,我們?yōu)檫@個 StatefulSet 額外添加了一個 volumeClaimTemplates 字段。從名字就可以看出來,它跟 Deployment 里 Pod 模板(PodTemplate)的作用類似。也就是說,凡是被這個 StatefulSet 管理的 Pod,都會聲明一個對應(yīng)的 PVC;而這個 PVC 的定義,就來自于 volumeClaimTemplates 這個模板字段。更重要的是,這個 PVC 的名字,會被分配一個與這個 Pod 完全一致的編號。
這個自動創(chuàng)建的 PVC,與 PV 綁定成功后,就會進入 Bound 狀態(tài),這就意味著這個 Pod 可以掛載并使用這個 PV 了。
如果你還是不太理解 PVC 的話,可以先記住這樣一個結(jié)論:PVC 其實就是一種特殊的 Volume。只不過一個 PVC 具體是什么類型的 Volume,要在跟某個 PV 綁定之后才知道。關(guān)于 PV、PVC 更詳細(xì)的知識,我會在容器存儲部分做進一步解讀。
當(dāng)然,PVC 與 PV 的綁定得以實現(xiàn)的前提是,運維人員已經(jīng)在系統(tǒng)里創(chuàng)建好了符合條件的 PV(比如,我們在前面用到的 pv-volume);或者,你的 Kubernetes 集群運行在公有云上,這樣 Kubernetes 就會通過 Dynamic Provisioning 的方式,自動為你創(chuàng)建與 PVC 匹配的 PV。
所以,我們在使用 kubectl create 創(chuàng)建了 StatefulSet 之后,就會看到 Kubernetes 集群里出現(xiàn)了兩個 PVC
可以看到,這些 PVC,都以“<PVC 名字 >-<StatefulSet 名字 >-< 編號 >”的方式命名,并且處于 Bound 狀態(tài)。
我們前面已經(jīng)講到過,這個 StatefulSet 創(chuàng)建出來的所有 Pod,都會聲明使用編號的 PVC。比如,在名叫 web-0 的 Pod 的 volumes 字段,它會聲明使用名叫 www-web-0 的 PVC,從而掛載到這個 PVC 所綁定的 PV。
所以,我們就可以使用如下所示的指令,在 Pod 的 Volume 目錄里寫入一個文件,來驗證一下上述 Volume 的分配情況
for i in 0 1; do kubectl exec web-$i -- sh -c 'echo hello $(hostname) > /usr/share/nginx/html/index.html'; done
如上所示,通過 kubectl exec 指令,我們在每個 Pod 的 Volume 目錄里,寫入了一個 index.html 文件。這個文件的內(nèi)容,正是 Pod 的 hostname。比如,我們在 web-0 的 index.html 里寫入的內(nèi)容就是 "hello web-0"。
此時,如果你在這個 Pod 容器里訪問“http://localhost”,你實際訪問到的就是 Pod 里 Nginx 服務(wù)器進程,而它會為你返回 /usr/share/nginx/html/index.html 里的內(nèi)容。這個操作的執(zhí)行方法如下所示:
$ for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done hello web-0 hello web-1
如果你使用 kubectl delete 命令刪除這兩個 Pod,這些 Volume 里的文件會不會丟失呢?
可以看到,正如我們前面介紹過的,在被刪除之后,這兩個 Pod 會被按照編號的順序被重新創(chuàng)建出來。而這時候,如果你在新創(chuàng)建的容器里通過訪問“http://localhost”的方式去訪問 web-0 里的 Nginx 服務(wù)
就會發(fā)現(xiàn),這個請求依然會返回:hello web-0。也就是說,原先與名叫 web-0 的 Pod 綁定的 PV,在這個 Pod 被重新創(chuàng)建之后,依然同新的名叫 web-0 的 Pod 綁定在了一起。對于 Pod web-1 來說,也是完全一樣的情況。
這是怎么做到的呢?
其實,我和你分析一下 StatefulSet 控制器恢復(fù)這個 Pod 的過程,你就可以很容易理解了。
首先,當(dāng)你把一個 Pod,比如 web-0,刪除之后,這個 Pod 對應(yīng)的 PVC 和 PV,并不會被刪除,而這個 Volume 里已經(jīng)寫入的數(shù)據(jù),也依然會保存在遠(yuǎn)程存儲服務(wù)里(比如,我們在這個例子里用到的 Ceph 服務(wù)器)。
此時,StatefulSet 控制器發(fā)現(xiàn),一個名叫 web-0 的 Pod 消失了。所以,控制器就會重新創(chuàng)建一個新的、名字還是叫作 web-0 的 Pod 來,“糾正”這個不一致的情況。
需要注意的是,在這個新的 Pod 對象的定義里,它聲明使用的 PVC 的名字,還是叫作:www-web-0。這個 PVC 的定義,還是來自于 PVC 模板(volumeClaimTemplates),這是 StatefulSet 創(chuàng)建 Pod 的標(biāo)準(zhǔn)流程。
所以,在這個新的 web-0 Pod 被創(chuàng)建出來之后,Kubernetes 為它查找名叫 www-web-0 的 PVC 時,就會直接找到舊 Pod 遺留下來的同名的 PVC,進而找到跟這個 PVC 綁定在一起的 PV。
這樣,新的 Pod 就可以掛載到舊 Pod 對應(yīng)的那個 Volume,并且獲取到保存在 Volume 里的數(shù)據(jù)。
通過這種方式,Kubernetes 的 StatefulSet 就實現(xiàn)了對應(yīng)用存儲狀態(tài)的管理。
看到這里,你是不是已經(jīng)大致理解了 StatefulSet 的工作原理呢?現(xiàn)在,我再為你詳細(xì)梳理一下吧。
首先,StatefulSet 的控制器直接管理的是 Pod。這是因為,StatefulSet 里的不同 Pod 實例,不再像 ReplicaSet 中那樣都是完全一樣的,而是有了細(xì)微區(qū)別的。比如,每個 Pod 的 hostname、名字等都是不同的、攜帶了編號的。而 StatefulSet 區(qū)分這些實例的方式,就是通過在 Pod 的名字里加上事先約定好的編號。
其次,Kubernetes 通過 Headless Service,為這些有編號的 Pod,在 DNS 服務(wù)器中生成帶有同樣編號的 DNS 記錄。只要 StatefulSet 能夠保證這些 Pod 名字里的編號不變,那么 Service 里類似于 web-0.nginx.default.svc.cluster.local 這樣的 DNS 記錄也就不會變,而這條記錄解析出來的 Pod 的 IP 地址,則會隨著后端 Pod 的刪除和再創(chuàng)建而自動更新。這當(dāng)然是 Service 機制本身的能力,不需要 StatefulSet 操心。
最后,StatefulSet 還為每一個 Pod 分配并創(chuàng)建一個同樣編號的 PVC。這樣,Kubernetes 就可以通過 Persistent Volume 機制為這個 PVC 綁定上對應(yīng)的 PV,從而保證了每一個 Pod 都擁有一個獨立的 Volume。
在這種情況下,即使 Pod 被刪除,它所對應(yīng)的 PVC 和 PV 依然會保留下來。所以當(dāng)這個 Pod 被重新創(chuàng)建出來之后,Kubernetes 會為它找到同樣編號的 PVC,掛載這個 PVC 對應(yīng)的 Volume,從而獲取到以前保存在 Volume 里的數(shù)據(jù)。
以上就是k8s編排之StatefulSet知識點詳解二的詳細(xì)內(nèi)容,更多關(guān)于k8s編排StatefulSet的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Rainbond對前端項目Vue及React的持續(xù)部署
這篇文章主要為大家介紹了Rainbond對前端項目Vue及React的持續(xù)部署,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-04-042022最新青龍面板對接機器人的詳細(xì)過程(傻妞對接onebot(oicq)協(xié)議實現(xiàn)機器人功能)
這篇文章主要介紹了2022最新青龍面板對接機器人的詳細(xì)過程(傻妞對接onebot(oicq)協(xié)議實現(xiàn)機器人功能),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05Kubernetes應(yīng)用服務(wù)質(zhì)量管理詳解
這篇文章主要為大家介紹了Kubernetes應(yīng)用服務(wù)質(zhì)量管理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11阿里云kubernetes查找鏡像中jar包的方法(docker查看鏡像中的jar)
這篇文章主要給大家介紹了關(guān)于阿里云kubernetes查找鏡像中jar包的方法,也就是在docker查看鏡像中的jar,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09