k8s數(shù)據(jù)管理(七)

volume

我們經(jīng)常會(huì)說(shuō):容器和 Pod 是短暫的。
其含義是它們的生命周期可能很短,會(huì)被頻繁地銷毀和創(chuàng)建。容器銷毀時(shí),保存在容器內(nèi)部文件系統(tǒng)中的數(shù)據(jù)都會(huì)被清除。

為了持久化保存容器的數(shù)據(jù),可以使用 Kubernetes Volume。

Volume 的生命周期獨(dú)立于容器,Pod 中的容器可能被銷毀和重建,但 Volume 會(huì)被保留。

本質(zhì)上,Kubernetes Volume 是一個(gè)目錄,這一點(diǎn)與 Docker Volume 類似。當(dāng) Volume 被 mount 到 Pod,Pod 中的所有容器都可以訪問(wèn)這個(gè) Volume。Kubernetes Volume 也支持多種 backend 類型,包括 emptyDir、hostPath、GCE Persistent Disk、AWS Elastic Block Store、NFS、Ceph 等,完整列表可參考 https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes

Volume 提供了對(duì)各種 backend 的抽象,容器在使用 Volume 讀寫數(shù)據(jù)的時(shí)候不需要關(guān)心數(shù)據(jù)到底是存放在本地節(jié)點(diǎn)的文件系統(tǒng)中呢還是云硬盤上。對(duì)它來(lái)說(shuō),所有類型的 Volume 都只是一個(gè)目錄。

emptyDir

emptyDir 是最基礎(chǔ)的 Volume 類型。一個(gè) emptyDir Volume 是 Host 上的一個(gè)空目錄。

emptyDir Volume 對(duì)于容器來(lái)說(shuō)是持久的,對(duì)于 Pod 則不是。當(dāng) Pod 從節(jié)點(diǎn)刪除時(shí),Volume 的內(nèi)容也會(huì)被刪除。但如果只是容器被銷毀而 Pod 還在,則 Volume 不受影響。

也就是說(shuō):emptyDir Volume 的生命周期與 Pod 一致。

Pod 中的所有容器都可以共享 Volume,它們可以指定各自的 mount 路徑。

下面通過(guò)例子來(lái)實(shí)踐 emptyDir

第一步:配置文件如下:

image

這里我們模擬了一個(gè) producer-consumer 場(chǎng)景。Pod 有兩個(gè)容器 producer和 consumer,它們共享一個(gè) Volume。producer 負(fù)責(zé)往 Volume中寫數(shù)據(jù),consumer 則是從 Volume 讀取數(shù)據(jù)。

① 文件最底部 volumes 定義了一個(gè) emptyDir 類型的 Volume shared-volume。

② producer 容器將 shared-volume mount 到 /producer_dir 目錄。

③ producer 通過(guò) echo 將數(shù)據(jù)寫到文件 hello 里。

④ consumer 容器將 shared-volume mount 到 /consumer_dir 目錄。

⑤ consumer 通過(guò) cat 從文件 hello 讀數(shù)據(jù)。

第二步:執(zhí)行如下命令創(chuàng)建 Pod:

[root@ken ~]# kubectl get pod
NAME                READY   STATUS    RESTARTS   AGE
producer-consumer   2/2     Running   0          2m1s
[root@ken ~]# kubectl logs producer-consumer consumer
hello world

注意:一個(gè)pod里面運(yùn)行多個(gè)容器的時(shí)候,查看容器日志,需要指定pod名稱及容器名

kubectl logs 顯示容器 consumer 成功讀到了 producer 寫入的數(shù)據(jù),驗(yàn)證了兩個(gè)容器共享 emptyDir Volume。

因?yàn)?emptyDir 是 Docker Host 文件系統(tǒng)里的目錄,其效果相當(dāng)于執(zhí)行了 docker run -v /producer_dir 和 docker run -v /consumer_dir。

第三步:通過(guò) docker inspect 查看容器的詳細(xì)配置信息,我們發(fā)現(xiàn)兩個(gè)容器都 mount 了同一個(gè)目錄:

image

image

這里 /var/lib/kubelet/pods/4dcc0366-245f-11e9-9172-000c292d5bb8/volumes/kubernetes.io~empty-dir/shared-volume 就是 emptyDir在 Host 上的真正路徑。

