該篇文章已經(jīng)被專欄《從零開始學(xué)k8s》收錄
上一篇文章:kubernetes持久化存儲下 點(diǎn)擊跳轉(zhuǎn)
Statefulset 控制器:概念、原理解讀
StatefulSet 是為了管理有狀態(tài)服務(wù)的問題而設(shè)計的
對于StatefulSet中的Pod,每個Pod掛載自己獨(dú)立的存儲,如果一個Pod出現(xiàn)故障,從其他節(jié)點(diǎn)啟動一個同樣名字的Pod,要掛載上原來Pod的存儲繼續(xù)以它的狀態(tài)提供服務(wù)。
有狀態(tài)服務(wù)?
StatefulSet 是有狀態(tài)的集合,管理有狀態(tài)的服務(wù),它所管理的 Pod 的名稱不能隨意變化。數(shù)據(jù)持久化的目錄也是不一樣,每一個 Pod 都有自己獨(dú)有的數(shù)據(jù)持久化存儲目錄。比如 MySQL 主從、redis 集群等。
- 讓每個Pod獨(dú)立的
- 讓每個Pod獨(dú)立的,保持Pod啟動順序和唯一性
- 唯一的網(wǎng)絡(luò)標(biāo)識符,持久存儲
- 有序,比如mysql中的主從
適合StatefulSet的業(yè)務(wù)包括數(shù)據(jù)庫服務(wù) MySQL 和 PostgreSQL,集群化管理服務(wù)Zookeeper、etcd等有狀態(tài)服務(wù)
StatefulSet的另一種典型應(yīng)用場景是作為一種比普通容器更穩(wěn)定可靠的模擬虛擬機(jī)的機(jī)制。傳統(tǒng)的虛擬機(jī)正是一種有狀態(tài)的寵物,運(yùn)維人員需要不斷地維護(hù)它,容器剛開始流行時,我們用容器來模擬虛擬機(jī)使用,所有狀態(tài)都保存在容器里,而這已被證明是非常不安全、不可靠的。
使用StatefulSet,Pod仍然可以通過漂移到不同節(jié)點(diǎn)提供高可用,而存儲也可以通過外掛的存儲來提供高可靠性,StatefulSet做的只是將確定的Pod與確定的存儲關(guān)聯(lián)起來保證狀態(tài)的連續(xù)性。
無狀態(tài)服務(wù)?
RC、Deployment、DaemonSet 都是管理無狀態(tài)的服務(wù),它們所管理的 Pod 的 IP、名字,啟停順序等都是隨機(jī)的。個體對整體無影響,所有 pod 都是共用一個數(shù)據(jù)卷的,部署的 tomcat 就是無狀態(tài)的服務(wù),tomcat 被刪除,在啟動一個新的 tomcat,加入到集群即可,跟 tomcat 的名字無關(guān)。
- 認(rèn)為Pod都是一樣的
- 沒有順序要求
- 不考慮應(yīng)用在哪個node上運(yùn)行
- 能夠進(jìn)行隨意伸縮和擴(kuò)展
StatefulSet 由以下幾個部分組成:
1.Headless Service:用來定義 pod 網(wǎng)路標(biāo)識,生成可解析的 DNS 記錄
2.volumeClaimTemplates:存儲卷申請模板,創(chuàng)建 pvc,指定 pvc 名稱大小,自動創(chuàng)建 pvc,且 pvc 由存儲類供應(yīng)。
3.StatefulSet:管理 pod 的
什么是 Headless service
Headless service 不分配 clusterIP,headless service 可以通過解析 service 的 DNS,返回所有 Pod 的 dns 和 ip 地址 (statefulSet 部署的 Pod 才有 DNS),普通的 service,只能通過解析 service 的 DNS 返回 service 的 ClusterIP。
為什么要用 headless service(沒有 service ip 的 service)?
在使用 Deployment 時,創(chuàng)建的 Pod 名稱是沒有順序的,是隨機(jī)字符串,在用 statefulset 管理 pod 時要求 pod 名稱必須是有序的 ,每一個 pod 不能被隨意取代,pod 重建后 pod 名稱還是一樣的。因為 pod IP 是變化的,所以要用 Pod 名稱來識別。pod 名稱是 pod 唯一性的標(biāo)識符, 必須持久穩(wěn)定有效。這時候要用到無頭服務(wù),它可以給每個 Pod 一個唯一的名稱。
1.headless service 會為 service 分配一個域名
<service name>.$<namespace name>.svc.cluster.local
K8s 中資源的全局 FQDN 格式:
Service_NAME.NameSpace_NAME.Domain.LTD.
Domain.LTD.=svc.cluster.local. #這是默認(rèn) k8s 集群的域名。
FQDN 全稱 Fully Qualified Domain Name 即全限定域名:同時帶有主機(jī)名和域名的名稱
FQDN = Hostname + DomainName
如 主機(jī)名是 paopao 域名是 csdn.com
FQDN= paopao.csdn.com
2.StatefulSet 會為關(guān)聯(lián)的 Pod 保持一個不變的 Pod Name
statefulset 中 Pod 的名字格式為$(StatefulSet name)-$(pod 序號)
3.StatefulSet 會為關(guān)聯(lián)的 Pod 分配一個 dnsName
$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local
為什么要用 volumeClaimTemplate?
對于有狀態(tài)應(yīng)用都會用到持久化存儲,比如 mysql 主從,由于主從數(shù)據(jù)庫的數(shù)據(jù)是不能存放在一個目錄下的,每個 mysql 節(jié)點(diǎn)都需要有自己獨(dú)立的存儲空間。而在 deployment 中創(chuàng)建的存儲卷是一個共享的存儲卷,多個 pod 使用同一個存儲卷,它們數(shù)據(jù)是同步的,而 statefulset 定義中的每一個 pod 都不能使用同一個存儲卷,這就需要使用 volumeClainTemplate,當(dāng)在使用statefulset 創(chuàng)建 pod 時,volumeClainTemplate 會自動生成一個 PVC,從而請求綁定一個PV,每一個 pod 都有自己專用的存儲卷。Pod、PVC 和 PV 對應(yīng)的關(guān)系圖如下:
Statefulset 資源清單文件編寫技巧
#查看定義 Statefulset 資源需要的字段
[root@k8smaster ~]# kubectl explain statefulset
KIND: StatefulSet
VERSION: apps/v1
DESCRIPTION:
StatefulSet represents a set of pods with consistent identities. Identities
are defined as: - Network: A single stable DNS and hostname. - Storage: As
many VolumeClaims as requested. The StatefulSet guarantees that a given
network identity will always map to the same storage identity.
FIELDS:
apiVersion <string> #定義 statefulset 資源需要使用的 api 版本
kind <string> #定義的資源類型
metadata<Object> #元數(shù)據(jù)
spec <Object> #定義容器相關(guān)的信息
#查看 statefulset.spec 字段如何定義?
[root@k8smaster ~]# kubectl explain statefulset.spec
KIND: StatefulSet
VERSION: apps/v1
RESOURCE: spec <Object>
DESCRIPTION:
Spec defines the desired identities of pods in this set.
A StatefulSetSpec is the specification of a StatefulSet.
FIELDS:
podManagementPolicy <string> #pod 管理策略
replicas <integer> #副本數(shù)
revisionHistoryLimit <integer> #保留的歷史版本
selector <Object> -required- #標(biāo)簽選擇器,選擇它所關(guān)聯(lián)的 pod
serviceName <string> -required- #headless service 的名字
template <Object> -required- #生成 pod 的模板
updateStrategy <Object> #更新策略
volumeClaimTemplates<[]Object> #存儲卷申請模板
#查看 statefulset 的 spec.template 字段如何定義?
#對于 template 而言,其內(nèi)部定義的就是 pod,pod 模板是一個獨(dú)立的對象
[root@k8smaster ~]# kubectl explain statefulset.spec.template
KIND: StatefulSet
VERSION: apps/v1
RESOURCE: template <Object>
DESCRIPTION:
template is the object that describes the pod that will be created if
insufficient replicas are detected. Each pod stamped out by the StatefulSet
will fulfill this Template, but have a unique identity from the rest of the
StatefulSet.
PodTemplateSpec describes the data a pod should have when created from a
template
FIELDS:
metadata <Object>
spec <Object> #定義容器屬性的
通過上面可以看到,statefulset 資源中有兩個 spec 字段。
第一個 spec 聲明的是 statefulset 定義多少個 Pod 副本(默認(rèn)將僅部署 1 個 Pod)、匹配 Pod 標(biāo)簽的選擇器、創(chuàng)建 pod 的模板、存儲卷申請模板。
第二個 spec 是 spec.template.spec:主要用于 Pod 里的容器屬性等配置。.spec.template 里的內(nèi)容是聲明 Pod 對象時要定義的各種屬性,所以這部分也叫做 PodTemplate(Pod 模板)。
還有一個值得注意的地方是:在.spec.selector 中定義的標(biāo)簽選擇器必須能夠匹配到 spec.template.metadata.labels 里定義的 Pod 標(biāo)簽,否則 Kubernetes 將 不允許創(chuàng)建 statefulset。文章來源:http://www.zghlxwxcb.cn/news/detail-778043.html
Statefulset 使用案例:部署 web 站點(diǎn)
#創(chuàng)建存儲類
[root@k8smaster ~]# mkdir state
[root@k8smaster ~]# cd state/
[root@k8smaster state]# vim class-web.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-web
provisioner: example.com/nfs
#更新資源清單文件
[root@xianchaomaster1 ~]# kubectl apply -f class-web.yaml
[root@k8smaster state]# kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-web example.com/nfs Delete Immediate false 6m16s
#編寫一個 Statefulset 資源清單文件
[root@k8smaster state]# vim statefulset.yaml
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
serviceName: "nginx"
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "nfs-web"
resources:
requests:
storage: 1Gi
#更新資源清單文件
[root@k8smaster state]# kubectl apply -f statefulset.yaml
service/nginx created
statefulset.apps/web created
#查看 statefulset 是否創(chuàng)建成功
[root@k8smaster state]# kubectl get sts -o wide
NAME READY AGE CONTAINERS IMAGES
web 2/2 59s nginx nginx
#查看 pod
[root@k8smaster state]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 76s
web-1 1/1 Pending 0 76s
#通過上面可以看到創(chuàng)建的 pod 是有序的
#查看 headless service
[root@k8smaster state]# kubectl get svc -l app=nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None <none> 80/TCP 3m
#查看 pvc
[root@k8smaster state]# kubectl get pvc
www-web-0 Bound pvc-13a0482f-4927-63ff-9f2e-1b926b299c6f 1Gi RWO,RWX nfs-web 4m45s
www-web-1 Bound pvc-bc23p2a9-5bjd-00df-829f-ccb4d24g01h1 1Gi RWO,RWX nfs-web 4m41s
#查看 pv
[root@k8smaster state]# kubectl get pv
pvc-13a0482f-4927-63ff-9f2e-1b926b299c6f 1Gi RWO,RWX Delete Bound default/www-web-0 nfs-web 5m3s
pvc-bc23p2a9-5bjd-00df-829f-ccb4d24g01h1 1Gi RWO,RWX Delete Bound default/www-web-1 nfs-web 5m59s
#在data nfs_pro目錄下劃分的pv
#查看 pod 主機(jī)名
[root@k8smaster ~]# for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname';done
web-0
web-1
#使用 kubectl run 運(yùn)行一個提供 nslookup 命令的容器的,這個命令來自于 dnsutils 包,通過對 pod 主機(jī)名執(zhí)行 nslookup,可以檢查它們在集群內(nèi)部的 DNS 地址:
[root@k8smaster ~]# kubectl exec -it web-1 -- /bin/bash
root@web-1:/# apt-get update
root@web-1:/# apt-get install dnsutils -y
root@web-1:/# nslookup web-0.nginx.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: web-0.nginx.default.svc.cluster.local
#statefulset 創(chuàng)建的 pod 也是有 dns 記錄的
Address: 10.244.103.139 #解析到的是 pod 的 ip 地址
root@web-1:/# nslookup nginx.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: nginx.default.svc.cluster.local #查詢 service dns,會把對應(yīng)的 pod ip 解析出來
Address: 10.244.103.139
Name: nginx.default.svc.cluster.local
Address: 10.244.121.93
[root@k8smaster state]# kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: <none>
Type: ClusterIP
IP: none
Port: web 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.103.139:80,10.244.121.93:80 #這兩個pod都有app=ngin的標(biāo)簽,service把這兩個都寫入endpoints列表了
Session Affinity: None
Events: <none>
root@web-1:/# dig -t A nginx.default.svc.cluster.local @10.96.0.10
; <<>> DiG 9.11.5-P4-5.1+deb10u3-Debian <<>> -t A nginx.default.svc.cluster.local @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16869
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 1cf973a5daa99ac7 (echoed)
;; QUESTION SECTION:
;nginx.default.svc.cluster.local. IN A
;; ANSWER SECTION:
nginx.default.svc.cluster.local. 30 IN A 10.244.103.139
nginx.default.svc.cluster.local. 30 IN A 10.244.121.93
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Thu Jul 14 06:49:51 UTC 2022
;; MSG SIZE rcvd: 166
root@web-1:/# nslookup kubernetes.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: kubernetes.default.svc.cluster.local
Address: 10.96.0.1
#解析kubernertes,有ip會把ip解析出來,沒有會解析后端pod
dig 的使用
dig -t A nginx.default.svc.cluster.local @10.96.0.10
格式如下:
@來指定域名服務(wù)器
A 為解析類型 ,A 記錄
-t 指定要解析的類型
A 記錄:
A 記錄是解析域名到 IP
資源清單詳細(xì)解讀:
apiVersion: v1 #定義 api 版本
kind: Service #定義要創(chuàng)建的資源:service
metadata:
name: nginx #定義 service 的名字
labels:
app: nginx #service 的標(biāo)簽
spec:
ports:
- port: 80
name: web
clusterIP: None #創(chuàng)建一個沒有 ip 的 service
selector:
app: nginx #選擇擁有 app=nginx 標(biāo)簽的 pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx" #headless service 的名字
replicas: 2 #副本數(shù)
template: #定義 pod 的模板
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: #存儲卷申請模板
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "nfs-web" #指定從哪個存儲類申請 pv
resources:
requests:
storage: 1Gi #需要 1G 的 pvc,會自動跟符合條件的 pv 綁定
擴(kuò)展:
service 和 headless service 區(qū)別:
#deployment 創(chuàng)建的 pod 是隨機(jī)生成的 解析的是 service 的 ip 地址
Statefulset 管理 pod:擴(kuò)容、縮容、更新
#Statefulset 實現(xiàn) pod 的動態(tài)擴(kuò)容
如果我們覺得兩個副本太少了,想要增加,只需要修改配置文件 statefulset.yaml 里的 replicas的值即可,原來 replicas: 2,現(xiàn)在變成 replicaset: 3,修改之后,執(zhí)行如下命令更新:
[root@k8smaster state]# kubectl apply -f statefulset.yaml
service/nginx unchanged
statefulset.apps/web configured
[root@k8smaster state]# kubectl get sts
web 3/3 30m
[root@k8smaster state]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 61m
web-1 1/1 Running 0 60m
web-2 1/1 Running 0 79s
#也可以直接編輯控制器實現(xiàn)擴(kuò)容
[root@xianchaomaster1 ~]# kubectl edit sts web
#這個是我們把請求提交給了 apiserver,實時修改,把 spec 下的 replicas 后面的值改成 4,保存退出
[root@xianchaomaster1 ~]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 62m
web-1 1/1 Running 0 62m
web-2 1/1 Running 0 3m13s
web-3 1/1 Running 0 26s
#Statefulset 實現(xiàn) pod 的動態(tài)縮容
如果我們覺得 4 個 Pod 副本太多了,想要減少,只需要修改配置文件 statefulset.yaml 里的
replicas 的值即可,把 replicaset:4 變成 replicas: 2,修改之后,執(zhí)行如下命令更新:
[root@k8smaster state]# kubectl apply -f statefulset.yaml
service/nginx unchanged
statefulset.apps/web configured
[root@k8smaster state]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 64m
web-1 1/1 Running 0 63m
#Statefulset 實現(xiàn) pod 的更新
[root@k8smaster state]# kubectl edit sts web
#修改鏡像 nginx 變成 image: tomcat,修改之后保存退出
[root@k8smaster state]# kubectl get pods -o wide -l app=nginx
NAME READY STATUS RESTARTS AGE IP NODE
web-0 1/1 Running 0 18s 10.244.201.106 k8snode
web-1 1/1 Running 0 36s 10.244.133.176 k8snode2
#查看 pod 詳細(xì)信息
[root@k8smaster state]# kubectl describe pods web-0
通過上面可以看到 pod 已經(jīng)使用剛才更新的鏡像 tomcat 了
寫在最后
創(chuàng)作不易,如果覺得內(nèi)容對你有幫助,麻煩給個三連關(guān)注支持一下我!如果有錯誤,請在評論區(qū)指出,我會及時更改!
目前正在更新的系列:從零開始學(xué)k8s
感謝各位的觀看,文章?lián)诫s個人理解,如有錯誤請聯(lián)系我指出~文章來源地址http://www.zghlxwxcb.cn/news/detail-778043.html
到了這里,關(guān)于【云原生 | 從零開始學(xué)Kubernetes】二十三、Kubernetes控制器Statefulset的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!