天天看點

K8S-資料持久化PV、PVC、StorageClass的關系

一、引言

在使用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的用途

  1. 緩存空間,例如基于磁盤的歸并排序。
  2. 為耗時較長的計算任務提供檢查點,以便任務能友善地從崩潰前狀态恢複執行。
  3. 在 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的用途

  1. 運作一個需要通路 Docker 内部機制的容器;可使用 hostPath 挂載/var/lib/docker 路徑。
  2. 在容器中運作 cAdvisor 時,以 hostPath 方式挂載/sys。
  3. 允許 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

  1. PV(PersistentVolume): 持久化卷。PV 是對底層共享存儲的一種抽象,由管理者進行建立和配置,它和具體的底層的共享存儲技術的實作方式有關,比如 Ceph、GlusterFS、NFS、hostPath 等,都是通過插件機制完成與共享存儲的對接。
  2. 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對象會定義下面兩部分内容:

  1. PV的屬性。比如,存儲類型,Volume的大小等。
  2. 建立這種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等,下圖是對這些概念的一個概括:

K8S-資料持久化PV、PVC、StorageClass的關系

繼續閱讀