emptyDir 是 Host 上創(chuàng)建的臨時(shí)目錄,其優(yōu)點(diǎn)是能夠方便地為 Pod 中的容器提供共享存儲(chǔ),不需要額外的配置。但它不具備持久性,如果 Pod 不存在了,emptyDir 也就沒(méi)有了。根據(jù)這個(gè)特性,emptyDir 特別適合 Pod 中的容器需要臨時(shí)共享存儲(chǔ)空間的場(chǎng)景,比如前面的生產(chǎn)者消費(fèi)者用例。

hostpath

hostPath Volume 的作用是將 Docker Host 文件系統(tǒng)中已經(jīng)存在的目錄 mount 給 Pod 的容器。大部分應(yīng)用都不會(huì)使用 hostPath Volume,因?yàn)檫@實(shí)際上增加了 Pod 與節(jié)點(diǎn)的耦合,限制了 Pod 的使用。不過(guò)那些需要訪問(wèn) Kubernetes 或 Docker 內(nèi)部數(shù)據(jù)(配置文件和二進(jìn)制庫(kù))的應(yīng)用則需要使用 hostPath。

比如 kube-apiserver 和 kube-controller-manager 就是這樣的應(yīng)用,通過(guò)

kubectl edit –namespace=kube-system pod kube-apiserver-k8s-master

查看 kube-apiserver Pod 的配置,下面是 Volume 的相關(guān)部分:

**
image

**

這里定義了三個(gè) hostPath volume k8s、certs 和 pki,分別對(duì)應(yīng) Host 目錄 /etc/kubernetes、/etc/ssl/certs 和 /etc/pki。

如果 Pod 被銷毀了,hostPath 對(duì)應(yīng)的目錄也還會(huì)被保留,從這點(diǎn)看,hostPath 的持久性比 emptyDir 強(qiáng)。不過(guò)一旦 Host 崩潰,hostPath 也就沒(méi)法訪問(wèn)了。

示例:把節(jié)點(diǎn)上的tmp目錄掛載到容器中

第一步:編寫yml文件

[root@ken-node1 ~]# cat hostpath.yml 
apiVersion: v1
kind: Pod
metadata:
   name: myhostpath
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: hostpath
      mountPath: /usr/share/nginx/html
  volumes:
  - name: hostpath
    hostPath:
      path: /tmp
      type: Directory

啟動(dòng)nginx,把主機(jī)的/tmp目錄掛載到nginx容器的網(wǎng)站根目錄

這里共享的是tmp目錄,如果是掛載其他的目錄要確保節(jié)點(diǎn)有這個(gè)目錄

第二步:?jiǎn)?dòng)

[root@ken-node1 ~]# kubectl apply -f hostpath.yml

第三步:在tmp目錄下編寫測(cè)試文件

[root@ken-node1 ~]# echo "hostpath" > /tmp/index.html

第四步:查看podIP并嘗試訪問(wèn)

[root@ken-node1 ~]# kubectl get pods -o wide
NAME                         READY   STATUS             RESTARTS   AGE     IP            NODE        NOMINATED NODE   READIN
myhostpath                   1/1     Running            0          8m8s    10.244.1.59   ken-node2   <none>           <none>

第五步:訪問(wèn)

[root@ken-node1 ~]# curl 10.244.1.59
hostpath

對(duì)接NFS

第一步:在控制節(jié)點(diǎn)部署NFS

[root@ken-node1 ~]# yum install nfs-utils rpcbind -y
[root@ken-node1 ~]# rm -rf /ken
[root@ken-node1 ~]# mkdir /ken
[root@ken-node1 ~]# chown -R nfsnobody: /ken
[root@ken-node1 ~]# echo "/ken *(rw)" > /etc/exports
[root@ken-node1 ~]# systemctl restart nfs rpcbind

第二步:編寫yml文件

[root@ken-node1 ~]# cat nfs.yml 
apiVersion: v1
kind: Pod
metadata:
  name: nfs
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: nfsback
      mountPath: /usr/share/nginx/html
  volumes:
    - name: nfsback
      nfs:
        path: /ken
        server: 192.168.163.132

第三步:節(jié)點(diǎn)需要下載nfs-utils去支持nfs文件類型,否則會(huì)報(bào)錯(cuò)

[root@ken-node2 ~]# yum install nfs-utils -y

第四步:執(zhí)行yml文件

[root@ken-node1 ~]# kubectl apply -f nfs.yml

第五步:查看pod的IP

[root@ken-node1 ~]# kubectl get pods -o wide
NAME                         READY   STATUS             RESTARTS   AGE     IP            NODE        NOMINATED NODE   READINESS GATES
nfs                          1/1     Running            0          3m3s    10.244.2.61   ken-node3   <none>           <none>

第六步:編寫測(cè)試文件在/ken共享目錄下

[root@ken-node1 ~]# echo "nfs" > /ken/index.html

第七步: 訪問(wèn)測(cè)試

[root@ken-node1 ~]# curl 10.244.2.61
nfs

PV & PVC

PersistentVolume (PV) 是外部存儲(chǔ)系統(tǒng)中的一塊存儲(chǔ)空間,由管理員創(chuàng)建和維護(hù)。與 Volume 一樣,PV 具有持久性,生命周期獨(dú)立于 Pod。

PersistentVolumeClaim (PVC) 是對(duì) PV 的申請(qǐng) (Claim)。PVC 通常由普通用戶創(chuàng)建和維護(hù)。需要為 Pod 分配存儲(chǔ)資源時(shí),用戶可以創(chuàng)建一個(gè) PVC,指明存儲(chǔ)資源的容量大小和訪問(wèn)模式(比如只讀)等信息,Kubernetes 會(huì)查找并提供滿足條件的 PV。

有了 PersistentVolumeClaim,用戶只需要告訴 Kubernetes 需要什么樣的存儲(chǔ)資源,而不必關(guān)心真正的空間從哪里分配,如何訪問(wèn)等底層細(xì)節(jié)信息。這些 Storage Provider 的底層信息交給管理員來(lái)處理,只有管理員才應(yīng)該關(guān)心創(chuàng)建 PersistentVolume 的細(xì)節(jié)信息。

Kubernetes 支持多種類型的 PersistentVolume,比如 AWS EBS、Ceph、NFS 等,完整列表請(qǐng)參考 https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes

NFS PV

第一步:需在 k8s-master 節(jié)點(diǎn)上搭建了一個(gè) NFS 服務(wù)器,目錄為 /nfsdata:

要更改目錄屬主,否則沒(méi)有寫入權(quán)限: chown -R nfsnobody.nfsnobody /nfsdata

注意:

  1. nfs可以安裝在任意節(jié)點(diǎn),不一定是在k8s集群當(dāng)中的一臺(tái)服務(wù)器
  2. k8s集群內(nèi)的每臺(tái)節(jié)點(diǎn)必須都要安裝nfs-utils否則識(shí)別不到nfs類型
[root@ken ~]# showmount -e
Export list for ken:
/nfsdata *

第二步:創(chuàng)建一個(gè) PV mypv1,配置文件 nfs-pv1.yml 如下:

[root@ken ~]# cat nfs-pv1.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv1
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /nfsdata/pv1   #需要?jiǎng)?chuàng)建pv1目錄,否則pod起不來(lái)
    server: 172.20.10.2

① capacity 指定 PV 的容量為 1G。

② accessModes 指定訪問(wèn)模式為 ReadWriteOnce,支持的訪問(wèn)模式有:

ReadWriteOnce – PV 能以 read-write 模式 mount 到單個(gè)節(jié)點(diǎn)。

ReadOnlyMany – PV 能以 read-only 模式 mount 到多個(gè)節(jié)點(diǎn)。

ReadWriteMany – PV 能以 read-write 模式 mount 到多個(gè)節(jié)點(diǎn)。

③ persistentVolumeReclaimPolicy 指定當(dāng) PV 的回收策略為 Recycle,支持的策略有:

Retain – 需要管理員手工回收。

