一、Volume
一般來(lái)說(shuō),容器一旦被刪除后,容器運(yùn)行時(shí)內(nèi)部產(chǎn)生的所有文件數(shù)據(jù)也會(huì)被清理掉,因此,Docker提供了 Volume 這種方式來(lái)將數(shù)據(jù)持久化存儲(chǔ)。
可以說(shuō),Volume 是Pod與外部存儲(chǔ)設(shè)備進(jìn)行數(shù)據(jù)傳遞的通道,也是Pod內(nèi)部容器間、Pod與Pod間、Pod與外部環(huán)境進(jìn)行數(shù)據(jù)共享的方式。
實(shí)際上,這個(gè) Volume 也只是宿主機(jī)上本地磁盤中的一個(gè)目錄,也就是說(shuō),volume方式是將容器里面的數(shù)據(jù)都保存到宿主機(jī)上。除此之外,還能保存到外部存儲(chǔ)上。
在k8s中,支持多種類型的Volume:本地存儲(chǔ)(emptyDir / hostPath)、外部存儲(chǔ)(如NFS)。
1、emptyDir?
若pod使用了emptyDir類型的volume,則在創(chuàng)建pod時(shí),emptyDir volume隨著pod也會(huì)一同被創(chuàng)建出來(lái)。emptyDir volume 會(huì)在pod所在的node節(jié)點(diǎn)上生成一個(gè)空目錄,而這個(gè)空目錄的默認(rèn)路徑是在/var/lib/kubelet/pods/下。
emptyDir 類型相當(dāng)于執(zhí)行【docker run -v /CONTAINER/DIR】。
emptyDir Volume與Pod生命周期一致,只要Pod一直運(yùn)行,該Volume就一直存在,而當(dāng)Pod被刪除時(shí),該Volume也同時(shí)會(huì)刪除,即Node上對(duì)應(yīng)目錄也會(huì)被刪掉。
一個(gè)Volume可被Pod中的所有容器共享,且可被掛載到容器的指定路徑下。
示例:
說(shuō)明:創(chuàng)建一個(gè)Pod,Pod有兩個(gè)容器,它們共享一個(gè)Volume,busybox容器負(fù)責(zé)往 Volume 中寫數(shù)據(jù),myapp容器則是從 Volume 讀取數(shù)據(jù)
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
spec:
volumes: # 定義emptyDir類型的Volume
- name: myweb
emptyDir: {}
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: myweb
mountPath: /usr/share/nginx/html/
- name: busybox
image: busybox:latest
volumeMounts: # 將名為myweb的volume掛載到容器里的/web目錄下
- name: myweb
mountPath: /web
command: [ "/bin/sh", "-c", "while true; do echo $(date) >> /web/index.html; done" ]
查看volume信息:
$ docker inspect 020799d427ae -f "{{.Mounts}}"
"Mounts": [
{
"Type": "bind",
"Source": "/var/lib/kubelet/pods/bb66b0cd-979d-4356-92a9-492d420fc613/volumes/kubernetes.io~empty-dir/html",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
嘗試將pod刪除,node上的volume目錄也會(huì)被刪除:
$ kubectl delete pod pod-demo
$ ls /var/lib/kubelet/pods/bb66b0cd-979d-4356-92a9-492d420fc613
2、hostPath
該類型是將Node上指定的文件或目錄掛載到Pod中。當(dāng)Pod被刪除時(shí),Node上對(duì)應(yīng)的該Volume的文件或目錄不會(huì)被刪除,會(huì)保留下來(lái),從這點(diǎn)來(lái)看,hostPath的持久性比emptyDir強(qiáng)。不過(guò)一旦node節(jié)點(diǎn)崩潰了,hostPath也就沒(méi)法訪問(wèn)了。
hostPath 類型相當(dāng)于執(zhí)行【docker run -v /HOST/DIR:/CONTAINER/DIR】。
apiVersion: v1
kind: Pod
metadata:
name: pod-demo2
spec:
volumes:
- name: myweb
hostPath:
path: /data/www/ # 指定node上的目錄
type: Directory
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: myweb
mountPath: /usr/share/nginx/html/ #要掛載到容器的哪個(gè)目錄下
3、外部存儲(chǔ)(以NFS為例)
除了將數(shù)據(jù)存放在本地node節(jié)點(diǎn)上,為了更安全,我們也可以將數(shù)據(jù)存儲(chǔ)到外部的遠(yuǎn)程磁盤上,比如放到NFS服務(wù)器上,IP為192.168.100.172。
1)搭建NFS服務(wù)器
yum -y install nfs-utils
mkdir -p /data/testvol
echo "NFS Test Data" > /data/testvol/index.html
echo "/data/testvol 192.168.100.0/24(rw,no_root_squash)" >> /etc/exports
systemctl start nfs
2)創(chuàng)建NFS存儲(chǔ)卷
# 在k8s集群的節(jié)點(diǎn)上,安裝nfs-utils工具
$ yum -y install nfs-utils
# 驗(yàn)證是否能成功掛載
$ mount -t nfs 192.168.100.172:/data/testvol /mnt
# yaml文件如下:
$ cat vol-nfs-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: vol-nfs
spec:
volumes:
- name: myweb
nfs:
path: /data/testvol # NFS共享目錄
server: 192.168.100.172 # NFS服務(wù)器IP
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: myweb
mountPath: /usr/share/nginx/html/
二、PV與PVC
除了Volume之外,kubernetes 還提供了 Persistent Volume 的方法持久化數(shù)據(jù)。
它與普通Volume的區(qū)別是,?普通Volume和Pod之間是一種靜態(tài)綁定關(guān)系,也就是,在定義pod時(shí),同時(shí)要將pod所使用的Volume一并定義好,Volume是Pod的附屬品。volume會(huì)隨著pod創(chuàng)建而被創(chuàng)建,我們無(wú)法單獨(dú)創(chuàng)建一個(gè)Volume,因?yàn)樗皇且粋€(gè)獨(dú)立的K8S資源對(duì)象。
而Persistent Volume則是一個(gè)K8S資源對(duì)象,它是獨(dú)立于Pod的,能單獨(dú)創(chuàng)建。Persistent Volume 不與Pod發(fā)生直接關(guān)系,而是通過(guò) Persistent Volume Claim(PVC) 來(lái)與Pod綁定關(guān)系。在定義Pod時(shí),為Pod指定一個(gè)PVC,Pod在創(chuàng)建時(shí)會(huì)根據(jù)PVC要求,從現(xiàn)有集群的PV中,選擇一個(gè)合適的PV綁定,或動(dòng)態(tài)建立一個(gè)新的PV,再與其進(jìn)行綁定。
Persistent Volume(PV):用于定義各種存儲(chǔ)資源的配置信息,一個(gè)PV對(duì)應(yīng)一個(gè)volume,定義一個(gè)PV內(nèi)容包括了 存儲(chǔ)類型、存儲(chǔ)大小和訪問(wèn)模式等。
Persistent Volume Claim(PVC):描述對(duì)PV的一個(gè)請(qǐng)求。請(qǐng)求信息包含存儲(chǔ)大小、訪問(wèn)模式等。PVC只會(huì)選擇符合自己要求的PV進(jìn)行綁定,然后在定義pod時(shí)指定使用哪個(gè)PVC就可以了。
原理:
PVC和PV的設(shè)計(jì),其實(shí)跟面向?qū)ο蟮乃枷胪耆恢拢琍VC是面向?qū)ο缶幊讨械慕涌?,PV是接口具體的實(shí)現(xiàn)。
用戶只需通過(guò)PVC來(lái)聲明自己的存儲(chǔ)需求,比如存儲(chǔ)大小、可讀寫權(quán)限等,類似于調(diào)用接口函數(shù)并傳入屬性參數(shù),而不用關(guān)心后端存儲(chǔ)實(shí)現(xiàn)細(xì)節(jié),這些都交由運(yùn)維人員統(tǒng)一管理即可。
Pod是直接與PVC綁定關(guān)系,再根據(jù)PVC存儲(chǔ)需求,去找到對(duì)應(yīng)PV。PVC只有綁定了PV之后才能被Pod使用。
PersistentVolume Controller 會(huì)不斷地查看當(dāng)前每一個(gè)PVC,是不是已經(jīng)處于Bound(已綁定)狀態(tài)。如果不是,那它就會(huì)遍歷所有的、可用的PV,并嘗試將其與這個(gè)PVC進(jìn)行綁定。這樣,Kubernetes就可以保證用戶提交的每一個(gè)PVC,只要有合適的PV出現(xiàn),它就能夠很快進(jìn)入綁定狀態(tài)。
在提交PVC后,是如何找到對(duì)應(yīng)的PV:先根據(jù)PVC的accessModes匹配出PV列表,再根據(jù)PVC的Capacity、StorageClassName、Label Selector進(jìn)一步篩選PV。如果滿足條件的PV有多個(gè),選擇PV的size最小的,accessmodes列表最短的PV,也即最小適合原則。
也就是說(shuō),PVC綁定PV的過(guò)程是有一定規(guī)則的,以下規(guī)則都滿足的PV才能被PVC綁定:
VolumeMode:被消費(fèi)PV的VolumeMode需要和PVC一致。
AccessMode:被消費(fèi)PV的AccessMode需要和PVC一致。
StorageClassName:如果PVC定義了此字段,則PV也必須有對(duì)應(yīng)字段才能進(jìn)行綁定。
LabelSelector:通過(guò)標(biāo)簽(labels)匹配的方式從PV列表中選擇合適的PV綁定。
Size:被消費(fèi)PV的capacity必須大于或等于PVC的存儲(chǔ)容量需求才能被綁定。
PV類型:
一般來(lái)說(shuō),PV又有多種類型:Static PV (靜態(tài))、Dynamic PV (動(dòng)態(tài))、Local PV (本地)。
Static/Dynamic PV:靜態(tài)和動(dòng)態(tài)PV
PV創(chuàng)建雖是由運(yùn)維人員完成的,但在一個(gè)大規(guī)模的Kubernetes集群里,很可能有成千上萬(wàn)個(gè)PVC,這就意味著運(yùn)維人員必須得事先創(chuàng)建出成千上萬(wàn)個(gè)PV,如果單純靠人工來(lái)管理,會(huì)存在一定的困難。
Kubernetes提供了一套可以自動(dòng)創(chuàng)建PV的機(jī)制,即Dynamic Volume Provisioning(動(dòng)態(tài)PV)。而手動(dòng)創(chuàng)建并管理的PV叫做Static Volume Provisioning(靜態(tài)PV)。
Dynamic PV創(chuàng)建機(jī)制的核心,在于一個(gè)名為StorageClass的API對(duì)象,它是一個(gè)用于創(chuàng)建PV的模板。
在YAML文件中定義PVC時(shí),需要指定一個(gè)StorageClass名稱,然后等到用戶要?jiǎng)?chuàng)建這個(gè)PVC時(shí),系統(tǒng)會(huì)根據(jù)PVC定義的需求,并參考StorageClass的存儲(chǔ)細(xì)節(jié),最后通過(guò)調(diào)用StorageClass聲明的存儲(chǔ)插件(Provisioner),動(dòng)態(tài)創(chuàng)建出需要的PV。
所以,在聲明一個(gè)PVC時(shí),如果在PVC中添加了StorageClassName字段,那就意味著,當(dāng)PVC在集群中找不到匹配的PV時(shí),它會(huì)根據(jù)StorageClassName的定義,觸發(fā)相應(yīng)的Provisioner插件創(chuàng)建出合適的PV進(jìn)行綁定。
也就是說(shuō),現(xiàn)在無(wú)需事先創(chuàng)建好將來(lái)要用到的PV,只要通過(guò)StorageClass準(zhǔn)備好一些PV模板,等到將來(lái)要使用時(shí),PVC再直接使用StorageClass定義好的PV模板,調(diào)用存儲(chǔ)插件將PV一并創(chuàng)建出來(lái)就可以了。
Local-PV:本地PV
一是,不應(yīng)該隨便把node上的任何一個(gè)目錄當(dāng)作PV使用,因?yàn)椴话踩瑧?yīng)該額外掛載一個(gè)外部磁盤到node上,也就是,一個(gè)PV對(duì)應(yīng)一塊外部數(shù)據(jù)盤。
二是,調(diào)度器要保證Pod始終能被正確地調(diào)度到它所請(qǐng)求的Local PV所在的節(jié)點(diǎn)上,那調(diào)度器就要知道所有node與local pv的關(guān)聯(lián)關(guān)系,即PV的位置分布信息(也叫存儲(chǔ)拓?fù)湫畔ⅲ缓蟾鶕?jù)這個(gè)位置信息來(lái)調(diào)度Pod。
流程圖:
1:先準(zhǔn)備好外部存儲(chǔ)資源;
2:然后通過(guò)static或dynamic方式,將存儲(chǔ)資源定義成PV;
3:定義PVC資源請(qǐng)求,PVC會(huì)根據(jù)配置描述選擇合適的PV;
4:最后Pod指定使用哪個(gè)PVC,最終是由PVC將Pod與匹配的PV綁定在一起;
————————————————————————————————
|namespace |
| |
| [pod1] [pod2] |
| ↓ ↓ |
| [volume1] [volume2] |
| ↑ ↑ |
| | / |
| ↓ ↓ |
| [pvc] [pvc] [pvc] |
——————↑—————————↑————————↑——————
/ \ |_ _ _ _ _ __
/ \ ↓
↓ ↓ ↓
[pv] [pv] | | [pv] [pv] [pv] | [pv] [pv] [pv]
| | |
static | | storageClass | storageClass
——————————— —————————————— ————————————————
↑↑ ↑↑
↑↑ ↑↑
———————————————— ——————————————————————
[NFS] [ISCSI] [Ceph RDB] [Glusterfs]
PV狀態(tài):
Create PV ---> pending --->?available ---> bound ---> released ---> deleted或failed
Available:創(chuàng)建PV后,會(huì)短暫處于pending狀態(tài),等真正創(chuàng)建好后,就會(huì)進(jìn)入available狀態(tài),只有處于該狀態(tài)下的PV才能夠被PVC綁定。
Bound:用戶在提交PVC后,并找到相應(yīng)PV,此時(shí)PV與PVC已綁在一起,兩者都處于BOUND狀態(tài)。
Released:如果PV設(shè)置了ReclaimPolicy策略為retain,也就是當(dāng)用戶在使用完P(guān)VC,將其刪除后,對(duì)應(yīng)的這個(gè)PV就會(huì)處于released狀態(tài)。
當(dāng)PV已經(jīng)處在released狀態(tài)時(shí),它是無(wú)法直接回到available狀態(tài),也就是說(shuō),接下來(lái)這個(gè)PV無(wú)法被一個(gè)新的PVC去做綁定。
有兩種方式復(fù)用處于released狀態(tài)的PV:
一種是對(duì)之前released的PV做好數(shù)據(jù)備份,然后重新創(chuàng)建一個(gè)PV,并將之前released的PV相關(guān)字段的信息填到這個(gè)PV中。另一種是在刪除Pod后,不要?jiǎng)h除PVC,將PVC保留下來(lái)供其他Pod直接復(fù)用。
1、Static PV
這里還是以NFS服務(wù)器作為PV存儲(chǔ)為例。
1)先搭建好NFS服務(wù)器(192.168.100.172)
創(chuàng)建4個(gè)NFS共享目錄:
yum -y install nfs-utils
mkdir -p /data/volumes/v{1..5}
echo "<h1>NFS stor 01</h1>" > /data/volumes/v1/index.html
echo "<h1>NFS stor 02</h1>" > /data/volumes/v2/index.html
echo "<h1>NFS stor 03</h1>" > /data/volumes/v3/index.html
echo "<h1>NFS stor 04</h1>" > /data/volumes/v4/index.html
cat > /etc/exports << EOF
/data/volumes/v1 192.168.100.0/24(rw,no_root_squash)
/data/volumes/v2 192.168.100.0/24(rw,no_root_squash)
/data/volumes/v3 192.168.100.0/24(rw,no_root_squash)
/data/volumes/v4 192.168.100.0/24(rw,no_root_squash)
EOF
systemctl start nfs
exportfs -rv # 重新加載配置
showmount -e # 查看本地有哪些共享目錄
2)創(chuàng)建PV
創(chuàng)建4個(gè)pv,都使用nfs共享的目錄,存儲(chǔ)大小各不相同,是否可讀也不相同。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0001
labels:
name: pv0001
spec:
nfs:
path: /data/volumes/v1
server: 192.168.100.172
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0002
labels:
name: pv0002
spec:
nfs:
path: /data/volumes/v2
server: 192.168.100.172
accessModes: ["ReadWriteOnce"]
capacity:
storage: 7Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
labels:
name: pv0003
spec:
nfs:
path: /data/volumes/v3
server: 192.168.100.172
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 10Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0004
labels:
name: pv0004
spec:
nfs:
path: /data/volumes/v4
server: 192.168.100.172
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 15Gi
字段說(shuō)明:
capacity:設(shè)置PV的存儲(chǔ)屬性,比如存儲(chǔ)大小。
accessModes:設(shè)置對(duì)Volume的訪問(wèn)模式
ReadWriteOnce – the volume can be mounted as read-write by a single node
ReadOnlyMany – the volume can be mounted read-only by many nodes
ReadWriteMany – the volume can be mounted as read-write by many nodespersistentVolumeReclaimPolicy:當(dāng)PVC被刪除時(shí),對(duì)應(yīng)PV的回收策略
Retain - 當(dāng)PVC被刪除時(shí),PV會(huì)保留,但被標(biāo)識(shí)為released狀態(tài)
Delete - 當(dāng)PVC被刪除時(shí),PV也同時(shí)被刪除
Recycle - 已廢棄
查看PV信息:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv0001 2Gi RWO,RWX Retain Available 6s
pv0002 7Gi RWO Retain Available 6s
pv0003 10Gi RWO,RWX Retain Available 6s
pv0004 15Gi RWO,RWX Retain Available 6s
3)創(chuàng)建PVC
創(chuàng)建一個(gè)PVC,創(chuàng)建好后,該P(yáng)VC會(huì)根據(jù)要求請(qǐng)求合適的PV資源。
如:下面的PVC會(huì)綁定到名為pv0003的PV上
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
spec:
accessModes: ["ReadWriteMany"] #匹配PV的accessModes要包含ReadWriteMany
resources:
requests:
storage: 6Gi #且匹配PV要大于6G
4)創(chuàng)建Pod
創(chuàng)建一個(gè)Pod,并指定使用哪個(gè)PVC,PVC會(huì)決定將哪個(gè)PV綁定到此Pod上。
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
spec:
volumes:
- name: myvol
persistentVolumeClaim:
claimName: mypvc #為此Pod指定使用哪個(gè)PVC
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: myvol
mountPath: /usr/share/nginx/html/
創(chuàng)建Pod后,查看PV和PVC狀態(tài):
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv0001 2Gi RWO,RWX Retain Available 18m
pv0002 7Gi RWO Retain Available 18m
pv0003 10Gi RWO,RWX Retain Bound default/mypvc 18m
pv0004 15Gi RWO,RWX Retain Available 18m
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound pv0003 10Gi RWO,RWX 17s
測(cè)試訪問(wèn):
$ kubectl get pods pod-demo -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pod-demo 1/1 Running 0 3m21s 10.244.1.73 node1
$ curl 10.244.1.73
<h1>NFS stor 03</h1>
2、Dynamic PV
步驟1:定義2個(gè)StorageClass(創(chuàng)建生成PV的模板文件),一個(gè)為普通磁盤,一個(gè)為SSD磁盤。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: kubernetes.io/aws-ebs # 指定一個(gè)volume plugin,即應(yīng)該用哪個(gè)存儲(chǔ)插件來(lái)去創(chuàng)建PV
parameters:
type: pd-standard
reclaimPolicy: Delete # PV的回收策略,默認(rèn)為delete
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-disk
parameters:
regionId: cn-hangzhou
zoneId: cn-hangzhou-b
fsType: ext4
type: cloud_ssd
provisioner: diskplugin.csi.alibabacloud.com
reclaimPolicy: Delete
步驟2:創(chuàng)建PVC,并指定storageClassName名,即到底用哪一個(gè)模板文件來(lái)生成PV,Kubernetes只會(huì)將StorageClass相同的PVC和PV綁定起來(lái)。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: disk-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: csi-disk # 為PVC指定使用哪個(gè)StorageClass
resources:
requests:
storage: 30Gi
步驟3:創(chuàng)建Pod,并指定要調(diào)用的PVC
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: dockerfile/nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: disk-pvc
三、部署NFS動(dòng)態(tài)存儲(chǔ)卷(案例)
1、master和node節(jié)點(diǎn)安裝nfs服務(wù)
yum -y install nfs-utils rpcbind
systemctl start nfs && systemctl enable nfs
systemctl start rpcbind && systemctl enable rpcbind
# master上創(chuàng)建并配置好共享掛載目錄(node節(jié)點(diǎn)不需要,只需安裝好nfs服務(wù)就行)
mkdir -pv /data/volumes/{v1,v2,v3}
cat > /etc/exports <<EOF
/data/volumes/v1 ?*(rw,no_root_squash,no_all_squash)
/data/volumes/v2 ?*(rw,no_root_squash,no_all_squash)
/data/volumes/v3 ?*(rw,no_root_squash,no_all_squash)
EOF
# 發(fā)布并查看
exportfs -arv
showmount -e
2、部署 NFS Provisioner插件(master)
git clone https://github.com/kubernetes-incubator/external-storage.git
cd external-storage/nfs-client/deploy/
cp class.yaml deployment.yaml rbac.yaml test-claim.yaml /var/lib/k8s/storage
cd /var/lib/k8s/storage
a. 配置rbac授權(quán)(默認(rèn)是存放在default空間,可修改為kube-system)
kubectl apply -f rbac.yaml
b. 部署 NFS Provisioner插件
# 修改deployment.yaml文件(設(shè)置nfs服務(wù)器相關(guān)信息)
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
namespace: kube-system #默認(rèn)是default,修改為kube-sytem
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: quay.io/external_storage/nfs-client-provisioner:latest
image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: nfs-client #可自定義,要與class.yaml中的provisioner的名稱一致,否則部署不成功
- name: NFS_SERVER
value: x.x.x.x #修改為nfs服務(wù)器地址
- name: NFS_PATH
value: /data/volumes/v1 #NFS服務(wù)器中的共享掛載目錄
volumes:
- name: nfs-client-root
nfs:
server: x.x.x.x #修改為nfs服務(wù)器地址
path: /data/volumes/v1 #NFS服務(wù)器中的共享掛載目錄
# 部署NFS Provisioner插件
kubectl apply -f deployment.yaml
# 查看安裝情況
kubectl get pod -o wide -n kube-system -l app=nfs-client-provisioner
[root@jdmaster ~]# kubectl get pod -o wide -n kube-system -l app=nfs-client-provisioner
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-client-provisioner-7f75997fb6-tchxb 1/1 Running 0 21h 10.244.1.8 jdnode <none> <none>
kubectl get deployment -n kube-system
[root@jdmaster ~]# kubectl get deployment -n kube-system
NAME READY UP-TO-DATE AVAILABLE AGE
coredns 2/2 2 2 3d
nfs-client-provisioner 1/1 1 1 21h
3、創(chuàng)建storageclass
# 修改class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
annotations:
storageclass.kubernetes.io/is-default-class: "true" #設(shè)置為默認(rèn)的storageclass(如果不設(shè)置默認(rèn),在創(chuàng)建pvc時(shí),需要手動(dòng)指定storageclass的名稱,否則會(huì)處于pending)
provisioner: nfs-client #可自定義,要與 deployment 中 env PROVISIONER_NAME 一致
parameters:
archiveOnDelete: "false"
# 也命令方式設(shè)置默認(rèn)的StorageClass(NAME后面會(huì)多出一個(gè)default字樣)
# kubectl patch storageclass managed-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
# 創(chuàng)建storageclass
kubectl apply -f class.yaml
# 查看(storageclass所有命名空間都可以看到,不需要指定某個(gè)namespace)
kubectl get sc
[root@jdmaster ~]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
managed-nfs-storage (default) nfs-client Delete Immediate false 21h
4、創(chuàng)建PVC
# 修改test-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
#annotations:
# volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" #若這里指定storageclass了,可以不用手動(dòng)指定storageClassName字段
spec:
storageClassName: managed-nfs-storage #若沒(méi)有設(shè)置默認(rèn)的storageclass,必須手動(dòng)指定使用哪個(gè)storageclass
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
# 查看pvc狀態(tài)(會(huì)處于Bound狀態(tài),若處于pending是不正常的)
kubectl get pvc
[root@jdmaster ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-claim Bound pvc-bcbea3c8-4a37-47c1-8aa6-2c2da6964108 1Gi RWX managed-nfs-storage 20h
# 只要?jiǎng)?chuàng)建好NFS Provisioner deployment 和 storageclass后,再創(chuàng)建PVC時(shí),就會(huì)自動(dòng)創(chuàng)建出PV
kubectl get pv
[root@jdmaster ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-bcbea3c8-4a37-47c1-8aa6-2c2da6964108 1Gi RWX Delete Bound default/test-claim managed-nfs-storage 20h
5、創(chuàng)建一個(gè)測(cè)試pod
kubectl apply -f test-pod.yaml
cat > test-pod.yaml <<EOF
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox:latest
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim
EOF
# POD會(huì)成功創(chuàng)建好SUCCESS文件,就退出了,狀態(tài)為Completed
# 進(jìn)入到NFS共享目錄(/data/volumes/v1/<namespace名稱>-<pvc名稱>-<pv名稱>/),查看SUCCESS文件是否存在
四、架構(gòu)設(shè)計(jì)
PV和PVC的處理流程:
【配圖-待補(bǔ)充】
csi全稱是container storage interface,它是K8s社區(qū)后面對(duì)存儲(chǔ)插件實(shí)現(xiàn)(out of tree)的官方推薦方式。
csi的實(shí)現(xiàn)大體可分為兩部分:
第一部分:是由k8s社區(qū)驅(qū)動(dòng)實(shí)現(xiàn)的通用的部分,如圖中的csi-provisioner和csi-attacher controller;
第二部分:由云存儲(chǔ)廠商實(shí)踐的,對(duì)接云存儲(chǔ)廠商的OpenApi,主要是實(shí)現(xiàn)真正的create/delete/mount/unmount 存儲(chǔ)的相關(guān)操作,對(duì)應(yīng)到圖中的csi-controller-server和csi-node-server。
用戶在提交PVC yaml時(shí),首先會(huì)在集群中生成一個(gè)PVC對(duì)象,然后PVC對(duì)象會(huì)被csi-provisioner controller watch到,csi-provisioner會(huì)結(jié)合PVC對(duì)象及PVC對(duì)象中聲明的 storageClass,通過(guò)GRPC調(diào)用csi-controller-server。然后,到云存儲(chǔ)服務(wù)這邊去創(chuàng)建真正的存儲(chǔ),并最終創(chuàng)建出來(lái)PV對(duì)象。最后,由集群中的PV controller將PVC和PV對(duì)象做bound 之后,這個(gè)PV就可以被使用了。
用戶在提交pod之后,首先會(huì)被scheduler調(diào)度選中某一個(gè)合適的node,然后node上的kubelet在創(chuàng)建pod時(shí),會(huì)先通過(guò)csi-node-server將之前創(chuàng)建的PV掛載到pod指定路徑。
然后kubelet開(kāi)始 create && start pod 中的所有container。
PV、PVC及通過(guò)csi使用存儲(chǔ)流程:
【配圖-待補(bǔ)充】
第一個(gè)階段:create階段,主要是創(chuàng)建存儲(chǔ)。
用戶提交完P(guān)VC,由csi-provisioner創(chuàng)建存儲(chǔ),并生成PV對(duì)象,之后PV controller將PVC及生成的PV對(duì)象做bound,bound之后,create階段就完成了。
第二個(gè)階段:attach階段,將對(duì)應(yīng)的存儲(chǔ)掛載到node上。
用戶在提交pod之后,首先會(huì)被scheduler調(diào)度選中某一個(gè)合適的node,node被選出來(lái)后,AD Controller會(huì)watch到該node,它會(huì)根據(jù)Pod使用了哪些PV,生產(chǎn)一個(gè)內(nèi)部的VolumeAttachment對(duì)象,從而去觸發(fā)csi-attacher去調(diào)用csi-controller-server去做真正的attach操作,attach操作調(diào)到云存儲(chǔ)廠商OpenAPI,并將存儲(chǔ)attach到pod將會(huì)運(yùn)行的node上面。
第三個(gè)階段:mount階段,將對(duì)應(yīng)的存儲(chǔ)進(jìn)一步掛載到pod里。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-404075.html
在kubelet創(chuàng)建pod的過(guò)程中,會(huì)先做一個(gè)mount操作,這是為了將已經(jīng)attach到這個(gè)node上的那塊盤,進(jìn)一步mount到pod可使用的一個(gè)具體路徑,之后kubelet才開(kāi)始創(chuàng)建并啟動(dòng)容器。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-404075.html
到了這里,關(guān)于k8s篇-應(yīng)用持久化存儲(chǔ)(PV和PVC)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!