一、引言
在使用K8S時總繞不開的話題就是K8S持久化存儲,要實作持久化資料,就要把資料存儲到硬碟上。在K8S持久化的過程中會有許多的概念PV、PVC、StorageClass、Provisioner等等。我隻想存儲一個檔案有麼有簡單的方式呢?答案是有的。
K8S環境下,Container 中的檔案在磁盤上是臨時存放的,當容器崩潰時檔案丢失。kubelet 會重新啟動容器, 但容器會以幹淨的狀态重新開機。是以我們要使用 Volume 來持久化資料。
Docker 也有 卷(Volume) 的概念,但對它隻有少量且松散的管理。 Docker 卷是磁盤上或者另外一個容器内的一個目錄 Docker 提供卷驅動程式,但是其功能非常有限。
Kubernetes 支援很多類型的卷。 Pod 可以同時使用任意數目的卷類型。
臨時卷類型的生命周期與 Pod 相同,但持久卷可以比 Pod 的存活期長。 當 Pod 不再存在時,Kubernetes 也會銷毀臨時卷;不過 Kubernetes 不會銷毀 持久卷。對于給定 Pod 中任何類型的卷,在容器重新開機期間資料都不會丢失。
卷的核心是一個目錄,其中可能存有資料,Pod 中的容器可以通路該目錄中的資料。 所采用的特定的卷類型将決定該目錄如何形成的、使用何種媒體儲存資料以及目錄中存放 的内容。 |
使用卷時,在 .spec.volumes 字段中設定為 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中聲明卷在容器中的挂載位置。 各個卷則挂載在鏡像内的指定路徑上。 卷不能挂載到其他卷之上,也不能與其他卷有硬連結。Pod 配置中的每個容器必須獨立指定各個卷的挂載位置。 |
二、K8S存儲的分類
2.1、Emptydir---臨時存儲
當pod的存儲方案設定為emptydir的時候,pod啟動時,就會在pod所在節點的磁盤空間開辟出一塊空卷,最開始裡面是什麼都沒有的,pod啟動後容器産生的資料會存放到那個空卷中。空卷變成了一個臨時卷供pod内的容器讀取和寫入資料,一旦pod容器消失,節點上開辟出的這個臨時卷就會随着pod的銷毀而銷毀。
Emptydir的用途
- 緩存空間,例如基于磁盤的歸并排序。
- 為耗時較長的計算任務提供檢查點,以便任務能友善地從崩潰前狀态恢複執行。
- 在 Web 伺服器容器服務資料時,儲存内容管理器容器擷取的檔案。
emptyDir配置示例
Go [root@k8s-master emptydir]# cat emptydir.yaml apiVersion: v1 kind: Pod metadata: name: test-pd spec: containers: - image: nginx name: test-container volumeMounts: - mountPath: /usr/share/nginx/html name: cache-volume volumes: - name: cache-volume emptyDir: {} |
建立和驗證
Go [root@k8s-master emptydir]# kubectl apply -f emptydir.yaml pod/test-pd created [root@k8s-master emptydir]# kubectl get pod -owide |grep test-pd test-pd 1/1 Running 0 29s 10.244.2.172 k8s-node2 <none> <none> #1、在K8S-node2上進行操作 [root@k8s-node2 cache-volume]# docker ps -a|grep test-pd ec7a0faec6bb nginx "/docker-entrypoint.…" 3 minutes ago Up 3 minutes k8s_test-container_test-pd_default_0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae_0 #2、檢視容器的詳細資訊 [root@k8s-node2 ~]# docker inspect f87f032bbaf8 .... "Mounts": [ { "Type": "bind", "Source": "/home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume", "Destination": "/usr/share/nginx/html", "Mode": "", "RW": true, "Propagation": "rprivate" }, ...... ###Source是主控端的位址 ###Destination是挂載到容器的位址 #3、進入主控端的目錄并建立檔案 [root@k8s-node2 cache-volume]# ls /home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume [root@k8s-node2 cache-volume]# cd /home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume [root@k8s-node2 cache-volume]# echo date > index.html [root@k8s-node2 cache-volume]# cat index.html date ##通路該pod的IP位址 [root@k8s-node2 cache-volume]# curl 10.244.2.173 date [root@k8s-node2 cache-volume]# date > index.html [root@k8s-node2 cache-volume]# curl 10.244.2.173 Sun Jun 5 17:02:30 CST 2022 ###建立其他的通路檔案 [root@k8s-node2 cache-volume]# echo 2022-06-05 > test.html [root@k8s-node2 cache-volume]# curl 10.244.2.173/test.html 2022-06-05 #4、删除對應的pod清除實驗。 [root@k8s-master emptydir]# kubectl delete -f emptydir.yaml pod "test-pd" deleted ###再次在node2計算節點上檢視 [root@k8s-node2 cache-volume]# ls /home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume ls: cannot access /home/k8s/kubelet/pods/0e27bcf4-7ebe-4dc3-b48a-3230cf7641ae/volumes/kubernetes.io~empty-dir/cache-volume: No such file or directory #emptydir是随pod建立而建立,然後再随pod删除而删除 |
2.2、hostPath
hostPath 卷能将主機節點檔案系統上的檔案或目錄挂載到你的 Pod 中, 雖然這不是大多數 Pod 需要的,但是它為一些應用程式提供了強大的逃生艙。
hostPath的用途
- 運作一個需要通路 Docker 内部機制的容器;可使用 hostPath 挂載/var/lib/docker 路徑。
- 在容器中運作 cAdvisor 時,以 hostPath 方式挂載/sys。
- 允許 Pod 指定給定的 hostPath 在運作 Pod 之前是否應該存在,是否應該建立以及應該以什麼方式存在。
Type的值
除了必需的path 屬性之外,使用者可以選擇性地為hostPath 卷指定type。
支援的type 值如下:
取值 | 行為 |
空 | 空字元串(預設)用于向後相容,這意味着在安裝 hostPath 卷之前不會執行任何檢查。 |
DirectoryOrCreate | 如果在給定路徑上什麼都不存在,那麼将根據需要建立空目錄,權限設定為 0755,具有與 kubelet 相同的組和屬主資訊。 |
Directory | 在給定路徑上必須存在的目錄。 |
FileOrCreate | 如果在給定路徑上什麼都不存在,那麼将在那裡根據需要建立空檔案,權限設定為 0644,具有與 kubelet 相同的組和所有權。 |
File | 在給定路徑上必須存在的檔案。 |
Socket | 在給定路徑上必須存在的 UNIX 套接字。 |
CharDevice | 在給定路徑上必須存在的字元裝置。 |
BlockDevice | 在給定路徑上必須存在的塊裝置。 |
hostPath配置示例
Go [root@k8s-master hostpath]# cat hostpath.yaml apiVersion: v1 kind: Pod metadata: name: test-pd spec: containers: - image: nginx name: test-container volumeMounts: - mountPath: /usr/share/nginx/html name: test-hostpath volumes: - name: test-hostpath hostPath: path: /data type: DirectoryOrCreate |
建立和配置示例
Go #1、建立pod [root@k8s-master hostpath]# kubectl apply -f hostpath.yaml pod/test-pd created [root@k8s-master hostpath]# kubectl get pod -owide|grep test-pd test-pd 1/1 Running 0 6m54s 10.244.2.174 k8s-node2 <none> <none> #2、在K8S-node2節點上檢視内部 [root@k8s-node2 data]# docker ps -a|grep test-container b4ff1de7e371 nginx "/docker-entrypoint.…" 8 minutes ago Up 8 minutes k8s_test-container_test-pd_default_e48b2791-54d6-40d6-bc77-56328ca4c038_0 [root@k8s-node2 data]# docker inspect b4ff1de7e371 [ .... "Mounts": [ { "Type": "bind", "Source": "/data", "Destination": "/usr/share/nginx/html", "Mode": "", "RW": true, "Propagation": "rprivate" }, .... ] ##"Source": "/data", # 主控端的目錄 ## "Destination": "/usr/share/nginx/html", # 容器中的目錄 #3、在master節點上進入pod [root@k8s-master hostpath]# kubectl exec -it pod/test-pd /bin/bash kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. root@test-pd:/# cd /usr/share/nginx/html root@test-pd:/usr/share/nginx/html# ls index.html root@test-pd:/usr/share/nginx/html# echo date >> index.html root@test-pd:/usr/share/nginx/html# cat index.html Sun Jun 5 17:23:17 CST 2022 test hostpath date [root@k8s-master hostpath]# curl 10.244.2.174 Sun Jun 5 17:23:17 CST 2022 test hostpath date #4、删除pod [root@k8s-master hostpath]# kubectl delete -f hostpath.yaml pod "test-pd" deleted [root@k8s-master hostpath]# kubectl delete -f hostpath.yaml Error from server (NotFound): error when deleting "hostpath.yaml": pods "test-pd" not found #5、重新開機建立pod [root@k8s-master hostpath]# kubectl apply -f hostpath.yaml pod/test-pd created [root@k8s-master hostpath]# kubectl get pod -owide|grep test-pd test-pd 1/1 Running 0 63s 10.244.2.175 k8s-node2 <none> <none> [root@k8s-master hostpath]# curl 10.244.2.175 Sun Jun 5 17:23:17 CST 2022 test hostpath date ###這種方式如果主控端一直在的話,或者該pod一直被排程到該節點的話,可以實作pod的存儲,如果該node停機維護或其他 問題,該資料就無法保持了。 |
2.3、pv、pvc
既然Host類型的持久化存儲無法解決節點當機或者pod在另外的機器上拉起導緻資料無法恢複的Bug,那我們就應該思考一個問題:既然我無法在主控端持久化,那我在叢集之外的伺服器上存儲資料,讓我的Pod關聯到這個資料存儲伺服器上,同時我對這個資料存儲伺服器做高可用,豈不美哉? 想法很好,那我們來介紹一下K8S給我們的解決方案: PersistentVolumes 簡稱PV
- PV(PersistentVolume): 持久化卷。PV 是對底層共享存儲的一種抽象,由管理者進行建立和配置,它和具體的底層的共享存儲技術的實作方式有關,比如 Ceph、GlusterFS、NFS、hostPath 等,都是通過插件機制完成與共享存儲的對接。
- PVC(PersistentVolumeClaim): 持久化卷聲明。PVC 是使用者存儲的一種聲明,PVC 和 Pod 比較類似,Pod 消耗的是節點,PVC 消耗的是 PV 資源,Pod 可以請求 CPU 和記憶體,而 PVC 可以請求特定的存儲空間和通路模式。對于真正使用存儲的使用者不需要關心底層的存儲實作細節,隻需要直接使用 PVC 即可。
hostpath建立pv、pvc
Go #1、建立pv [root@k8s-master volumes]# cat pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: nginx-pv-volume labels: type: local spec: storageClassName: manual-nginx capacity: storage: 5Gi accessModes: - ReadWriteOnce hostPath: path: "/home/nfs" [root@k8s-master volumes]# kubectl apply -f pv.yaml persistentvolume/nginx-pv-volume created [root@k8s-master ~]# kubectl get pv -owide NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE nginx-pv-volume 5Gi RWO Retain Available manual-nginx 10s Filesystem ##可以看到這個PV為10G,通路模式為RWO,解除安裝後保留,目前的STATUS為可用狀态。 #2、建立pvc [root@k8s-master volumes]# kubectl apply -f pvc.yaml persistentvolumeclaim/nginx-pv-claim created [root@k8s-master volumes]# cat pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nginx-pv-claim spec: storageClassName: manual-nginx accessModes: - ReadWriteOnce resources: requests: storage: 3Gi [root@k8s-master volumes]# kubectl get pv,pvc -owide|grep pv-claim persistentvolume/nginx-pv-volume 5Gi RWO Retain Bound default/nginx-pv-claim manual-nginx 5m54s Filesystem persistentvolumeclaim/nginx-pv-claim Bound nginx-pv-volume 5Gi RWO manual-nginx 97s Filesystem 3、建立pod [root@k8s-master volumes]# cat pvc-pod.yaml apiVersion: v1 kind: Pod metadata: name: task-pv-pod spec: volumes: - name: nginx-pv-volume persistentVolumeClaim: claimName: nginx-pv-claim containers: - name: task-pv-container image: nginx:1.7.9 ports: - containerPort: 80 name: "http-server" volumeMounts: - mountPath: "/usr/share/nginx/html" name: nginx-pv-volume nodeSelector: kubernetes.io/hostname: k8s-node6 [root@k8s-master volumes]# kubectl apply -f pvc-pod.yaml pod/task-pv-pod created [root@k8s-master volumes]# kubectl get pod -owide|grep task-pv-pod task-pv-pod 1/1 Running 0 20s 10.244.4.117 k8s-node6 <none> <none> #3、在k8s-node3中執行 [root@k8s-node6 ~]# hostname > /home/nfs/index.html [root@k8s-node6 ~]# curl 10.244.4.117 k8s-node6 |
NFS建立pv pvc
大多數情況下,持久化 Volume 的實作,往往依賴于一個遠端存儲服務,比如:遠端檔案存儲(比如,NFS、GlusterFS)、遠端塊存儲(比如,公有雲提供的遠端磁盤)等等。
Go 1、搭建nfs伺服器 yum -y install nfs-utils rpcbind [root@k8s-master ~]# vim /etc/exports /data/k8s *(rw,sync,no_root_squash) [root@k8s-master ~]# systemctl enable rpcbind [root@k8s-master ~]# systemctl start rpcbind [root@k8s-master ~]# systemctl status rpcbind ####在啟動nfs [root@k8s-master ~]# systemctl enable nfs Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service. [root@k8s-master ~]# systemctl start nfs [root@k8s-master ~]# systemctl status nfs 用戶端挂在 [root@k8s-node1 ~]# mkdir /data/k8s/ -p [root@k8s-node1 ~]# mount -t nfs 172.16.4.169:/data/k8s /data/k8s 2、建立pv和pvc [root@k8s-master volumes]# kubectl apply -f nfs-pv.yaml persistentvolume/nginx-nfs-pv created [root@k8s-master volumes]# cat nfs-pv.yaml apiVersion: v1 kind: PersistentVolume # 類型為PV metadata: name: nginx-nfs-pv # pv的名稱 spec: accessModes: # 通路模式 - ReadWriteMany # PV以read-write挂載到多個節點 capacity: # 容量 storage: 2Gi # pv可用的大小 nfs: path: /home/k8s/nfs # NFS的路徑 server: 172.16.4.169 # NFS伺服器位址 ##建立pvc [root@k8s-master volumes]# cat nfs-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim # 類型 metadata: name: nginx-nfs-pvc # PVC的名稱 spec: accessModes: # 通路模式 - ReadWriteMany # PVC以read-write挂載到多個節點 resources: requests: storage: 2Gi # PVC允許申請的大小 [root@k8s-master volumes]# kubectl apply -f nfs-pvc.yaml persistentvolumeclaim/nginx-nfs-pvc created [root@k8s-master ~]# kubectl get pv,pvc -owide|grep nfs persistentvolume/nginx-nfs-pv 2Gi RWX Retain Bound default/nginx-nfs-pvc 4m37s Filesystem persistentvolumeclaim/nginx-nfs-pvc Bound nginx-nfs-pv 2Gi RWX 53s Filesystem ##c建立pod [root@k8s-master volumes]# cat nfs-pod.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-nfs-pvc spec: selector: matchLabels: app: nginx-pvc template: metadata: labels: app: nginx-pvc spec: containers: - name: nginx-test-pvc image: nginx imagePullPolicy: IfNotPresent ports: - name: web-port containerPort: 80 protocol: TCP volumeMounts: - name: nginx-persistent-storage # 取個名字,與下面的volumes的名字要一緻 mountPath: /usr/share/nginx/html # 容器中的路徑 volumes: - name: nginx-persistent-storage persistentVolumeClaim: claimName: nginx-nfs-pvc # 引用前面聲明的PVC [root@k8s-master volumes]# kubectl apply -f nfs-pod.yaml deployment.apps/nginx-nfs-pvc created [root@k8s-master volumes]# kubectl get pod -owide|grep nfs nginx-nfs-pvc-577dbd6d5-jsjqf 1/1 Running 0 2m32s 10.244.2.183 k8s-node2 <none> <none> [root@k8s-master volumes]# curl 10.244.2.183 Thu May 12 19:26:48 CST 2022 this is mater 4、回收的順序為:先删除pod,在删除pvc,檢視pv的時候pv的狀态為:Released ,如果變為avaiable, 則需要删除claimRef:字段下的所有配置。 |
2.4、StorageClass
建立PV有兩種方式:一種是人工管理 PV 的方式就叫作 Static Provisioning;另一種是Dynamic Provisioning動态建立存儲卷,動态供給的關鍵就是StorageClass,它的作用就是建立PV模闆,Provision意為”提供者。 |
建立StorageClass裡面需要定義PV屬性比如存儲類型、大小等;另外建立這種PV需要用到存儲插件。最終效果是,使用者送出PVC,裡面指定存儲類型,如果符合我們定義的StorageClass,則會為其自動建立PV并進行綁定。 |
什麼是StorageClass
StorageClass 為管理者提供了描述存儲 "class(類)" 的方法。 不同的 class 可能會映射到不同的服務品質等級或備份政策,或由群集管理者确定的任意政策。
Kubernetes提供了一套可以自動建立PV的機制,即:Dynamic Provisioning。而這個機制的核心在于StorageClass這個API對象。
StorageClass對象會定義下面兩部分内容:
- PV的屬性。比如,存儲類型,Volume的大小等。
- 建立這種PV需要用到的存儲插件,即存儲制備器,比如,Ceph 等等。
有了這兩個資訊之後,Kubernetes就能夠根據使用者送出的PVC,找到一個對應的StorageClass,之後Kubernetes就會調用該StorageClass聲明的存儲插件,進而建立出需要的PV。
StorageClass 為管理者提供了描述存儲 “類” 的方法。 不同的類型可能會映射到不同的服務品質等級或備份政策,或是由叢集管理者制定的任意政策。 Kubernetes 本身并不清楚各種類代表的什麼。這個類的概念在其他存儲系統中有時被稱為 “配置檔案”。
StorageClass的功能
StorageClass 的作用,則是充當 PV 的模闆。并且,隻有同屬于一個 StorageClass 的 PV 和 PVC,才可以綁定在一起。StorageClass 的另一個重要作用,是指定 PV 的 Provisioner(存儲插件)。這時候,如果你的存儲插件支援 Dynamic Provisioning 的話,Kubernetes 就可以自動為你建立 PV 了。
通過StorageClass建立pv和pvc例子
Go 1、建立pvc和storageclass的yaml檔案 [root@k8s-master storageclass]# cat storageclass-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: storageclass-claim1 spec: accessModes: - ReadWriteOnce # 指定所使用的存儲類,此存儲類将會自動建立符合要求的 PV storageClassName: fast resources: requests: storage: 30Gi --- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/gce-pd parameters: type: pd-ssd [root@k8s-master storageclass]# kubectl apply -f storageclass-pvc.yaml persistentvolumeclaim/storageclass-claim1 created storageclass.storage.k8s.io/fast created 2、檢視該pvc處于pending原因,由于沒有沒有gce插件 [root@k8s-master storageclass]# kubectl describe persistentvolumeclaim/storageclass-claim1 Name: storageclass-claim1 Namespace: default StorageClass: fast Status: Pending Volume: Labels: <none> Annotations: volume.beta.kubernetes.io/storage-provisioner: kubernetes.io/gce-pd Finalizers: [kubernetes.io/pvc-protection] Capacity: Access Modes: VolumeMode: Filesystem Used By: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning ProvisioningFailed 14m persistentvolume-controller storageclass.storage.k8s.io "fast" not found Warning ProvisioningFailed 68s (x10 over 13m) persistentvolume-controller Failed to provision volume with StorageClass "fast": failed to get GCE GCECloudProvider with error <nil> |
StorageClass 的作用,則是充當 PV 的模闆。并且,隻有同屬于一個 StorageClass 的 PV 和 PVC,才可以綁定在一起。StorageClass 的另一個重要作用,是指定 PV 的 Provisioner(存儲插件)。這時候,如果你的存儲插件支援 Dynamic Provisioning 的話,Kubernetes 就可以自動為你建立 PV 了。
2.5、Local PV(local-volume-provisioner)
Kubernetes 依靠 PV、PVC 實作了一個新的特性,這個特性的名字叫作:Local Persistent Volume,也就是 Local PV。
Local PV 實作的功能就非常類似于 hostPath 加上 nodeAffinity,比如,一個 Pod 可以聲明使用類型為 Local 的 PV,而這個 PV 其實就是一個 hostPath 類型的 Volume。如果這個 hostPath 對應的目錄,已經在節點 A 上被事先建立好了,那麼,我隻需要再給這個 Pod 加上一個 nodeAffinity=nodeA,不就可以使用這個 Volume 了嗎?理論上确實是可行的,但是事實上,我們絕不應該把一個主控端上的目錄當作 PV 來使用,因為本地目錄的存儲行為是完全不可控,它所在的磁盤随時都可能被應用寫滿,甚至造成整個主控端當機。是以,一般來說 Local PV 對應的存儲媒體是一塊額外在挂載在主控端的磁盤或者塊裝置,我們可以認為就是“一個 PV 一塊盤”。
local-volume-provisioner建立local PV
3.1、準備本地存儲
Go ##依次在K8S的各個計算節點依次執行 1、建立對應的目錄 mkdir /home/data/{data1,data2,data3} 2、依次挂載對應的節點 mount --bind /home/data/data1/ /home/data/data1/ mount --bind /home/data/data2/ /home/data/data2/ mount --bind /home/data/data3/ /home/data/data3/ 3、把相關的配置資訊寫道/etc/fstab echo UUID=`sudo blkid -s UUID -o value /dev/sda2` /home/data/data1 ext4 defaults 0 2 | sudo tee -a /etc/fstab echo UUID=`sudo blkid -s UUID -o value /dev/sda2` /home/data/data2 ext4 defaults 0 2 | sudo tee -a /etc/fstab echo UUID=`sudo blkid -s UUID -o value /dev/sda2` /home/data/data3 ext4 defaults 0 2 | sudo tee -a /etc/fstab ### 上述的/home/data/data1、/home/data/data2、/home/data/data13是 local-volume-provisioner 使用的發現目錄(discovery directory),local-volume-provisioner 會為發現目錄下的每一個 子目錄建立對應的 PV |
3.2、下載下傳和配置 local-volume-provisioner
Go 1、下載下傳 wget https://raw.githubusercontent.com/pingcap/tidb-operator/master/examples/local-pv/local-volume-provisioner.yaml 2、修改不同的路徑。如果你使用與上一步中不同路徑的發現目錄,需要修改 ConfigMap 和 DaemonSet 定義。 #cat local-volume-provisioner.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: "local-storage" provisioner: "kubernetes.io/no-provisioner" volumeBindingMode: "WaitForFirstConsumer" --- apiVersion: v1 kind: ConfigMap metadata: name: local-provisioner-config namespace: kube-system data: setPVOwnerRef: "true" nodeLabelsForPV: | - kubernetes.io/hostname storageClassMap: | local-storage: hostDir: /home/data mountDir: /data --- apiVersion: apps/v1 kind: DaemonSet metadata: name: local-volume-provisioner namespace: kube-system labels: app: local-volume-provisioner spec: selector: matchLabels: app: local-volume-provisioner template: metadata: labels: app: local-volume-provisioner spec: serviceAccountName: local-storage-admin containers: - image: "quay.io/external_storage/local-volume-provisioner:v2.3.4" name: provisioner securityContext: privileged: true env: - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: MY_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: JOB_CONTAINER_IMAGE value: "quay.io/external_storage/local-volume-provisioner:v2.3.4" resources: requests: cpu: 100m memory: 100Mi limits: cpu: 100m memory: 100Mi volumeMounts: - mountPath: /etc/provisioner/config name: provisioner-config readOnly: true - mountPath: /data name: local-disks mountPropagation: "HostToContainer" volumes: - name: provisioner-config configMap: name: local-provisioner-config - name: local-disks hostPath: path: /home/data --- apiVersion: v1 kind: ServiceAccount metadata: name: local-storage-admin namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: local-storage-provisioner-pv-binding namespace: kube-system subjects: - kind: ServiceAccount name: local-storage-admin namespace: kube-system roleRef: kind: ClusterRole name: system:persistent-volume-provisioner apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: local-storage-provisioner-node-clusterrole namespace: kube-system rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: local-storage-provisioner-node-binding namespace: kube-system subjects: - kind: ServiceAccount name: local-storage-admin namespace: kube-system roleRef: kind: ClusterRole name: local-storage-provisioner-node-clusterrole apiGroup: rbac.authorization.k8s.io |
如果你使用與上一步中不同路徑的發現目錄,需要修改 ConfigMap 和 DaemonSet 定義。
3.3、部署和檢查 local-volume-provisioner 程式
Go 1、部署 [root@k8s-master tidb]# kubectl apply -f local-volume-provisioner.yaml storageclass.storage.k8s.io/local-storage unchanged configmap/local-provisioner-config unchanged daemonset.apps/local-volume-provisioner unchanged serviceaccount/local-storage-admin unchanged clusterrolebinding.rbac.authorization.k8s.io/local-storage-provisioner-pv-binding unchanged clusterrole.rbac.authorization.k8s.io/local-storage-provisioner-node-clusterrole unchanged clusterrolebinding.rbac.authorization.k8s.io/local-storage-provisioner-node-binding unchanged 2、檢查pv和pod狀态 [root@k8s-master tidb]# kubectl get po -n kube-system -l app=local-volume-provisioner && kubectl get pv NAME READY STATUS RESTARTS AGE local-volume-provisioner-9gp9x 1/1 Running 0 29h local-volume-provisioner-kghc7 1/1 Running 0 29h local-volume-provisioner-v2vvt 1/1 Running 0 29h NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE local-pv-264b0ff0 446Gi RWO Delete Available local-storage 62m local-pv-27bc7b00 446Gi RWO Delete Available local-storage 62m local-pv-4653df42 446Gi RWO Delete Available local-storage 62m local-pv-993f4e47 446Gi RWO Delete Available local-storage 62m local-pv-ad7b1fa4 446Gi RWO Delete Available local-storage 62m local-pv-b9e5d531 446Gi RWO Delete Available local-storage 62m local-pv-bfe87b7 446Gi RWO Delete Available local-storage 62m local-pv-dc8fa7ee 446Gi RWO Delete Available local-storage 62m local-pv-f12d96bb 446Gi RWO Delete Available local-storage 62m |
三、總結
本文讨論了 k8s 存儲的幾種常見的存儲類型類型,有臨時存儲如:hostPath、emptyDir。也有真正的持久化存儲,還讨論了相關的概念,如:PVC、PV、StorageClass等,下圖是對這些概念的一個概括:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM1czX3xCZlhXam9VbsUmepNXZy9CXwJWZ3xCdh1mcvZ2Lc1zaHRGcWdUYuVzVa9GczoVdG1mWfVGc5RHLwIzX39GZhh2csATMflHLwEzX4xSZz91ZsAzMfRHLGZkRGZkRfJ3bs92YskmNhVTYykVNQJVMRhXVEF1X0hXZ0xiNx8VZ6l2cssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2IjZyUTNzMWMjhjYvwlNyIDMy8CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)