國外域名查詢網(wǎng)站2021年10月新聞?wù)?/h1>
深入理解StatefulSet(一):拓撲狀態(tài)
k8s有狀態(tài)與無狀態(tài)的區(qū)別
無狀態(tài)服務(wù):deployment
Deployment被設(shè)計用來管理無狀態(tài)服務(wù)的pod,每個pod完全一致.什么意思呢?
無狀態(tài)服務(wù)內(nèi)的多個Pod創(chuàng)建的順序是沒有順序的. 無狀態(tài)服務(wù)內(nèi)的多個Pod的名稱是隨機的.pod被重新啟動調(diào)度后,它的名稱與IP都會發(fā)生變化. 無狀態(tài)服務(wù)內(nèi)的多個Pod背后是共享存儲的.
有狀態(tài)服務(wù):StatefulSet
Deployment組件是為無狀態(tài)服務(wù)而設(shè)計的,其中的Pod名稱,主機名,存儲都是隨機,不穩(wěn)定的,并且Pod的創(chuàng)建與銷毀也是無序的.這個設(shè)計決定了無狀態(tài)服務(wù)并 不適合數(shù)據(jù)庫領(lǐng)域的應(yīng)用.
而Stateful管理有狀態(tài)的應(yīng)用,它的Pod有如下特征:
唯一性: 每個Pod會被分配一個唯一序號. 順序性: Pod啟動,更新,銷毀是按順序進行. 穩(wěn)定的網(wǎng)絡(luò)標識: Pod主機名,DNS地址不會隨著Pod被重新調(diào)度而發(fā)生變化. 穩(wěn)定的持久化存儲: Pod被重新調(diào)度后,仍然能掛載原有的PV,從而保證了數(shù)據(jù)的完整性和一致性.
總結(jié): 本文主要介紹了無狀態(tài)和有狀態(tài)服務(wù)在K8S中的典型應(yīng)用場景.
通過對Deployment部署無狀態(tài)服務(wù)所遇到問題的分析,引出了Stateful新的部署組件.它是通過支持Pod一些特性(e.g. 名稱唯一性,穩(wěn)定的網(wǎng)絡(luò)標識, 穩(wěn)定的持久化存儲等)來實現(xiàn)在K8S中部署運維有狀態(tài)服務(wù).
牢記: Stateful有狀態(tài)服務(wù),每個Pod有獨立的PVC/PV存儲組件
StatefulSet 的工作原理之前,必須先為你講解一個 Kubernetes 項目中非常實用的概念:Headless Service。
Service 是 Kubernetes 項目中用來將 一組 Pod 暴露給外界訪問的一種機制。
比如,一個 Deployment 有 3 個 Pod,那么我就可以 定義一個 Service。然后,用戶只要能訪問到這個 Service,它就能訪問到某個具體的 Pod。
那么,這個 Service 又是如何被訪問的呢?
第一種方式:通過 VIP(Virtual IP,即:虛擬 IP),如:當訪問 10.0.23.1 這個 Service 的 IP 地址時(VIP),它會把請求轉(zhuǎn)發(fā)到該 Service 所代理的某一個 Pod 上。
第二種方式: 以service 的 DNS 方式,但可分為2種處理方法:
(1)是 Normal Service。這種情況下,你訪問“my-svc.mynamespace.svc.cluster.local”解析到的,正是 my-svc 這個 Service 的 VIP,后面的流程就跟 VIP 方式一致了。
(2)正是 Headless Service,當你訪問“my-svc.mynamespace.svc.cluster.local”解析到的,直接就是 my-svc 代理的某一個 Pod 的 IP 地址。
區(qū)別在于,Headless Service 不需要分配一個 VIP,而是可以直接以 DNS 記錄 的方式解析出被代理 Pod 的 IP 地址。
標準的 Headless Service 對應(yīng)的 YAML 文件
apiVersion: v1
Kind: Service
metadata:name: nginxlables:app: nginx
spec:ports:- port: 80name: webclusterIP: Noneselector:app: nginx
可以觀察看到 ClusterIP 字段的值為 None,也就是所謂的 “無頭服務(wù)” 沒有VIP作為頭。
當這個 Service 被創(chuàng)建出來后并不會被分配一個 VIP,而是會以 DNS 記錄的方式暴露出它所代理的Pod。
是如何給一組 Pod 暴露端口給外界訪問的呢?在 YAML 你是觀察到有一個 Selector 字段,他就是使用 Label Selector 機制選擇出所有帶了 app=nginx 標簽的 Pod,都會被這個 Service 代理起來,這樣可以做到負載均衡Pod的訪問了。
StatefulSet 又是如何使用這個 DNS 記錄來維持 Pod 的拓撲狀態(tài)的呢?
示例編寫一個 StatefulSet 的 YAML 文件,如下所示:
apiVersion: apps/v1
kind: StatefulSet
metadata:name: web
spec:serviceName: "nginx" replicas: 2 selector:matchLabels:app: nginx template:metadata:labels:app: nginxspec:containers:- name :nginximage: nginx:1.9.1ports:- containerPort: 80name: web
該 YAML 文件和平時我們寫的 Deployment 都差不多,唯一區(qū)別就是多一個 ServiceName=nginx 字段。
這個字段的作用,告訴 StatefulSet 控制器,在執(zhí)行控制循環(huán)(Control Loop)時,請使用 nginx 這個 Headless Service 來保證 Pod 的 “可解析身份”
創(chuàng)建完后可以快速實時查看stateful創(chuàng)建的狀態(tài):kubectl get pods -w -l app=nginx
試用 nslookup 命令,解析一下 Pod 對應(yīng)的 Headless Service:
nslookup web-0.nginx
總結(jié):
StatefulSet 控制器作用:使用Pod模版創(chuàng)建 Pod時對他們進行編號,并且按照順序逐一完成創(chuàng)建工作。StatefulSet 控制循環(huán) 發(fā)現(xiàn) Pod的 “實際狀態(tài)” 與 “期望狀態(tài)” 不一致,則需要新建或刪除 Pod 進行 “調(diào)諧” 時會嚴格按照這些Pod編號的順序逐一完成這波操作。
深入理解StatefulSet(二):存儲狀態(tài)
在前面的 Stateful 講解了它是如何保證應(yīng)用實例的拓撲狀態(tài),在 Pod 刪除和創(chuàng)建的過程中保持穩(wěn)定。
今天講解 StatefulSet 對存儲狀態(tài)的管理機制。
在 Pod 中有個 Volume (卷),想要容器掛載到外面地方三存儲或本地機器,只需要在Pod里面加上spec.volumes
字段即可,如 Volume 類型 hostPath就掛在本地機器。
有一個問題,對于開發(fā)人員來說,如果你并不知道有哪些 Volume 類型可以用,要怎么辦呢?作為開發(fā)人員對持久存儲項目如Ceph、GlusterFS 都一竅不通,讓開發(fā)人員來寫已經(jīng)超出了知識儲備了
后來 kubernetes 項目引入了一組叫 “Persistent Volume Claim” 和 “Persistent Volume” 的 API 對象,降低用戶聲明和使用持久 Volume 的門檻。
假設(shè)我現(xiàn)在是開發(fā)人員,現(xiàn)在想要一個 Volume ,需要兩步即可。
第一步:申請。定義一個PVC聲明想要的 Volume的屬性:
apiVersion: v1
Kind: PersistentVolumeClaim
metadata:name: pv-claim
spec:accessModes:- ReadWirteOnceresources:requests:storage: 1Gi
開發(fā)人員定義了一個 PVC,描述只需要的屬性定義,如:storage: 1Gi 表示想要 Volume 大小至少為 1GB;accessModes: ReadWirteOnce 表示這個 Volume的掛載方式是可讀寫,且只能被掛載在一個節(jié)點而非多個節(jié)點共享。
第二步:在應(yīng)用的 Pod 中,聲明剛才你定義的 PVC 即可使用。
apiVersion: v1
kind: Pod
metadata:name: pv-pod
spec:containers:- name: pv-container image: nginxports:- containerPort: 80name: "http-server"volumeMounts:- mountPath: "/usr/share/nginx/html"name: pv-storeage
volumes:- name: pv-storagepersistentVolumeClaim:claimName: pv-claim
以上就是申請好一個 1GB 大小的 Volume了,不需要關(guān)系 Volume 的類型,然后創(chuàng)建這個 PVC 對象,Kubernetes 就會自動為它綁定一個符合條件的 Volume。
可是,這些符合條件的 Volume 又是從哪里來的呢?這個需要運維人員去維護 PV 對象了。
Kubernetes 中 PVC 和 PV 的設(shè)計,實際上類似于“接口”和“實現(xiàn)”的思想。開發(fā)者 只要知道并會使用“接口”,即:PVC;而運維人員則負責給“接口”綁定具體的實現(xiàn),即: PV。
而 PVC、PV 的設(shè)計,也使得 StatefulSet 對存儲狀態(tài)的管理成為了可能?;仡?#xff1a;
apiVersion: apps/v1
kind: StatefulSet
metadata:name: web
spec:serviceName: "nginx" replicas: 2 selector:matchLabels:app: nginx template:metadata:labels:app: nginxspec:containers:- name :nginximage: nginx:1.9.1ports:- containerPort: 80name: webvolumeMounts:- name: wwwmountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:name: wwwspec:accessModel:- ReadWriteOnceresources:requests:storage: 1Gi
volumeClaimTemplates 字段,從名字就可以 看出來,它跟 Deployment 里 Pod 模板(PodTemplate)的作用類似。
也就是說,凡是被這 個 StatefulSet 管理的 Pod,都會聲明一個對應(yīng)的 PVC;而這個 PVC 的定義,就來自于 volumeClaimTemplates 這個模板字段。更重要的是,這個 PVC 的名字,會被分配一個與這個 Pod 完全一致的編號。
這個自動創(chuàng)建的 PVC,與 PV 綁定成功后,就會進入 Bound 狀態(tài),這就意味著這個 Pod 可以 掛載并使用這個 PV 了。
如果你使用 kubectl delete 命令刪除這兩個 Pod,這些 Volume 里的文件會不會丟失呢?
前面介紹過,在被刪除之后這兩個 Pod 會被按照編號順序被重啟創(chuàng)建出來。如果你在創(chuàng)建新的容器通過本地訪問去訪問,會發(fā)現(xiàn)請求依然會返回,說明原先與名叫web-0的Pod綁定PV,Pod被重新創(chuàng)建后,依然同新的名字web-0的Pod綁定了在一起。
這是怎么做到的呢?
分析:當你把一個 Pod,比如 web-0,刪除之后,這個 Pod 對應(yīng)的 PVC 和 PV,并不會被刪除,而這個 Volume 里已經(jīng)寫入的數(shù)據(jù),也依然會保存在遠程存儲服務(wù)里(比如,我們在這個 例子里用到的 Ceph 服務(wù)器)。
當刪除后,StatefulSet 控制器發(fā)現(xiàn),一個名叫 web-0 的 Pod 消失了。所以,控制器就會重新創(chuàng)建 一個新的、名字還是叫作 web-0 的 Pod 來,“糾正”這個不一致的情況。
需要注意的是,在這個新的 Pod 對象的定義里,它聲明使用的 PVC 的名字,還是叫作:wwwweb-0。這個 PVC 的定義,還是來自于 PVC 模板(volumeClaimTemplates),這是 StatefulSet 創(chuàng)建 Pod 的標準流程。
通過這種方式,Kubernetes 的 StatefulSet 就實現(xiàn)了對應(yīng)用存儲狀態(tài)的管理。
深入理解StatefulSet(三):有狀態(tài)應(yīng)用實踐
官網(wǎng):案例
部署一個 MySQL 集群,如何使用 StatefulSet 將它的集群搭建過程“容器化”
首先,用自然語言來描述一下我們想要部署的“有狀態(tài)應(yīng)用”。
- 是一個“主從復(fù)制”(Maser-Slave Replication)的 MySQL 集群;
- 有 1 個主節(jié)點(Master);
- 有多個從節(jié)點(Slave);
- 從節(jié)點需要能水平擴展;
- 所有的寫操作,只能在主節(jié)點上執(zhí)行;
- 讀操作可以在所有節(jié)點上執(zhí)行。
在常規(guī)環(huán)境里,部署這樣一個主從模式的 MySQL 集群的主要難點在于:如何讓從節(jié)點能夠擁有 主節(jié)點的數(shù)據(jù),即:如何配置主(Master)從(Slave)節(jié)點的復(fù)制與同步。
第一步:通過 XtraBackup 將 Master 節(jié)點的數(shù)據(jù)備份到指定目錄。
第二步:配置 Slave 節(jié)點。Slave 節(jié)點在第一次啟動前,需要先把 Master 節(jié)點的備份數(shù)據(jù),連 同備份信息文件,一起拷貝到自己的數(shù)據(jù)目錄(/var/lib/mysql)下。然后,我們執(zhí)行這樣一句 SQL:
第三步:啟動 Slave 節(jié)點。在這一步,我們需要執(zhí)行這樣一句 SQL:
第四步:在這個集群中添加更多的 Slave 節(jié)點。
將部署 MySQL 集群的流程遷移到 Kubernetes 項目上,需要 能夠“容器化”地解決下面的“三座大山”:
-
Master 節(jié)點和 Slave 節(jié)點需要有不同的配置文件(即:不同的 my.cnf)
-
- Master 節(jié)點和 Salve 節(jié)點需要能夠傳輸備份信息文件;
-
在 Slave 節(jié)點第一次啟動之前,需要執(zhí)行一些初始化 SQL 操作;
“第一座大山:Master 節(jié)點和 Slave 節(jié)點需要有不同的配置文件”,很容易處理:我們只需要給主從節(jié)點分別準備兩份不同的 MySQL 配置文件,然后根據(jù) Pod 的序號(Index)掛載進去即可。
配置文件信息保存在 ConfigMap 里供 Pod 使 用。它的定義如下所示:
apiVersion: v1
kind: ConfigMap
metadata:name: mysql labels:app: mysql
data:master.cnf: |[mysql]log-bin
slave.cnf: |[mysql]super-read-only
- master.cnf 開啟了 log-bin,即:使用二進制日志文件的方式進行主從復(fù)制,這是一個標準 的設(shè)置。
- slave.cnf 的開啟了 super-read-only,代表的是從節(jié)點會拒絕除了主節(jié)點的數(shù)據(jù)同步操作之 外的所有寫操作,即:它對用戶是只讀的。
接下來,我們需要創(chuàng)建兩個 Service 來供 StatefulSet 以及用戶使用。這兩個 Service 的定義如 下所示:
```yaml
# 為 StatefulSet 成員提供穩(wěn)定的 DNS 表項的無頭服務(wù)(Headless Service)
apiVersion: v1
kind: Service
metadata:name: mysqllabels:app: mysqlapp.kubernetes.io/name: mysql
spec:ports:- name: mysqlport: 3306clusterIP: None # Headless Service,作用為 Pod 分配 DNS 記錄來固定它的拓撲狀態(tài)selector:app: mysql
---
# 用于連接到任一 MySQL 實例執(zhí)行讀操作的客戶端服務(wù)
# 對于寫操作,你必須連接到主服務(wù)器:mysql-0.mysql
apiVersion: v1
kind: Service
metadata:name: mysql-readlabels:app: mysqlapp.kubernetes.io/name: mysqlreadonly: "true"
spec:ports:- name: mysqlport: 3306selector:app: mysql
兩個 Service 都代理了所有攜帶 app=mysql 標簽的 Pod,也就是所有的 MySQL Pod。端口映射都是用 Service 的 3306 端口對應(yīng) Pod 的 3306 端口。
第二座大山:Master 節(jié)點和 Salve 節(jié)點需要能夠傳輸備份文件”的 問題。