Recycle – 清除 PV 中的數(shù)據(jù),效果相當(dāng)于執(zhí)行 rm -rf /thevolume/*。

Delete – 刪除 Storage Provider 上的對(duì)應(yīng)存儲(chǔ)資源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。

④ storageClassName 指定 PV 的 class 為 nfs。相當(dāng)于為 PV 設(shè)置了一個(gè)分類,PVC 可以指定 class 申請(qǐng)相應(yīng) class 的 PV。

⑤ 指定 PV 在 NFS 服務(wù)器上對(duì)應(yīng)的目錄。

第三步:創(chuàng)建 mypv1:

[root@ken ~]# kubectl apply -f nfs-pv1.yml
persistentvolume/mypv1 created

第四步:查看pv

[root@ken ~]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
mypv1   1Gi        RWO            Recycle          Available           nfs                     48s

STATUS 為 Available,表示 mypv1 就緒,可以被 PVC 申請(qǐng)。

第五步:接下來(lái)創(chuàng)建 PVC mypvc1,配置文件 nfs-pvc1.yml 如下:

注意:

1. 各個(gè)節(jié)點(diǎn)都需要下載nfs-utils

[root@ken-node1 ~]# cat pvc.yml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
   requests:
     storage: 1Gi
  volumeName: mypv   #pv名字

PVC 就很簡(jiǎn)單了,只需要指定 PV 的容量,訪問(wèn)模式和 class。

[root@ken ~]# kubectl apply -f nfs-pvc1.yml
persistentvolumeclaim/mypvc1 created

第六步:查看pvc

[root@ken ~]# kubectl get pvc
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc1   Bound    mypv1    1Gi        RWO            nfs            112s
[root@ken ~]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
mypv1   1Gi        RWO            Recycle          Bound    default/mypvc1   nfs                     6m5s

從 kubectl get pvc 和 kubectl get pv 的輸出可以看到 mypvc1 已經(jīng) Bound 到 mypv1,申請(qǐng)成功。

第七步:接下來(lái)就可以在 Pod 中使用存儲(chǔ)了,Pod 配置文件 pod1.yml 如下:

image

與使用普通 Volume 的格式類似,在 volumes 中通過(guò) persistentVolumeClaim 指定使用 mypvc1 申請(qǐng)的 Volume。

第八步:創(chuàng)建 mypod1:

[root@ken ~]# kubectl apply -f pod1.yml
pod/mypod1 created

[root@ken ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mypod1 1/1 Running 0 51s 10.244.1.59 host1 <none> <none>

第九步:驗(yàn)證 PV 是否可用:

[root@ken ~]# kubectl exec mypod1 touch /mydata/hello

[root@ken ~]# ls /nfsdata/pv1/
hello

可見(jiàn),在 Pod 中創(chuàng)建的文件 /mydata/hello 確實(shí)已經(jīng)保存到了 NFS 服務(wù)器目錄 /nfsdata/pv1 中。

回收PV

當(dāng) PV 不再需要時(shí),可通過(guò)刪除 PVC 回收。

當(dāng) PVC mypvc1 被刪除后,Kubernetes 啟動(dòng)了一個(gè)新 Pod recycler-for-mypv1,這個(gè) Pod 的作用就是清除 PV mypv1 的數(shù)據(jù)。此時(shí) mypv1 的狀態(tài)為 Released,表示已經(jīng)解除了與 mypvc1 的 Bound,正在清除數(shù)據(jù),不過(guò)此時(shí)還不可用。

當(dāng)數(shù)據(jù)清除完畢,mypv1 的狀態(tài)重新變?yōu)?Available,此時(shí)則可以被新的 PVC 申請(qǐng)。

因?yàn)?PV 的回收策略設(shè)置為 Recycle,所以數(shù)據(jù)會(huì)被清除,但這可能不是我們想要的結(jié)果。如果我們希望保留數(shù)據(jù),可以將策略設(shè)置為 Retain。

第一步:將策略設(shè)置為 Retain。

[root@ken ~]# cat nfs-pv1.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv1
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /nfsdata/pv1
    server: 172.20.10.2

第二步:通過(guò) kubectl apply 更新 PV:

root@ken ~]# kubectl apply -f nfs-pv1.yml
persistentvolume/mypv1 configured
[root@ken ~]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
mypv1   1Gi        RWO            Retain           Available                        nfs                     65m

回收策略已經(jīng)變?yōu)?Retain,通過(guò)下面步驟驗(yàn)證其效果:

① 重新創(chuàng)建 mypvc1。

② 在 mypv1 中創(chuàng)建文件 hello。

mypv1 狀態(tài)變?yōu)?Released

④ Kubernetes 并沒(méi)有啟動(dòng) Pod recycler-for-mypv1。

⑤ PV 中的數(shù)據(jù)被完整保留。

另外使用retain雖然刪除pod后的數(shù)據(jù)得到了保留,但其 PV 狀態(tài)會(huì)一直處于 Released,不能被其他 PVC 申請(qǐng)。為了重新使用存儲(chǔ)資源,可以刪除并重新創(chuàng)建 PV。刪除操作只是刪除了 PV 對(duì)象,存儲(chǔ)空間中的數(shù)據(jù)并不會(huì)被刪除。

新建的 mypv1 狀態(tài)為 Available,已經(jīng)可以被 PVC 申請(qǐng)。

小結(jié)

本章我們討論了 Kubernetes 如何管理存儲(chǔ)資源。

emptyDir 和 hostPath 類型的 Volume 很方便,但可持久性不強(qiáng),Kubernetes 支持多種外部存儲(chǔ)系統(tǒng)的 Volume。

PV 和 PVC 分離了管理員和普通用戶的職責(zé),更適合生產(chǎn)環(huán)境。

文章轉(zhuǎn)自: http://www.kendd.cn/?p=718

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容