Kubernetes 存儲卷
根據(jù)應(yīng)用本身是否需要持久存儲數(shù)據(jù),以及每一次的請求跟此前的請求之間是否有關(guān)聯(lián)性囊蓝,可以分為四類應(yīng)用:
- 有狀態(tài)、要存儲
- 有狀態(tài)令蛉、無存儲
- 無狀態(tài)聚霜、有存儲
- 無狀態(tài)、無存儲
持久化數(shù)據(jù)的方式
節(jié)點級:節(jié)點提供存儲卷珠叔。此方式在k8s上蝎宇,不太適用。這是因為一旦Pod被刪除了祷安,Pod是要被Scheduler組件重新調(diào)度的姥芥,調(diào)度之后的Pod并不一定還能運行在原來的節(jié)點上。
脫離節(jié)點而存在的網(wǎng)絡(luò)共享存儲設(shè)備汇鞭。k8s使用這種方式凉唐。
Pod的特點:
同一個Pod內(nèi)的多個容器,可共享訪問同一個存儲卷霍骄。因為:對k8s來講台囱,存儲卷不屬于容器,而屬于Pod读整,可以在容器中掛在存儲卷簿训,所以,如果兩個容器掛在了同一個存儲卷米间,相當(dāng)于兩個容器共享數(shù)據(jù)了强品。
為什么Pod能有存儲卷Volume,也能有網(wǎng)絡(luò)命名空間Namespace呢屈糊?Pod其實底層有個基礎(chǔ)容器pause的榛。所有的網(wǎng)絡(luò)名稱空間,存儲卷的掛載另玖,都是分配給基礎(chǔ)容器pause的困曙。在Pod中運行的容器是共享基礎(chǔ)容器pause的命名空間、存儲卷的谦去。所以這就是為什么同一個Pod內(nèi)的所有容器都能使用同一個IP地址慷丽、共享同一個TCP/IP協(xié)議棧、使用同一個主機(jī)名的原因(因為ipc鳄哭、net要糊、uts名稱空間是共享的)。
如果在Pod上使用存儲卷:Pod的基礎(chǔ)架構(gòu)容器pause使用存儲卷——>容器的存儲卷就是容器的目錄與宿主機(jī)目錄建立關(guān)系——>如果宿主機(jī)的目錄就是宿主機(jī)本地的妆丘,那么就隨著宿主機(jī)的終結(jié)而終結(jié)锄俄,所以為了真正實現(xiàn)持久性,宿主機(jī)的目錄也不是宿主機(jī)本地的勺拣,而是宿主機(jī)掛載的外部存儲設(shè)備上的存儲卷奶赠。
k8s提供的存儲卷類型
empryDir
emptyDir類型的volume在pod分配到node上時被創(chuàng)建,kubernetes會在node上自動分配 一個目錄药有,因此無需指定宿主機(jī)node上對應(yīng)的目錄文件毅戈。這個目錄的初始內(nèi)容為空,當(dāng)Pod從node上移除時愤惰,emptyDir中的數(shù)據(jù)會被永久刪除苇经。不具備持久存儲性。
hostPath
hostPath Volume為pod掛載宿主機(jī)上的目錄或文件宦言,使得容器可以使用宿主機(jī)的高速文件系統(tǒng)進(jìn)行存儲扇单。缺點是,在k8s中奠旺,pod都是動態(tài)在各node節(jié)點上調(diào)度蜘澜。當(dāng)一個pod在當(dāng)前node節(jié)點上啟動并通過hostPath存儲了文件到本地以后,下次調(diào)度到另一個節(jié)點上啟動時响疚,就無法使用在之前節(jié)點上存儲的文件(如果調(diào)度到同一個節(jié)點兼都,還是可以繼續(xù)使用之前節(jié)點上存儲的文件的)。不具備持久存儲性稽寒。
使用 subPath
引用卷的時候扮碧,默認(rèn)會將卷的根目錄掛載到指定路徑中。
可以通過 subPath 掛載卷的子目錄杏糙,而不是根目錄慎王。
示例
apiVersion: v1
kind: Pod
metadata:
name: my-lamp-site
spec:
containers:
- name: mysql
image: mysql
volumeMounts:
- mountPath: /var/lib/mysql
name: site-data
subPath: mysql
volumes:
- name: site-data
persistentVolumeClaim:
claimName: my-lamp-site-data
將掛載 site-data 卷的子目錄 mysql 到容器目錄 /var/lib/mysql 中
gitRepo
gitRepo—通過檢查git倉庫的內(nèi)容來初始化卷(實質(zhì)也是一個emptyDir,只不過預(yù)置了git倉庫內(nèi)容)
每次pod重新創(chuàng)建時宏侍,會自動拉取最新代碼
網(wǎng)絡(luò)存儲設(shè)備
無論P(yáng)od重啟后是否調(diào)度到原來的節(jié)點赖淤,存儲的文件可以繼續(xù)使用。
傳統(tǒng)意義上的網(wǎng)絡(luò)存儲設(shè)備:SAN(存儲區(qū)域網(wǎng)絡(luò)的簡稱谅河,常見的有:iSCSI...)咱旱、NAS(網(wǎng)絡(luò)附屬存儲:常見的有:nfs确丢、cifs)...
nfs 卷能將 NFS (網(wǎng)絡(luò)文件系統(tǒng)) 掛載到您的 Pod 中。
不像 emptyDir 那樣會在刪除 Pod 的同時也會被刪除吐限,nfs 卷的內(nèi)容在刪除 Pod 時會被保存鲜侥,卷只是被卸載掉了。
這意味著 nfs 卷可以被預(yù)先填充數(shù)據(jù)诸典,并且這些數(shù)據(jù)可以在 Pod 之間"傳遞"描函。分布式網(wǎng)絡(luò)存儲設(shè)備:glusterfs(文件系統(tǒng)級別存儲)、cephfs(文件系統(tǒng)級別存儲)狐粱、ceph rbd(塊級別存儲)...
云網(wǎng)絡(luò)存儲設(shè)備:EBS(亞馬遜的)舀寓、Azure Disk(微軟的)、Azure File(微軟的)...
pvc和pv
兩種特殊類型的存儲卷:目的不是給Pod提供存儲空間肌蜻,而是給管理員或用戶提供了互墓,從集群外部向Pod內(nèi)部的應(yīng)用,注入配置信息的configmap
ConfigMap 資源提供了向 Pod 注入配置數(shù)據(jù)的方法蒋搜。
ConfigMap 對象中存儲的數(shù)據(jù)可以被 configMap 類型的卷引用轰豆,然后被應(yīng)用到 Pod 中運行的容器。
可以在 volumes 字段中引用 configMap 名稱來生成一個卷齿诞。
可以自定義 ConfigMap 中特定條目所要使用的路徑酸休。
如果容器以 subPath 卷掛載方式使用 ConfigMap 時,將無法接收 ConfigMap 的更新祷杈。
示例
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: test
image: busybox
volumeMounts:
- name: config-vol
mountPath: /etc/config
volumes:
- name: config-vol
configMap:
name: log-config
items:
- key: log_level
path: log_level
ConfigMap 中 key log_level 中的內(nèi)容將被掛載到 Pod 路徑 /etc/config/log_level 中
路徑由 spec.containers 中參數(shù) volumeMounts.mountpath 和 volumes 中參數(shù) items.path 拼接而成
- secret(方式)
secret 卷用來給 Pod 傳遞敏感信息斑司,例如密碼。
可以將 secret 存儲在 Kubernetes API 服務(wù)器上但汞,然后以文件的形式掛在到 Pod 中宿刮,實現(xiàn)與 Pod 解耦。
secret 卷由 tmpfs(基于內(nèi)存的文件系統(tǒng))提供存儲私蕾,因此它們永遠(yuǎn)不會被寫入持久化的存儲器僵缺。
容器以 subPath 卷的方式掛載 Secret 時,它將無法實時獲取 Secret 的更新
pvc的相關(guān)知識
pvc——>與當(dāng)前命名空間中的pvc資源建立關(guān)系——>與pv資源(真正提供存儲的資源)建立關(guān)系——>與存儲系統(tǒng)建立關(guān)系
- 在pvc不被調(diào)用時踩叭,pvc和pv之間是沒有綁定的磕潮。
- pv和pvc是一一對應(yīng)的,一旦某個pv被某個pvc綁定了容贝,這個pv就不能被其他pvc綁定自脯。
- pvc究竟綁定哪個pv?取決于pvc的定義中所指定的dataSource的大小斤富。比如pvc指定存儲空間的大小為5G膏潮,那么存儲空間為2G的pv就不符合條件。
-
還可以指定pvc的訪問模型(取決于pvc的定義中做指定的accessModes).
image.png
首先我們看下PV和PVC的生命周期過程:
資源供應(yīng) (Provisioning)
資源供應(yīng) 就是集群管理員(k8s集群)將volume虛擬化為很多個PV满力,目的就是創(chuàng)建合適的PV焕参,有靜態(tài)模式和動態(tài)模式轻纪。
靜態(tài)模式:集群管理員手工創(chuàng)建許多PV,在定義PV時需要將后端存儲的特性進(jìn)行設(shè)置
動態(tài)模式:集群管理員無須手工創(chuàng)建PV叠纷,而是通過StorageClass的設(shè)置對后端存儲進(jìn)行描述刻帚,標(biāo)記為某種 “類型(Class)”。此時要求PVC對存儲的類型進(jìn)行聲明讲岁,系統(tǒng)將自動完成PV的創(chuàng)建及PVC的綁定我擂。PVC可以聲明Class為””衬以,說明該P(yáng)VC禁止使用動態(tài)模式
資源綁定 (Binding)
用戶定義好PVC后缓艳,系統(tǒng)會根據(jù)PVC對存儲的請求選擇一個滿足PVC要求的PV(PV的存在可能比PVC請求的大),找到就綁定看峻,PV就被該P(yáng)VC獨占阶淘,不能和其他PVC綁定,如果沒找到就一直處于pending中互妓。如果資源供應(yīng)使用的是動態(tài)模式溪窒,則系統(tǒng)在PVC找到合適的StorageClass后,將會自動創(chuàng)建PV并完成PVC的綁定冯勉。
資源使用 (Using)
POD創(chuàng)建可以綁定PVC澈蚌,也可以多個POD掛載同一個PVC即共享多個實例共同訪問一塊存儲空間
資源釋放 (Releasing):
當(dāng)用戶對存儲資源使用哪個完畢后,用戶可以刪除PVC灼狰,與該P(yáng)VC綁定的PV將會被標(biāo)記為已釋放宛瞄,但還不能立刻與其他PVC進(jìn)行綁定。通過之前PVC寫入的數(shù)據(jù)可能還留在存儲設(shè)備上交胚,只有在清除之后該P(yáng)V才能繼續(xù)使用
資源回收 (Reclaiming)
對于PV份汗,管理員可以設(shè)定回收策略(Reclaim Policy)用于設(shè)置與之綁定的PVC釋放資源之后,對于遺留數(shù)據(jù)如何處理蝴簇。只有PV的存儲空間完成回收杯活,才能供新的PVC綁定和使用。
對于上述生命周期過程熬词,對于PV的不同狀態(tài):
- Available (可用): 表示可用狀態(tài)旁钧,還未被任何PVC綁定 (資源供應(yīng)、資源釋放<數(shù)據(jù)清除完>)
- Bound (已綁定):已經(jīng)綁定到某個PVC (資源綁定互拾、資源使用)
- Released (已釋放):對應(yīng)的PVC已經(jīng)刪除,但資源還沒有被集群收回 (資源釋放<數(shù)據(jù)未清除>)
- Failed:PV自動回收失敗
下面說下怎么創(chuàng)建PV:
首先要創(chuàng)建存儲服務(wù)均践,以NFS存儲為例:https://www.csdn.net/gather_26/MtjaggzsOTk0NTItYmxvZwO0O0OO0O0O.html
定義好PV模型及pv的yaml文件:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1 #pv名稱
spec:
capacity: #存儲能力,一個pv對象都要指定一個存儲能力摩幔,目前僅支持存儲空間的設(shè)置
storage: 1Gi #存儲空間
accessModes:
- ReadWriteOnce #訪問模式
persistentVolumeReclaimPolicy: Recycle #回收策略
nfs: #服務(wù)模式 (nfs彤委、ceph、hostpath等)
path: /data/k8s-volume #共享數(shù)據(jù)目錄掛載點
server: 192.168.1.4044 #nfs服務(wù)器地址
其中訪問模式有三種:
- ReadWriteOnce (RWO) 讀寫權(quán)限或衡,但是只能被單個節(jié)點掛載
- ReadOnlyMany (ROX) 只讀權(quán)限焦影,可能被多個節(jié)點掛載
- ReadWriteMany (RWX) 讀寫權(quán)限车遂,可以被多個節(jié)點掛載
回收策略也有三種:
- Retain (保留) 保留數(shù)據(jù),需要管理員手動清理
- Recycle (回收) 清除PV中的數(shù)據(jù)斯辰,效果相當(dāng)于執(zhí)行刪除命令
- Delete (刪除) 與PV相連的后端存儲完成volume的刪除操作舶担,常見于云服務(wù)商的存儲服務(wù)
創(chuàng)建PV:
[root]# kubectl apply -f pv.yaml
persistentvolume/pv1 created
查看PV:
[root]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWO Recycle Available 5s
如果PV被PVC綁定,會有CLAIM信息:
創(chuàng)建PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
[root@harbor ~]# kubectl apply -f pv.yaml
persistentvolume/pv1 created
[root@harbor ~]# kubectl get pvc -n default
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-nfs Bound pv1 1Gi RWO 71s
[root@harbor ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWO Recycle Bound default/pvc-nfs 4m35s
這里我們可以看到彬呻,當(dāng)我們創(chuàng)建pvc之后衣陶,pv的狀態(tài)變成了Bound綁定狀態(tài),并且和pvc的狀態(tài)相同闸氮。并且可以看到pvc已經(jīng)綁定到名稱為pv1的volume上剪况,同時在pv上可以看到綁定到名稱為pvc-nfs的pvc中
其中查詢PVC信息要帶namespaces,因為PVC被POD使用必須歸屬某個命名空間
但是我們怎么通過創(chuàng)建PVC綁定我們需要的PV呢蒲跨,這邊就涉及l(fā)abel的使用了译断,在k8s中pod綁定node等都是通過label來的:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
labels: #這里將pv設(shè)置一個labels
app: nfs
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /data/k8s-volume
server: 192.168.1.144
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc2-nfs
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
selector: ##pvc匹配標(biāo)簽為app=nfs的pv
matchLabels:
app: nfs
下面我們創(chuàng)建deployment使用PVC:
apiVersion: apps/v1
kind: Deployment
metadata:
name: pv-nfs-nginx
spec:
replicas: 3
selector:
matchLabels:
app: pv-nfs-nginx
template:
metadata:
labels:
app: pv-nfs-nginx
spec:
containers:
- name: pv-nfs-nginx
image: nginx
ports:
- containerPort: 801
volumeMounts: #掛載,首先添加需要掛載的目錄
- name: pv-nginx #掛載點的名稱
mountPath: /usr/share/nginx/html #掛載點的路徑
volumes: #綁定
- name: pv-nginx
persistentVolumeClaim: #將鏡像中的nginx目錄掛載到下面名稱的pvc中
claimName: pvc2-nfs #pvc名稱
---
apiVersion: v1
kind: Service
metadata:
name: nfs-pvc
labels:
app: pv-nfs-nginx
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 324
selector:
app: pv-nfs-nginx
deploy是replicaset上一層的控制器或悲,而service為deployment對外提供訪問服務(wù)的能力的孙咪,而本項目是沒有使用deployment而只使用了replicaset,且也沒有使用service
StorageClass
理論
在動態(tài)資源供應(yīng)模式下巡语,通過StorageClass和PVC完成資源動態(tài)綁定(系統(tǒng)自動生成PV)翎蹈,并供Pod使用的存儲管理機(jī)制。
volumeClaimTemplates實現(xiàn)了pvc的自動化男公,StorageClass實現(xiàn)了pv的自動化
什么是StorageClass
Kubernetes提供了一套可以自動創(chuàng)建PV的機(jī)制荤堪,即:Dynamic Provisioning。而這個機(jī)制的核心在于StorageClass這個API對象理澎。
StorageClass對象會定義下面兩部分內(nèi)容:
- PV的屬性逞力。比如,存儲類型糠爬,Volume的大小等寇荧。
- 創(chuàng)建這種PV需要用到的存儲插件,即存儲制備器执隧。
有了這兩個信息之后揩抡,Kubernetes就能夠根據(jù)用戶提交的PVC,找到一個對應(yīng)的StorageClass镀琉,之后Kubernetes就會調(diào)用該StorageClass聲明的存儲插件峦嗤,進(jìn)而創(chuàng)建出需要的PV。
但是其實使用起來是一件很簡單的事情屋摔,你只需要根據(jù)自己的需求烁设,編寫YAML文件即可,然后使用kubectl create命令執(zhí)行即可钓试。
StorageClass 為管理員提供了描述存儲 “類” 的方法装黑。 不同的類型可能會映射到不同的服務(wù)質(zhì)量等級或備份策略副瀑,或是由集群管理員制定的任意策略。 Kubernetes 本身并不清楚各種類代表的什么恋谭。這個類的概念在其他存儲系統(tǒng)中有時被稱為 “配置文件”糠睡。
為什么需要StorageClass
在一個大規(guī)模的Kubernetes集群里,可能有成千上萬個PVC疚颊,這就意味著運維人員必須實現(xiàn)創(chuàng)建出這個多個PV狈孔,此外,隨著項目的需要材义,會有新的PVC不斷被提交均抽,那么運維人員就需要不斷的添加新的,滿足要求的PV母截,否則新的Pod就會因為PVC綁定不到PV而導(dǎo)致創(chuàng)建失敗到忽。而且通過 PVC 請求到一定的存儲空間也很有可能不足以滿足應(yīng)用對于存儲設(shè)備的各種需求橄教。
而且不同的應(yīng)用程序?qū)τ诖鎯π阅艿囊罂赡芤膊槐M相同清寇,比如讀寫速度、并發(fā)性能等护蝶,為了解決這一問題华烟,Kubernetes 又為我們引入了一個新的資源對象:StorageClass,通過 StorageClass 的定義持灰,管理員可以將存儲資源定義為某種類型的資源盔夜,比如快速存儲、慢速存儲等堤魁,用戶根據(jù) StorageClass 的描述就可以非常直觀的知道各種存儲資源的具體特性了喂链,這樣就可以根據(jù)應(yīng)用的特性去申請合適的存儲資源了。
運行原理
要使用 StorageClass妥泉,我們就得安裝對應(yīng)的自動配置程序椭微,比如我們這里存儲后端使用的是 nfs,那么我們就需要使用到一個 nfs-client 的自動配置程序盲链,我們也叫它 Provisioner(制備器)蝇率,這個程序使用我們已經(jīng)配置好的 nfs 服務(wù)器,來自動創(chuàng)建持久卷刽沾,也就是自動幫我們創(chuàng)建 PV本慕。
- 自動創(chuàng)建的 PV 以
{pvcName}-${pvName}這樣的命名格式創(chuàng)建在 NFS 服務(wù)器上的共享數(shù)據(jù)目錄中
- 而當(dāng)這個 PV 被回收后會以archieved-
{pvcName}-${pvName}這樣的命名格式存在 NFS 服務(wù)器上。
image.png
StorageClass 資源
每個 StorageClass 都包含 provisioner侧漓、parameters 和 reclaimPolicy 字段锅尘, 這些字段會在 StorageClass 需要動態(tài)分配 PersistentVolume 時會使用到。
StorageClass 對象的命名很重要布蔗,用戶使用這個命名來請求生成一個特定的類藤违。 當(dāng)創(chuàng)建 StorageClass 對象時忙菠,管理員設(shè)置 StorageClass 對象的命名和其他參數(shù),一旦創(chuàng)建了對象就不能再對其更新纺弊。
管理員可以為沒有申請綁定到特定 StorageClass 的 PVC 指定一個默認(rèn)的存儲類牛欢。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:
- debug
volumeBindingMode: Immediate
存儲制備器
每個 StorageClass 都有一個制備器(Provisioner),用來決定使用哪個卷插件制備 PV淆游。 該字段必須指定
表卷插件 | 內(nèi)置制備器 | 配置例子 |
---|---|---|
AWSElasticBlockStore | ? | AWS EBS |
AzureFile | ? | Azure File |
AzureDisk | ? | Azure Disk |
CephFS | - | - |
Cinder | ? | OpenStack Cinder |
FC | - | - |
FlexVolume | - | - |
Flocker | ? | - |
GCEPersistentDisk | ? | GCE PD |
Glusterfs | ? | Glusterfs |
iSCSI | - | - |
Quobyte | ? | Quobyte |
NFS | - | - |
RBD | ? | Ceph RBD |
VsphereVolume | ? | vSphere |
PortworxVolume | ? | Portworx Volume |
ScaleIO ? ScaleIO | ||
StorageOS | ? | StorageOS |
Local | - | Local |
你不限于指定此處列出的 “內(nèi)置” 制備器(其名稱前綴為 “kubernetes.io” 并打包在 Kubernetes 中)傍睹。 你還可以運行和指定外部制備器,這些獨立的程序遵循由 Kubernetes 定義的 規(guī)范犹菱。 外部供應(yīng)商的作者完全可以自由決定他們的代碼保存于何處拾稳、打包方式、運行方式腊脱、使用的插件(包括 Flex)等访得。 代碼倉庫 kubernetes-sigs/sig-storage-lib-external-provisioner 包含一個用于為外部制備器編寫功能實現(xiàn)的類庫。你可以訪問代碼倉庫 kubernetes-sigs/sig-storage-lib-external-provisioner 了解外部驅(qū)動列表陕凹。
例如悍抑,NFS 沒有內(nèi)部制備器,但可以使用外部制備器杜耙。 也有第三方存儲供應(yīng)商提供自己的外部制備器搜骡。
后面會演示NFS
回收策略
由 StorageClass 動態(tài)創(chuàng)建的 PersistentVolume 會在類的 reclaimPolicy 字段中指定回收策略,可以是 Delete 或者 Retain佑女。如果 StorageClass 對象被創(chuàng)建時沒有指定 reclaimPolicy记靡,它將默認(rèn)為 Delete。
通過 StorageClass 手動創(chuàng)建并管理的 PersistentVolume 會使用它們被創(chuàng)建時指定的回收政策团驱。
允許卷擴(kuò)展
PersistentVolume 可以配置為可擴(kuò)展摸吠。將此功能設(shè)置為 true 時,允許用戶通過編輯相應(yīng)的 PVC 對象來調(diào)整卷大小嚎花。
當(dāng)下層 StorageClass 的 allowVolumeExpansion 字段設(shè)置為 true 時寸痢,以下類型的卷支持卷擴(kuò)展。
卷類型 | Kubernetes 版本要求 |
---|---|
gcePersistentDisk | 1.11 |
awsElasticBlockStore | 1.11 |
Cinder | 1.11 |
glusterfs | 1.11 |
rbd | 1.11 |
Azure File | 1.11 |
Azure Disk | 1.11 |
Portworx | 1.11 |
FlexVolume | 1.13 |
CSI | 1.14 (alpha), 1.16 (beta) |
說明: 此功能僅可用于擴(kuò)容卷贩幻,不能用于縮小卷轿腺。
掛載選項
由 StorageClass 動態(tài)創(chuàng)建的 PersistentVolume 將使用類中 mountOptions 字段指定的掛載選項。
如果卷插件不支持掛載選項丛楚,卻指定了該選項族壳,則制備操作會失敗。 掛載選項在 StorageClass 和 PV 上都不會做驗證趣些,所以如果掛載選項無效仿荆,那么這個 PV 就會失敗。
卷綁定模式
volumeBindingMode 字段控制了卷綁定和動態(tài)制備 應(yīng)該發(fā)生在什么時候。
默認(rèn)情況下拢操,Immediate 模式表示一旦創(chuàng)建了 PersistentVolumeClaim 也就完成了卷綁定和動態(tài)制備锦亦。 對于由于拓?fù)湎拗贫羌核泄?jié)點可達(dá)的存儲后端,PersistentVolume 會在不知道 Pod 調(diào)度要求的情況下綁定或者制備令境。
集群管理員可以通過指定 WaitForFirstConsumer 模式來解決此問題杠园。 該模式將延遲 PersistentVolume 的綁定和制備,直到使用該 PersistentVolumeClaim 的 Pod 被創(chuàng)建舔庶。 PersistentVolume 會根據(jù) Pod 調(diào)度約束指定的拓?fù)鋪磉x擇或制備抛蚁。這些包括但不限于 資源需求、 節(jié)點篩選器惕橙、 pod 親和性和互斥性瞧甩、 以及污點和容忍度。
以下插件支持動態(tài)供應(yīng)的 WaitForFirstConsumer 模式:
- AWSElasticBlockStore
- GCEPersistentDisk
- AzureDisk
以下插件支持預(yù)創(chuàng)建綁定 PersistentVolume 的 WaitForFirstConsumer 模式: - 上述全部
- Local
動態(tài)配置和預(yù)先創(chuàng)建的 PV 也支持 CSI卷弥鹦, 但是你需要查看特定 CSI 驅(qū)動程序的文檔以查看其支持的拓?fù)滏I名和例子肚逸。
允許的拓?fù)浣Y(jié)構(gòu)
當(dāng)集群操作人員使用了 WaitForFirstConsumer 的卷綁定模式, 在大部分情況下就沒有必要將制備限制為特定的拓?fù)浣Y(jié)構(gòu)彬坏。 然而朦促,如果還有需要的話,可以使用 allowedTopologies苍鲜。
這個例子描述了如何將供應(yīng)卷的拓?fù)湎拗圃谔囟ǖ膮^(qū)域思灰,在使用時應(yīng)該根據(jù)插件 支持情況替換 zone 和 zones 參數(shù)玷犹。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-standard
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
- key: failure-domain.beta.kubernetes.io/zone
values:
- us-central1-a
- us-central1-b
實戰(zhàn)演示
部署流程
搭建StorageClass + NFS混滔,大致有以下幾個步驟:
創(chuàng)建一個可用的NFS Server
創(chuàng)建Service Account,這是用來管控NFS Provisioner 在k8s集群中運行的權(quán)限
NFS provisioner是一個provisioner相關(guān)的插件歹颓,需要從網(wǎng)絡(luò)上下載坯屿,我們已經(jīng)下載下來放到鏡像庫中了
下載以后需要以pod方式運行通過deployment部署導(dǎo)入到本地環(huán)境中
image.png
創(chuàng)建StorageClass的時候需要指定provisioner
創(chuàng)建StorageClass,負(fù)責(zé)建立PVC并調(diào)用NFS provisioner進(jìn)行預(yù)定的工作巍扛,并讓PV與PVC建立關(guān)聯(lián)
創(chuàng)建NFS provisioner领跛,有兩個功能,一個是在NFS共享目錄下創(chuàng)建掛載點(volume)撤奸,另一個則是建了PV并將PV與NFS的掛載點建立關(guān)聯(lián)
創(chuàng)建Service Account
NFS Server在前面的章節(jié)中已經(jīng)安裝過了吠昭。
鑒權(quán)概述 官方文檔
使用 RBAC 鑒權(quán) 官方文檔
# rbac.yaml:#唯一需要修改的地方只有namespace,根據(jù)實際情況定義
apiVersion: v1
kind: ServiceAccount # 創(chuàng)建一個賬戶,主要用來管理NFS provisioner在k8s集群中運行的權(quán)限
metadata:
name: nfs-client-provisioner
namespace: default
---
kind: ClusterRole # 創(chuàng)建集群角色
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner # 角色名
rules: # 角色權(quán)限
- apiGroups: [""]
resources: ["persistentvolumes"] # 操作的資源
verbs: ["get", "list", "watch", "create", "delete"] # 對該資源的操作權(quán)限
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding # 集群角色綁定
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects: # 角色綁定對象
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: ClusterRole # 哪個角色
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role # 創(chuàng)建角色
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner # 角色名
namespace: default # Role需要指定名稱空間胧瓜,ClusterRole 不需要
rules: # 角色權(quán)限
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding # 角色綁定
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
subjects: # 角色綁定對象
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef: # 綁定哪個角色
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
創(chuàng)建StorageClass矢棚,指定provisioner
#創(chuàng)建NFS資源的StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass # 創(chuàng)建StorageClass
metadata:
name: managed-nfs-storage
provisioner: qgg-nfs-storage #這里的名稱要和provisioner配置文件中的環(huán)境變量PROVISIONER_NAME保持一致
parameters:
archiveOnDelete: "false"
# 創(chuàng)建NFS provisioner
apiVersion: apps/v1
kind: Deployment # 部署nfs-client-provisioner
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
namespace: default #與RBAC文件中的namespace保持一致
spec:
replicas: 1
selector:
matchLabels:
app: nfs-client-provisioner
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner # 指定serviceAccount!
containers:
- name: nfs-client-provisioner
image: hub.kaikeba.com/java12/nfs-client-provisioner:v1 #鏡像地址
volumeMounts: # 掛載數(shù)據(jù)卷到容器指定目錄
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME # 配置provisioner的Name
value: qgg-nfs-storage # 確保該名稱與 StorageClass 資源中的provisioner名稱保持一致
- name: NFS_SERVER #綁定的nfs服務(wù)器
value: 192.168.66.13
- name: NFS_PATH #綁定的nfs服務(wù)器目錄
value: /opt/k8s
volumes: # 申明nfs數(shù)據(jù)卷
- name: nfs-client-root
nfs:
server: 192.168.66.13
path: /opt/k8s
創(chuàng)建pod測試
創(chuàng)建pod,申明PVC進(jìn)行測試
# 申明一個PVC府喳,指定StorageClass
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
annotations:
# 通過annotations注解蒲肋,和storage-class進(jìn)行關(guān)聯(lián),為什么不使用storageClassName,因為版本比較低
# 這里指定的名字就是上面創(chuàng)建的StorageClass的名字兜粘,讓它幫我們創(chuàng)建PV
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
---
# 創(chuàng)建測試pod,查看是否可以正常掛載
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox:1.24
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1" #創(chuàng)建一個SUCCESS文件后退出
volumeMounts:
- name: nfs-pvc # 掛載數(shù)據(jù)卷
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim: # 數(shù)據(jù)卷掛載的是pvc
claimName: test-claim #與PVC名稱保持一致
測試是否會幫我自動創(chuàng)建pv:
看到自動創(chuàng)建了一個PV與PVC進(jìn)行綁定申窘。
清除環(huán)境
集合StatefulSet測試
StatefulSet+volumeClaimTemplates自動創(chuàng)建PV:
# StateFulDet+volumeClaimTemplates自動創(chuàng)建PV
---
apiVersion: v1
kind: Service
metadata:
name: nginx-headless
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: ikubernetes/myapp:v1
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: # 通過模板化方式綁定
- metadata:
name: www # 指定pvc的名字
annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" #只指定了storageClass
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
看到是有序依次創(chuàng)建:
看到pvc是自動創(chuàng)建的,pv也是: