一、數(shù)據(jù)卷類型
為什么需要數(shù)據(jù)卷?
- 容器中的文件在磁盤上是臨時存放的,這給容器中運(yùn)行比較重要的應(yīng)用程序帶來一些問題。
- 當(dāng)容器升級或者崩潰時,kubelet會重建容器,容器內(nèi)文件會丟失。
- 一個Pod中運(yùn)行多個容器時,需要共享文件。
- 而K8s 數(shù)據(jù)卷就可以解決這兩個問題。
Volume概念:
- Volume是與Pod綁定的(獨(dú)立于容器)與Pod具有相同生命周期的資源對象。
- 可以將Volume的內(nèi)容理解為目錄或文件,容器若需使用某個Volume,則僅需設(shè)置volumeMounts將一個或多個Volume掛載為容器中的目錄或文件,即可訪問Volume中的數(shù)據(jù)。
常用的數(shù)據(jù)卷類型:
- 節(jié)點(diǎn)本地(hostPath,emptyDir)
- 網(wǎng)絡(luò)(NFS,Ceph,GlusterFS)
- 公有云(AWS EBS)
- K8S資源(configmap,secret)
概念圖:
1.1 臨時數(shù)據(jù)卷(節(jié)點(diǎn)掛載)
概念:
- emptyDir卷是一個臨時存儲卷,與Pod生命周期綁定一起,如果Pod刪除了卷也會被刪除。
應(yīng)用場景:
- Pod中容器之間數(shù)據(jù)共享,是從Pod層面上提供的技術(shù)方案。
- 當(dāng)一個Pod內(nèi)有多個容器,且都分布在同一個節(jié)點(diǎn)上時,則數(shù)據(jù)共享;若pod內(nèi)的多個容器不在同一個節(jié)點(diǎn)上時,數(shù)據(jù)不共享。
特點(diǎn):
- kubelet會在Node的工作目錄下為Pod創(chuàng)建EmptyDir目錄。
- 可以將該節(jié)點(diǎn)上的某pod工作目錄EmptyDir下的數(shù)據(jù)掛載到該pod容器里,從而實(shí)現(xiàn)本地?cái)?shù)據(jù)共享。
- 只有在pod所在的節(jié)點(diǎn)上才能看到本地?cái)?shù)據(jù)。
- Pod刪除后,本地?cái)?shù)據(jù)也會被刪除。
- 此種模式?jīng)]有參數(shù)應(yīng)用,其他模式都有參數(shù)應(yīng)用。
缺點(diǎn):
- 不能持久化。當(dāng)node1節(jié)點(diǎn)上的Pod刪除后,會觸發(fā)健康檢查重新拉起容器,此時新容器在node2節(jié)點(diǎn),node2節(jié)點(diǎn)上看不到之前Node1節(jié)點(diǎn)上容器數(shù)據(jù),因?yàn)楸粍h除了。
參考地址:
- K8S官網(wǎng)地址
![]()
1.編輯yaml文件,創(chuàng)建pod容器。
[root@k8s-master bck]# cat my-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod ##容器名稱
spec:
containers:
- name: write
image: centos
command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
volumeMounts: ##定義引用數(shù)據(jù)卷
- name: data ##引用哪個數(shù)據(jù)卷,通過數(shù)據(jù)卷名稱來引用。
mountPath: /data ##將本地?cái)?shù)據(jù)卷掛載到容器里哪個路徑下。
- name: read
image: centos
command: ["bash","-c","tail -f /data/hello"]
volumeMounts:
- name: data
mountPath: /data
volumes: ##定義數(shù)據(jù)卷
- name: data ##數(shù)據(jù)卷名稱
emptyDir: {} ##數(shù)據(jù)卷類型
[root@k8s-master bck]# kubectl apply -f my-pod.yaml
2.進(jìn)入容器驗(yàn)證數(shù)據(jù)是否共享。
3.查看該pod容器在哪個節(jié)點(diǎn)上,進(jìn)入該節(jié)點(diǎn)查找本地?cái)?shù)據(jù)。
[root@k8s-node1 ~]# cd /var/lib/kubelet/pods/cdacb40e-3e2f-4c57-97bc-1fc81c446685/volumes/kubernetes.io~empty-dir
4.刪除pod,數(shù)據(jù)目錄也會被刪除。
1.2 節(jié)點(diǎn)數(shù)據(jù)卷(節(jié)點(diǎn)掛載)
概念:
- hostPath卷:掛載Node文件系統(tǒng)(Pod所在節(jié)點(diǎn))上文件或者目錄到Pod中的容器。
- 和 emptyDir數(shù)據(jù)卷一樣,只能在pod容器所在的node節(jié)點(diǎn)上查看到掛載目錄文件數(shù)據(jù),但區(qū)別是hostPath數(shù)據(jù)卷掛載不會因?yàn)閯h除pod而導(dǎo)致宿主機(jī)上的掛載目錄文件消失。
缺點(diǎn):
- 不能持久化。當(dāng)node1節(jié)點(diǎn)上的Pod刪除后,會觸發(fā)健康檢查重新拉起容器,此時新容器在node2節(jié)點(diǎn),node2節(jié)點(diǎn)上看不到之前Node1節(jié)點(diǎn)上容器數(shù)據(jù),因?yàn)楸粍h除了。
應(yīng)用場景:
- 容器應(yīng)用的關(guān)鍵數(shù)據(jù)需要被持久化到宿主機(jī)上。
- 需要使用Docker中的某些內(nèi)部數(shù)據(jù),可以將主機(jī)的/var/lib/docker目錄掛載到容器內(nèi)。
- 監(jiān)控系統(tǒng),例如cAdvisor需要采集宿主機(jī)/sys目錄下的內(nèi)容。
- Pod的啟動依賴于宿主機(jī)上的某個目錄或文件就緒的場景。
type字段的取值類型:
- htstPath數(shù)據(jù)卷有個可選字段type。
- FileOrCreate 模式不會負(fù)責(zé)創(chuàng)建文件的父目錄。 如果欲掛載的文件的父目錄不存在,Pod 啟動會失敗。 為了確保這種模式能夠工作,可以嘗試把文件和它對應(yīng)的目錄分開掛載
![]()
注意事項(xiàng):
- HostPath 卷存在許多安全風(fēng)險(xiǎn),最佳做法是盡可能避免使用 HostPath。 當(dāng)必須使用 HostPath 卷時,它的范圍應(yīng)僅限于所需的文件或目錄,并以只讀方式掛載。
- 如果通過 AdmissionPolicy 限制 HostPath 對特定目錄的訪問,則必須要求 volumeMounts 使用 readOnly 掛載以使策略生效。
1.編輯yaml文件,將宿主機(jī)上的/tmp目錄掛載到test容器里的/data目錄下,數(shù)據(jù)卷為data。
[root@k8s-master bck]# cat hostPath.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod2
spec:
containers:
- name: test
image: centos
command: ["bash","-c","for i in {1..1000};do echo $i >> /data/hello;sleep 1;done"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
hostPath:
path: /tmp
type: Directory
2.導(dǎo)入yaml,進(jìn)入容器查看/data目錄已經(jīng)把節(jié)點(diǎn)機(jī)器上的/tmp目錄映射進(jìn)來,我這里的pod2部署在node1節(jié)點(diǎn)上的,就去node1節(jié)點(diǎn)上看,其他節(jié)點(diǎn)不共享數(shù)據(jù)看不到。
3. 修改yaml,同時掛載2個目錄,根據(jù)數(shù)據(jù)卷的名稱識別一一掛載。
[root@k8s-master bck]# cat hostPath.yaml
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
containers:
- name: web
image: centos
command: ["bash","-c","for i in {1..1000};do echo $i >> /data/hello;sleep 1;done"]
volumeMounts:
- name: data
mountPath: /data
- name: qingjun
mountPath: /opt
volumes:
- name: data
hostPath:
path: /tmp
type: Directory
- name: qingjun
hostPath:
path: /
type: Directory
4.進(jìn)入Pod所在節(jié)點(diǎn),進(jìn)入容器,查看。
1.3 網(wǎng)絡(luò)數(shù)據(jù)卷NFS
概念:
- NFS是一個主流的文件共享服務(wù)器,NFS卷提供對NFS掛載支持,可以自動將NFS共享路徑掛載到Pod中。
注意事項(xiàng):
- 每個Node上都要安裝nfs-utils包。
概念圖:
1.選擇一臺服務(wù)器作為NFS服務(wù)器。我這里選擇的是node2。
1.安裝nfs服務(wù)。
[root@k8s-node2 ~]# yum -y install nfs-utils
2.創(chuàng)建共享目錄,名字自取,并編輯共享規(guī)則:只能是192.168.130.0網(wǎng)段的機(jī)器上的root用戶訪問,具備讀寫權(quán)限。
[root@k8s-node2 ~]# mkdir -p /nfs/k8s
[root@k8s-node2 ~]# cat /etc/exports
/nfs/k8s 192.168.130.0/24(rw,no_root_squash)
3.啟動服務(wù),并設(shè)置開機(jī)自啟。
[root@k8s-node2 ~]# systemctl start nfs
[root@k8s-node2 ~]# systemctl enable nfs
2.在其他所有節(jié)點(diǎn)上安裝nfs客戶端,不然無法掛載。
[root@k8s-master bck]# yum -y install nfs-utils
[root@k8s-node1 ~]# yum -y install nfs-utils
#掛載。在其他工作節(jié)點(diǎn)上掛載,將192.168.130.147上的/nfs/k8s目錄掛載到本地的/mnt/目錄下。
[root@k8s-node1 ~]# mount -t nfs 192.168.130.147:/nfs/k8s /mnt/
#取消掛載。
[root@k8s-node1 ~]# umount /mnt/
3.此時在node1節(jié)點(diǎn)上的/mnt/下操作,就相當(dāng)于在NFS服務(wù)器上的/nfs/k8s目錄下操作。
4.查看容器內(nèi)的掛載情況。
1.3.1 效果測試
1.編輯yaml文件,創(chuàng)建pod容器。
[root@k8s-master bck]# cat qingjun.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: baimu
name: baimu
spec:
replicas: 3
selector:
matchLabels:
app: baimu
template:
metadata:
labels:
app: baimu
spec:
containers:
- image: nginx
name: nginx
volumeMounts: ##定義掛載規(guī)則。
- name: mq ##指定掛載哪個數(shù)據(jù)卷。
mountPath: /usr/share/nginx/html ##指定將數(shù)據(jù)掛載到容器里的哪個目錄下。
volumes: ##定義掛載卷。
- name: mq ##掛載卷名稱。
nfs:
server: 192.168.130.147 ##指定nfs服務(wù)器地址,網(wǎng)絡(luò)能通。
path: /nfs/k8s ##指定nfs服務(wù)器上的共享目錄。
2.數(shù)據(jù)共享測試。
- 創(chuàng)建一組pod,內(nèi)有3個容器,查看進(jìn)入容器驗(yàn)證。
- 先進(jìn)入第一個容器的掛載目錄,查看已經(jīng)將nfs服務(wù)器上的/nfs/k8s目錄下的內(nèi)容掛載進(jìn)來。
- 創(chuàng)建888目錄,nfs服務(wù)器上查看888目錄被創(chuàng)建。
- 退出第一個容器,在nfs服務(wù)器共享目錄下創(chuàng)建22222目錄,再進(jìn)入第二個容器查看22222目錄被同步創(chuàng)建。
3.重建pod,新pod數(shù)據(jù)共享測試。
- 刪除podl里的第三個容器,等待新容器被創(chuàng)建運(yùn)行。
- 進(jìn)入新容器掛載目錄,查看該目錄下也共享nfs服務(wù)器上的共享目錄。
4.擴(kuò)容新pod數(shù)據(jù)共享測試。
- 擴(kuò)容副本到5個。
- 進(jìn)入新容器的掛載目錄,查看該目錄下也共享nfs服務(wù)器上的共享目錄。
1.4 持久數(shù)據(jù)卷(PVC/PV)
為什么會有PVC、PV?
- 提高安全性。上文我們使用nfs掛載出來的信息都是記錄在yaml文件中,安全性低。
- 職責(zé)分離。當(dāng)后端需要用到存儲時,作為非專業(yè)人士來說,存儲這塊的工作量是需要專門的運(yùn)維大佬來做的,而后端只需要簡單的提交你程序所需要的存儲大小即可,這樣一來就可以職責(zé)分離。
概念:
- PersistentVolume(PV):由管理員創(chuàng)建和配置,將存儲定義為一種容器應(yīng)用可以使用的資源,使得存儲作為集群中的資源管理。
- PersistentVolumeClaim(PVC):用戶來操作,是對存儲資源的一個申請,讓用戶不需要關(guān)心具體的Volume實(shí)現(xiàn)細(xì)節(jié)。
概念圖:
- 管理員需要提前定義pv,是手動的,也能自動創(chuàng)建需要依賴過StorageClass資源,后面講。
- 用戶在創(chuàng)建pod時,需要在yaml里定義pvc,內(nèi)容包括pvc名稱、申請資源大小、訪問模式。
- K8s通過PVC查找匹配到合適的PV,并掛載到Pod容器里。
![]()
1.用戶定義pod和pvc。
[root@k8s-master bck]# cat web1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web1
name: web1
spec:
replicas: 3
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: mq
mountPath: /usr/share/nginx/html
volumes:
- name: mq
persistentVolumeClaim:
claimName: qingjun ##這里的名稱需要與PVC名稱一致。
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: qingjun ##PVC名稱
spec:
accessModes:
- ReadWriteMany ##訪問模式,ReadWriteOnce、ReadOnlyMany或ReadWriteMany。
resources:
requests:
storage: 5Gi ##程序要申請的存儲資源。
2.導(dǎo)入yaml,查看pod和pvc都處于等待狀態(tài),是因?yàn)榇藭r還沒有關(guān)聯(lián)到pv。
3.管理員定義創(chuàng)建pv,導(dǎo)入yaml,pvc和Pod狀態(tài)改變。
[root@k8s-master bck]# cat pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: text ##PV名稱,自定義。
spec:
capacity:
storage: 5Gi ##容量。
accessModes:
- ReadWriteMany
nfs:
path: /nfs/k8s ##定義nfs掛載卷共享目錄。
server: 192.168.130.147 ##指定nfs服務(wù)器地址。
4.進(jìn)入Pod容器驗(yàn)證數(shù)據(jù)共享。Pod滾動升級、擴(kuò)容也都會共享數(shù)據(jù),測試方法同上文的nfs測試流程。
1.4.1 效果測試
1.先在nfs服務(wù)器上創(chuàng)建多個目錄,作為多個pv掛載目錄。
[root@k8s-node2 k8s]# pwd
/nfs/k8s
[root@k8s-node2 k8s]# mkdir pv0001
[root@k8s-node2 k8s]# mkdir pv0002
[root@k8s-node2 k8s]# mkdir pv0003
2.創(chuàng)建3個pv,分別為:
- pv0001,內(nèi)存5G,掛載nfs服務(wù)器為192.168.130.147,掛載目錄為/nfs/k8s/pv0001。
- pv0002,內(nèi)存25G,掛載nfs服務(wù)器為192.168.130.147,掛載目錄為/nfs/k8s/pv0002。
- pv0003,內(nèi)存50G,掛載nfs服務(wù)器為192.168.130.147,掛載目錄為/nfs/k8s/pv0003。
[root@k8s-master bck]# cat pv-all.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0001
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
nfs:
path: /nfs/k8s/pv0001
server: 192.168.130.147
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0002
spec:
capacity:
storage: 25Gi
accessModes:
- ReadWriteMany
nfs:
path: /nfs/k8s/pv0002
server: 192.168.130.147
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
nfs:
path: /nfs/k8s/pv0003
server: 192.168.130.147
[root@k8s-master bck]# kubectl apply -f pv-all.yaml
3.創(chuàng)建第一個pvc,名稱為web1-pvc,申請資源10G。此時pv和內(nèi)存為25G的pv0002綁定在一起。
[root@k8s-master bck]# cat web1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web1
name: web1
spec:
replicas: 3
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: mq
mountPath: /usr/share/nginx/html
volumes:
- name: mq
persistentVolumeClaim:
claimName: web1-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: web1-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
4.創(chuàng)建第二個pvc,名稱為web2-pvc,申請資源25G。此時pv和內(nèi)存為50G的pv0003綁定在一起。
[root@k8s-master bck]# cat web2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web2
name: web2
spec:
replicas: 3
selector:
matchLabels:
app: web2
template:
metadata:
labels:
app: web2
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: mq
mountPath: /usr/share/nginx/html
volumes:
- name: mq
persistentVolumeClaim:
claimName: web2-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: web2-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 25Gi
[root@k8s-master bck]# kubectl apply -f web2.yaml
5.創(chuàng)建第三個pvc,名稱為web3-pvc,申請資源6G。此時pv沒有和剩余的pv0001綁定。為什么呢?
[root@k8s-master bck]# cat web3.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web3
name: web3
spec:
replicas: 3
selector:
matchLabels:
app: web3
template:
metadata:
labels:
app: web3
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: mq
mountPath: /usr/share/nginx/html
volumes:
- name: mq
persistentVolumeClaim:
claimName: web3-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: web3-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 6Gi
1.4.2 測試結(jié)論
pvc與pv怎么匹配的?
- 主要根據(jù)存儲容量和訪問模式。我們定義pvc、pv的yaml文件里,都有這兩個字段,并不是說創(chuàng)建了3個pv,再創(chuàng)建的3個pvc就能一一對上,還要根據(jù)第二點(diǎn),存儲容量。
存儲容量怎么匹配的 ?
- 向上就近容量匹配。比如上文的web1-pvc,它的申請容量為10G,那再已有的三個pvc里面,容量分別為5G、25G、50G,就去匹配向上的、匹配就近的25G;當(dāng)web2-pvc來匹配時,它的申請容量為25G,再剩下的兩個pvc里面,就去匹配向上就近的50G;剩下的web3-pvc匹配時,它的申請容量為6G,再僅剩的一個pvc5G,是滿足不了“向上就近原則”,所以就沒匹配中。
pv與pvc的關(guān)系:
- 一對一
容量能不能限制?
- 目前容量主要用作pvc與pv匹配的,具體的限制取決于后端存儲。
二、PV、PVC生命周期
- AccessModes(訪問模式):AccessModes 是用來對 PV 進(jìn)行訪問模式的設(shè)置,用于描述用戶應(yīng)用對存儲資源的訪問權(quán)限,訪問權(quán)限包括下面幾種方式:
- ReadWriteOnce(RWO):讀寫權(quán)限,但是只能被單個節(jié)點(diǎn)掛載。常用于塊設(shè)備存儲(云硬盤)。
- ReadOnlyMany(ROX):只讀權(quán)限,可以被多個節(jié)點(diǎn)掛載。常用于數(shù)據(jù)共享(文件系統(tǒng)存儲)。
- ReadWriteMany(RWX):讀寫權(quán)限,可以被多個節(jié)點(diǎn)掛載
- RECLAIM POLICY(回收策略):指PVC刪除之后,PV是去是留的一種策略。
目前 PV 支持的策略有三種:
- Retain(保留): 保留數(shù)據(jù),需要管理員手工清理數(shù)據(jù)。
- Recycle(回收):清除 PV 中的數(shù)據(jù),效果相當(dāng)于執(zhí)行 rm -rf /ifs/kuberneres/*
- Delete(刪除):與 PV 相連的后端存儲同時刪除
- STATUS(狀態(tài)):
一個 PV 的生命周期中,可能會處于4中不同的階段:
- Available(可用):表示可用狀態(tài),還未被任何 PVC 綁定。
- Bound(已綁定):表示 PV 已經(jīng)被 PVC 綁定。
- Released(已釋放):PVC 被刪除,但是資源還未被集群重新聲明。
- Failed(失敗): 表示該 PV 的自動回收失敗。
2.1 各階段工作原理
生命周期階段:
- 我們可以將PV看作可用的存儲資源,PVC則是對存儲資源的需求。
- PV和PVC的生命周期包括資源供應(yīng)(Provisioning)、資源綁定(Binding)、資源使用(Using)、資源回收(Reclaiming)幾個階段。
![]()
2.1.1 資源供應(yīng)
- K8s支持兩種資源供應(yīng)模式:靜態(tài)模式(Static)和動態(tài)模式(Dynamic),資源供應(yīng)的結(jié)果就是將適合的PV與PVC成功綁定。
- 靜態(tài)模式:運(yùn)維預(yù)先創(chuàng)建許多PV,在PV的定義中能夠體現(xiàn)存儲資源的特性。
- 動態(tài)模式:運(yùn)維無須預(yù)先創(chuàng)建PV,而是通過StorageClass的設(shè)置對后端存儲資源進(jìn)行描述,標(biāo)記存儲的類型和特性。用戶通過創(chuàng)建PVC對存儲類型進(jìn)行申請,系統(tǒng)將自動完成PV的創(chuàng)建及與PVC的綁定。如果PVC聲明的Class為空"",則說明PVC不使用動態(tài)模式。另外,Kubernetes支持設(shè)置集群范圍內(nèi)默認(rèn)的StorageClass設(shè)置,通過kube-apiserver開啟準(zhǔn)入控制器DefaultStorageClass,可以為用戶創(chuàng)建的PVC設(shè)置一個默認(rèn)的存儲類StorageClass。
靜態(tài)模式工作原理圖:
動態(tài)模式原理圖:
2.1.2 資源綁定
- 當(dāng)用戶定義PVC后,系統(tǒng)將根據(jù)PVC對存儲資源的請求(存儲空間和訪問模式)在提前創(chuàng)建好的PV中選擇一個滿足要求的PV,并與PVC綁定。
- 若系統(tǒng)中沒有滿足要求的PV,PVC則會無限期處于Pending狀態(tài),直到系統(tǒng)管理員創(chuàng)建了一個符合其要求的PV。
- PV只能一個PVC綁定,綁定關(guān)系是一對一的,不會存在一對多的情況。
- 若PVC申請的存儲空間比PV擁有的空間少,則整個PV的空間都能為PVC所用,可能會造成資源的浪費(fèi)。
- 若資源供應(yīng)使用的是動態(tài)模式,則系統(tǒng)在為PVC找到合適的StorageClass后,將自動創(chuàng)建一個PV并完成與PVC的綁定。
2.1.3 .資源使用
- 若Pod需要使用存儲資源,則需要在yaml里定義Volume字段引用PVC類型的存儲卷,將PVC掛載到容器內(nèi)的某個路徑下進(jìn)行使用。
- 同一個PVC還可以被多個Pod同時掛載使用,在這種情況下,應(yīng)用程序需要處理好多個進(jìn)程訪問同一個存儲的問題。
使用中的存儲對象保護(hù)機(jī)制:
- PV、PVC存儲資源可以單獨(dú)刪除。當(dāng)刪除時,系統(tǒng)會檢測存儲資源當(dāng)前是否正在被使用,若仍被使用,則對相關(guān)資源對象的刪除操作將被推遲,直到?jīng)]被使用才會執(zhí)行刪除操作,這樣可以確保資源仍被使用的情況下不會被直接刪除而導(dǎo)致數(shù)據(jù)丟失。
- 若刪除的PVC有被使用時,則會等到使用它的Pod被刪除之后再執(zhí)行,此時PVC狀態(tài)為Terminating。
- 若刪除的PV有被使用時,則會等到綁定它的PVC被刪除之后再執(zhí)行,此時PV狀態(tài)為Terminating。
2.1.4 資源回收
- 回收策略,指PVC刪除之后,PV是去是留的一種策略。目前 PV 支持的策略有三種:
- Retain(保留): 保留數(shù)據(jù),需要管理員手工清理數(shù)據(jù)。
- Recycle(回收):清除 PV 中的數(shù)據(jù),效果相當(dāng)于執(zhí)行 rm -rf /ifs/kuberneres/*
- Delete(刪除):與 PV 相連的后端存儲同時刪除
2.1.5 PVC資源擴(kuò)容
- PVC在首次創(chuàng)建成功之后,還可以在使用過程中進(jìn)行存儲空間的擴(kuò)容。
- 支持PVC擴(kuò)容的存儲類型有:AWSElasticBlockStore、AzureFile、AzureDisk、Cinder、FlexVolume、GCEPersistentDisk、Glusterfs、Portworx Volumes、RBD和CSI等。
擴(kuò)容步驟:
- 先在PVC對應(yīng)的StorageClass中設(shè)置參數(shù)“allowVolumeExpansion=true”。
- 修改pvc.yaml,將resources.requests.storage設(shè)置為一個更大的值。
擴(kuò)容失敗恢復(fù)步驟:
- 設(shè)置與PVC綁定的PV資源的回收策略為“Retain”。
- 刪除PVC,此時PV的數(shù)據(jù)仍然存在。
- 刪除PV中的claimRef定義,這樣新的PVC可以與之綁定,結(jié)果將使得PV的狀態(tài)為“Available”。
- 新建一個PVC,設(shè)置比PV空間小的存儲空間申請,同時設(shè)置volumeName字段為PV的名稱,結(jié)果將使得PVC與PV完成綁定。
- 恢復(fù)PVC的原回收策略
2.2 測試PV回收策略
2.2.1 Retain保留策略
- Retain策略表示在刪除PVC之后,與之綁定的PV不會被刪除,僅被標(biāo)記為已釋放(released)。PV中的數(shù)據(jù)仍然存在,在清空之前不能被新的PVC使用,需要管理員手工清理之后才能繼續(xù)使用。
- 清理步驟:
- 刪除PV資源對象,此時與該P(yáng)V關(guān)聯(lián)的某些外部存儲提供商(例如AWSElasticBlockStore、GCEPersistentDisk、AzureDisk、Cinder等)的后端存儲資產(chǎn)(asset)中的數(shù)據(jù)仍然存在。
- 手工清理PV后端存儲資產(chǎn)(asset)中的數(shù)據(jù)。
- 手工刪除后端存儲資產(chǎn)。如果希望重用該存儲資產(chǎn),則可以創(chuàng)建一個新的PV與之關(guān)聯(lián)。
1.如圖。已有一個pv和pvc關(guān)聯(lián)綁定,進(jìn)入容器查看驗(yàn)證成功。
2.刪除pvc,查看pv狀態(tài)變?yōu)镽eleased已釋放狀態(tài)。此時的pv不可用,需要把pv里面的數(shù)據(jù)轉(zhuǎn)移到其他機(jī)器做備份。
3.也就是nfs機(jī)器上的共享目錄下的數(shù)據(jù)。
2.2.2 Recycle回收策略
- Recycle和Delete策略都是和存儲類配合使用才能測出效果。
- 回收策略 Recycle 已被廢棄,取而代之的建議方案是使用動態(tài)制備,單獨(dú)創(chuàng)建一個pod來進(jìn)行刪除操作。
- 目前只有HostPort和NFS類型的Volume支持Recycle策略,其實(shí)現(xiàn)機(jī)制為運(yùn)行rm-rf/thevolume/*命令,刪除Volume目錄下的全部文件,使得PV可以被新的PVC使用。
- 刪除模板:
![]()
1.創(chuàng)建pv時,添加策略參數(shù)。
[root@k8s-master bck]# cat pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: text1 ##PV名稱,自定義。
spec:
persistentVolumeReclaimPolicy: Recycle ##Recycle回收策略。
capacity:
storage: 10Gi ##容量。
accessModes:
- ReadWriteOnce
nfs:
path: /nfs/k8s
server: 192.168.130.147
2.導(dǎo)入pv.yaml后,再創(chuàng)建pvc與之綁定。
3.刪除pvc,pv的數(shù)據(jù)被刪除,也就是nfs服務(wù)器的共享目錄下的數(shù)據(jù)被刪除。
4.這里沒有被刪除是因?yàn)閯h除操作要拉取國外的一個鏡像生成一個新容器,這個容器去刪除pv里的數(shù)據(jù),所以這里就拉取失敗了。若要使用該策略,需要提前拉取這個鏡像。
2.3 StorageClass動態(tài)供給
什么是靜態(tài)供給?
- 我們前面演示時,都是手動寫pv.yaml文件提前創(chuàng)建好存儲大小不同的pv,當(dāng)有pvc需求時就會根據(jù)需求大小去匹配對應(yīng)的pvc從而綁定。關(guān)鍵詞是手動創(chuàng)建,所以維護(hù)成本高。
什么是動態(tài)供給?
- 為了解決靜態(tài)供給的缺點(diǎn),K8s開始支持PV動態(tài)供給,使用StorageClass對象實(shí)現(xiàn)。
- 當(dāng)有pvc需求時,就可以自動創(chuàng)建pv與之綁定。關(guān)鍵詞是自動生成。
靜態(tài)供給概念圖:
動態(tài)供給概念圖:
實(shí)現(xiàn)PV動態(tài)補(bǔ)給流程步驟:
- 部署動態(tài)供給程序,是以容器方式部署的,調(diào)取api server 獲取指定自己的pvc。
- 創(chuàng)建pod時,在pod.yaml里定義pvc資源,并在pvc資源下面指定存儲類。
- 調(diào)取后端nfs服務(wù)器創(chuàng)建共享目錄,再調(diào)取api server創(chuàng)建pv,從而實(shí)現(xiàn)自動創(chuàng)建pv動作。
- 流程圖:
![]()
2.3.1 部署存儲插件
- 支持動態(tài)補(bǔ)給的存儲插件
![]()
- 社區(qū)獲取各存儲插件yanl文件
![]()
- nfs獲取地址路徑
- 文件地址,下載這三個yaml文件上傳到服務(wù)器。
![]()
1.將這個三個文件上傳至服務(wù)器,修改其中兩個yaml文件參數(shù)。
[root@k8s-master storageclass]# cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage ##自定義名稱。
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiveOnDelete: "false"
[root@k8s-master storageclass]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: lizhenliang/nfs-subdir-external-provisioner:v4.0.1
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner ##與class.yaml文件里的名稱保持一致。
- name: NFS_SERVER
value: 192.168.130.147 ##修改nfs服務(wù)器地址
- name: NFS_PATH
value: /nfs/k8s ##修改nfs服務(wù)器共享目錄。
volumes:
- name: nfs-client-root
nfs:
server: 192.168.130.147 ##修改nfs服務(wù)器地址
path: /nfs/k8s ##修改nfs服務(wù)器共享目錄。
2.導(dǎo)入yaml文件,查看存儲類。
- kubectl apply -f rbac.yaml # 授權(quán)訪問apiserver
- kubectl apply -f deployment.yaml # 部署插件,需修改里面NFS服務(wù)器地址與共享目錄。
- kubectl apply -f class.yaml # 創(chuàng)建存儲類。
- kubectl get sc # 查看存儲類
2.3.2 使用插件
1.編輯yaml文件創(chuàng)建pvc,指定使用哪個存儲類,也就是我們上面創(chuàng)建的sc。
[root@k8s-master bck]# cat pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web1
name: web1
spec:
selector:
matchLabels:
app: web1
template:
metadata:
labels:
app: web1
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: mq
mountPath: /usr/share/nginx/html
volumes:
- name: mq
persistentVolumeClaim:
claimName: qingjun
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: qingjun
spec:
storageClassName: "managed-nfs-storage" ##添加此行,指定使用已創(chuàng)建的sc。
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
2.創(chuàng)建pvc后會自動創(chuàng)建一個pv,并且是綁定狀態(tài),帶有storage標(biāo)識,最后成功創(chuàng)建了deploy。
3.進(jìn)入pod檢查。會在共享目錄里隨機(jī)生成一個目錄,
/nfs/k8s/default-qingjun-pvc-d207b4d4-8966-43d0-b32c-6caf45ee54b8
default:代表命名空間。
qingjun:代表pvc名稱。
pvc-d207b4d4-8966-43d0-b32c-6caf45ee54b8:代表pv名稱。
4.此時刪除pvc,會發(fā)現(xiàn)pv及其數(shù)據(jù)也會被刪除,是因?yàn)槟J(rèn)的回收策略是“Delete”。
5.修改歸檔刪除策略。
[root@k8s-master storageclass]# cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiveOnDelete: "true" ##默認(rèn)為flase,代表直接刪除不備份。修改成true代表先備份再刪除。
[root@k8s-master storageclass]# kubectl delete -f class.yaml #刪除原來的。
[root@k8s-master storageclass]# kubectl apply -f class.yaml #再導(dǎo)入新的,更新。
三、StatefulSet
3.1 控制器介紹
StatefulSet控制器作用:
- StatefulSet控制器用于部署有狀態(tài)應(yīng)用,滿足一些有狀態(tài)應(yīng)用的需求。
控制器特點(diǎn):
- Pod有序的部署、擴(kuò)容、刪除和停止。
- Pod分配一個穩(wěn)定的且唯一的網(wǎng)絡(luò)標(biāo)識。
- Pod分配一個獨(dú)享的存儲。
無狀態(tài)與有狀態(tài):
- 無狀態(tài):Deployment控制器設(shè)計(jì)原則是,管理的所有Pod一模一樣,提供同一個服務(wù),也不考慮在哪臺Node運(yùn)行,可隨意擴(kuò)容和縮容。這種應(yīng)用稱為“無狀態(tài)”。例如Web服務(wù)集群,每個工作節(jié)點(diǎn)上都有一個nginx容器,它們之間不需要互相業(yè)務(wù)“交流”,具備這個特點(diǎn)的應(yīng)用就是“無狀態(tài)”。
- 有狀態(tài):像分布式應(yīng)用這種,需要部署多個實(shí)例,實(shí)例之間有依賴關(guān)系,例如主從關(guān)系、主備關(guān)系,這種應(yīng)用稱為“有狀態(tài)”,例如MySQL主從、Etcd集群。
無狀態(tài)應(yīng)用特點(diǎn):
- 每個pod一模一樣。
- 每個pod之間沒有連接關(guān)系。
- 使用共享存儲。
有狀態(tài)應(yīng)用特點(diǎn):
- 每個pod不對等,承擔(dān)的角色不同。
- pod之間有連接關(guān)系。
- 每個pod有獨(dú)立的存儲。
StatefulSet與Deployment區(qū)別:
- 前者有身份,后者沒有。
- 身份三要素:域名、主機(jī)名、存儲(PVC)
3.2 部署實(shí)踐
需要穩(wěn)定的網(wǎng)絡(luò)ID(域名):
- 使用Headless Service(相比普通Service只是將spec.clusterIP定義為None)來維護(hù)Pod網(wǎng)絡(luò)身份。
- 并且添加serviceName:“nginx”字段指定StatefulSet控制器要使用這個Headless Service。
- DNS解析名稱:< statefulsetName-index >.< service-name > .< namespace-name >.svc.cluster.local
需要穩(wěn)定的存儲:
- StatefulSet的存儲卷使用VolumeClaimTemplate創(chuàng)建,稱為卷申請模板,當(dāng)StatefulSet使用VolumeClaimTemplate創(chuàng)建一個PersistentVolume時,同樣也會為每個Pod分配并創(chuàng)建一個編號的PVC。
- 第一步,先創(chuàng)建正常的svc,名為web。
1.創(chuàng)建一個deployment和svc。
[root@k8s-master bck]# kubectl create deployment web --image=nginx
[root@k8s-master bck]# kubectl expose deployment web --port=80 --target-port=80
2.導(dǎo)出svc的yaml文件,可以看出這里的ClusterIP,這種情況下容器內(nèi)的通信都是以這個ClusterIP來進(jìn)行。
- 第二步,再創(chuàng)建statefulset,引用第二個狀態(tài)為None的svc。
3.創(chuàng)建statefulset。yaml中是先創(chuàng)建了第二個svc,狀態(tài)為None,再創(chuàng)建statefulset指定儲存類和這個None狀態(tài)的svc。
[root@k8s-master bck]# cat statefulset.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None ##添加此行,使其變成一種識別標(biāo)簽,供后面的pod使用。
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx" ##指定哪個svc的名稱。
replicas: 3
minReadySeconds: 10
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: ##statefulset獨(dú)有配置,deployment不支持此配置。是給每個pod分配各自的pv、pvc。
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "managed-nfs-storage" ##指定哪個存儲類。使用kubectl get sc查看。
resources:
requests:
storage: 1Gi
5.導(dǎo)入yaml,查看會依次創(chuàng)建三個Pod,因?yàn)閥aml里指定的就是3個副本。
[root@k8s-master bck]# kubectl apply -f statefulset.yaml
6.對比兩個svc。
7.創(chuàng)建測試容器bs。
[root@k8s-master bck]# kubectl run bs --image=busybox:1.28.4 -- sleep 240h
[root@k8s-master bck]# kubectl exec -it bs -- sh
8.查看nfs服務(wù)器共享目錄,進(jìn)入對應(yīng)目錄,創(chuàng)建一個index.html文件,再次就能訪問了。
3.3 集群部署流程
- 集群一般都是三個節(jié)點(diǎn),也就是需要提前寫三個yaml文件。
- 需要寫一些腳本。
- 通過配置文件中的節(jié)點(diǎn)名稱、IP、存儲目錄區(qū)分3個pod的角色,。
部署一個etcd集群思路:文章來源:http://www.zghlxwxcb.cn/news/detail-447642.html
- 需要有3個副本,每個pod里只能指定一個鏡像,所以需要保證啟動的3個副本容器,每一個都能按照自己的角色 (配置文件) 啟動。
- 根據(jù)當(dāng)前主機(jī)名可以判定用戶當(dāng)前啟動的是第幾個容器,就用哪個配置文件后動。比如etcd-0.conf、etcd-1.conf、etcd-2.conf。
文章來源地址http://www.zghlxwxcb.cn/news/detail-447642.html
3.3.1 etcd案例
- etcd集群yaml文件實(shí)例
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
k8s-app: infra-etcd-cluster
app: etcd
name: infra-etcd-cluster
namespace: default
spec:
replicas: 3
selector:
matchLabels:
k8s-app: infra-etcd-cluster
app: etcd
serviceName: infra-etcd-cluster
template:
metadata:
labels:
k8s-app: infra-etcd-cluster
app: etcd
name: infra-etcd-cluster
spec:
containers:
- image: lizhenliang/etcd:v3.3.8
imagePullPolicy: Always
command:
- /bin/sh
- -ec
- |
HOSTNAME=$(hostname)
echo "etcd api version is ${ETCDAPI_VERSION}"
# 生成連接etcd集群節(jié)點(diǎn)字符串
# 例如http://etcd-0.etcd.default:2379,http://etcd-1.etcd.default:2379,http://etcd-2.etcd.default:2379
eps() {
EPS=""
for i in $(seq 0 $((${INITIAL_CLUSTER_SIZE} - 1))); do
EPS="${EPS}${EPS:+,}http://${SET_NAME}-${i}.${SET_NAME}.${CLUSTER_NAMESPACE}:2379"
done
echo ${EPS}
}
# 獲取etcd節(jié)點(diǎn)成員hash值,例如740e031d5b17222d
member_hash() {
etcdctl member list | grep http://${HOSTNAME}.${SET_NAME}.${CLUSTER_NAMESPACE}:2380 | cut -d':' -f1 | cut -d'[' -f1
}
# 生成初始化集群節(jié)點(diǎn)連接字符串
# 例如etcd-0=http://etcd-0.etcd.default:2380,etcd-1=http://etcd-1.etcd.default:2380,etcd-2=http://etcd-1.etcd.default:2380
initial_peers() {
PEERS=""
for i in $(seq 0 $((${INITIAL_CLUSTER_SIZE} - 1))); do
PEERS="${PEERS}${PEERS:+,}${SET_NAME}-${i}=http://${SET_NAME}-${i}.${SET_NAME}.${CLUSTER_NAMESPACE}:2380"
done
echo ${PEERS}
}
# etcd-SET_ID
SET_ID=${HOSTNAME##*-}
# 向已有集群添加成員 (假設(shè)所有pod都初始化完成)
if [ "${SET_ID}" -ge ${INITIAL_CLUSTER_SIZE} ]; then
export ETCDCTL_ENDPOINTS=$(eps)
# 判斷成員是否添加
MEMBER_HASH=$(member_hash)
if [ -n "${MEMBER_HASH}" ]; then
# 成員hash存在,但由于某種原因失敗
# 如果datadir目錄沒創(chuàng)建,可以刪除該成員
# 檢索新的hash值
if [ "${ETCDAPI_VERSION}" -eq 3 ]; then
ETCDCTL_API=3 etcdctl --user=root:${ROOT_PASSWORD} member remove ${MEMBER_HASH}
else
etcdctl --username=root:${ROOT_PASSWORD} member remove ${MEMBER_HASH}
fi
fi
echo "添加成員"
rm -rf /var/run/etcd/*
# 確保etcd目錄存在
mkdir -p /var/run/etcd/
# 休眠60s,等待端點(diǎn)準(zhǔn)備好
echo "sleep 60s wait endpoint become ready,sleeping..."
sleep 60
if [ "${ETCDAPI_VERSION}" -eq 3 ]; then
ETCDCTL_API=3 etcdctl --user=root:${ROOT_PASSWORD} member add ${HOSTNAME} --peer-urls=http://${HOSTNAME}.${SET_NAME}.${CLUSTER_NAMESPACE}:2380 | grep "^ETCD_" > /var/run/etcd/new_member_envs
else
etcdctl --username=root:${ROOT_PASSWORD} member add ${HOSTNAME} http://${HOSTNAME}.${SET_NAME}.${CLUSTER_NAMESPACE}:2380 | grep "^ETCD_" > /var/run/etcd/new_member_envs
fi
if [ $? -ne 0 ]; then
echo "member add ${HOSTNAME} error."
rm -f /var/run/etcd/new_member_envs
exit 1
fi
cat /var/run/etcd/new_member_envs
source /var/run/etcd/new_member_envs
# 啟動etcd
exec etcd --name ${HOSTNAME} \
--initial-advertise-peer-urls http://${HOSTNAME}.${SET_NAME}.${CLUSTER_NAMESPACE}:2380 \
--listen-peer-urls http://0.0.0.0:2380 \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://${HOSTNAME}.${SET_NAME}.${CLUSTER_NAMESPACE}:2379 \
--data-dir /var/run/etcd/default.etcd \
--initial-cluster ${ETCD_INITIAL_CLUSTER} \
--initial-cluster-state ${ETCD_INITIAL_CLUSTER_STATE}
fi
# 檢查前面etcd節(jié)點(diǎn)是否啟動,啟動后再啟動本節(jié)點(diǎn)
for i in $(seq 0 $((${INITIAL_CLUSTER_SIZE} - 1))); do
while true; do
echo "Waiting for ${SET_NAME}-${i}.${SET_NAME}.${CLUSTER_NAMESPACE} to come up"
ping -W 1 -c 1 ${SET_NAME}-${i}.${SET_NAME}.${CLUSTER_NAMESPACE} > /dev/null && break
sleep 1s
done
done
echo "join member ${HOSTNAME}"
# 啟動etcd節(jié)點(diǎn)
exec etcd --name ${HOSTNAME} \
--initial-advertise-peer-urls http://${HOSTNAME}.${SET_NAME}.${CLUSTER_NAMESPACE}:2380 \
--listen-peer-urls http://0.0.0.0:2380 \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://${HOSTNAME}.${SET_NAME}.${CLUSTER_NAMESPACE}:2379 \
--initial-cluster-token etcd-cluster-1 \
--data-dir /var/run/etcd/default.etcd \
--initial-cluster $(initial_peers) \
--initial-cluster-state new
env:
- name: INITIAL_CLUSTER_SIZE # 初始集群節(jié)點(diǎn)數(shù)量
value: "3"
- name: CLUSTER_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: ETCDAPI_VERSION
value: "3"
- name: ROOT_PASSWORD
value: '@123#'
- name: SET_NAME
value: "infra-etcd-cluster"
- name: GOMAXPROCS
value: "4"
# 關(guān)閉pod,自動清理該節(jié)點(diǎn)信息
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -ec
- |
HOSTNAME=$(hostname)
member_hash() {
etcdctl member list | grep http://${HOSTNAME}.${SET_NAME}.${CLUSTER_NAMESPACE}:2380 | cut -d':' -f1 | cut -d'[' -f1
}
eps() {
EPS=""
for i in $(seq 0 $((${INITIAL_CLUSTER_SIZE} - 1))); do
EPS="${EPS}${EPS:+,}http://${SET_NAME}-${i}.${SET_NAME}.${CLUSTER_NAMESPACE}:2379"
done
echo ${EPS}
}
export ETCDCTL_ENDPOINTS=$(eps)
SET_ID=${HOSTNAME##*-}
# 從集群中移出etcd節(jié)點(diǎn)成員
if [ "${SET_ID}" -ge ${INITIAL_CLUSTER_SIZE} ]; then
echo "Removing ${HOSTNAME} from etcd cluster"
if [ "${ETCDAPI_VERSION}" -eq 3 ]; then
ETCDCTL_API=3 etcdctl --user=root:${ROOT_PASSWORD} member remove $(member_hash)
else
etcdctl --username=root:${ROOT_PASSWORD} member remove $(member_hash)
fi
if [ $? -eq 0 ]; then
# 刪除數(shù)據(jù)目錄
rm -rf /var/run/etcd/*
fi
fi
name: infra-etcd-cluster
ports:
- containerPort: 2380
name: peer
protocol: TCP
- containerPort: 2379
name: client
protocol: TCP
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: "0.3"
memory: 300Mi
volumeMounts:
- mountPath: /var/run/etcd
name: datadir
updateStrategy:
type: OnDelete
volumeClaimTemplates:
- metadata:
name: datadir
spec:
storageClassName: "managed-nfs-storage"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: infra-etcd-cluster
app: infra-etcd
name: infra-etcd-cluster
namespace: default
spec:
clusterIP: None
ports:
- name: infra-etcd-cluster-2379
port: 2379
protocol: TCP
targetPort: 2379
- name: infra-etcd-cluster-2380
port: 2380
protocol: TCP
targetPort: 2380
selector:
k8s-app: infra-etcd-cluster
app: etcd
type: ClusterIP
3.3.2 zookeeper示例
- zookeeper參考地址
apiVersion: v1
kind: Service
metadata:
name: zk-hs
labels:
app: zk
spec:
ports:
- port: 2888
name: server
- port: 3888
name: leader-election
clusterIP: None
selector:
app: zk
---
apiVersion: v1
kind: Service
metadata:
name: zk-cs
labels:
app: zk
spec:
ports:
- port: 2181
name: client
selector:
app: zk
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
selector:
matchLabels:
app: zk
maxUnavailable: 1
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: zk
spec:
selector:
matchLabels:
app: zk
serviceName: zk-hs
replicas: 3
updateStrategy:
type: RollingUpdate
podManagementPolicy: OrderedReady
template:
metadata:
labels:
app: zk
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: "app"
operator: In
values:
- zk
topologyKey: "kubernetes.io/hostname"
containers:
- name: kubernetes-zookeeper
imagePullPolicy: Always
image: "registry.k8s.io/kubernetes-zookeeper:1.0-3.4.10"
resources:
requests:
memory: "1Gi"
cpu: "0.5"
ports:
- containerPort: 2181
name: client
- containerPort: 2888
name: server
- containerPort: 3888
name: leader-election
command:
- sh
- -c
- "start-zookeeper \
--servers=3 \
--data_dir=/var/lib/zookeeper/data \
--data_log_dir=/var/lib/zookeeper/data/log \
--conf_dir=/opt/zookeeper/conf \
--client_port=2181 \
--election_port=3888 \
--server_port=2888 \
--tick_time=2000 \
--init_limit=10 \
--sync_limit=5 \
--heap=512M \
--max_client_cnxns=60 \
--snap_retain_count=3 \
--purge_interval=12 \
--max_session_timeout=40000 \
--min_session_timeout=4000 \
--log_level=INFO"
readinessProbe:
exec:
command:
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
livenessProbe:
exec:
command:
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
volumeMounts:
- name: datadir
mountPath: /var/lib/zookeeper
securityContext:
runAsUser: 1000
fsGroup: 1000
volumeClaimTemplates:
- metadata:
name: datadir
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
到了這里,關(guān)于K8s基礎(chǔ)10——數(shù)據(jù)卷、PV和PVC、StorageClass動態(tài)補(bǔ)給、StatefulSet控制器的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!