03.01 k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

一、Volume

1. 概念

  Kubernetes的卷是pod的一個組成部分,因此像容器一樣在pod的規範中就定義了。它們不是獨立的Kubernetes對象,也不能單獨創建或刪除。pod中的所有容器都可以使用卷,但必須先將它掛載在每個需要訪問它的容器中。在每個容器中,都可以在其文件系統的任意位置掛載卷。

2. 為什麼需要Volume

  容器磁盤上的文件的生命週期是短暫的,這就使得在容器中運行重要應用時會出現一些問題。首先,當容器崩潰時,kubelet會重啟它,但是容器中的文件將丟失——容器以乾淨的狀態(鏡像最初的狀態)重新啟動。其次,在 Pod 中同時運行多個容器時,這些容器之間通常需要共享文件。Kubernetes 中的 Volume 抽象就很好的解決了這些問題。

3. Volume類型

目前,Kubernetes支持以下Volume 類型:

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

本文將對emptyDir,hostPath,共享存儲NFS,PV及PVC分別進行測試實踐。

二、emptyDir

1. emptyDir概念

  emptyDir是最基礎的Volume類型,用於存儲臨時數據的簡單空目錄。如果Pod設置了emptyDir類型Volume,Pod被分配到Node上時候,會創建emptyDir,只要Pod運行在Node上,emptyDir都會存在(容器掛掉不會導致emptyDir丟失數據),但是如果Pod從Node上被刪除(Pod被刪除,或者Pod發生遷移),emptyDir也會被刪除,並且永久丟失。

  下面將用emptyDir卷實現在同一pod中兩個容器之間的文件共享

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

2. 創建pod emptyDir-fortune

<code>[root@master ~]# more emptyDir-pod.yaml apiVersion: v1kind: Podmetadata:  labels:    app: prod                           #pod標籤   name: emptydir-fortunespec:  containers:  - image: loong576/fortune    name: html-generator    volumeMounts:                       #名為html的卷掛載至容器的/var/htdocs目錄    - name: html      mountPath: /var/htdocs  - image: nginx:alpine    name: web-server    volumeMounts:                       #掛載相同的卷至容器/usr/share/nginx/html目錄且設置為只讀    - name: html      mountPath: /usr/share/nginx/html       readOnly: true    ports:    - containerPort: 80      protocol: TCP  volumes:  - name: html                          #卷名為html的emptyDir卷同時掛載至以上兩個容器    emptyDir: {} [root@master ~]# kubectl apply -f emptyDir-pod.yaml pod/emptydir-fortune created[root@master ~]# kubectl get po -o wide             NAME               READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESemptydir-fortune   2/2     Running   0          9s    10.244.2.140   node02   <none>           <none>/<none>/<code>
k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

創建pod emptydir-fortune,該pod有兩個容器,同時掛載emptyDir卷,容器html-generator向卷中寫入隨機內容,通過訪問容器web-server驗證是否實現文件的共享。

2.1 loong576/fortune鏡像

root@master ~]# more Dockerfile

<code>[root@master ~]# more fortune/Dockerfile FROM ubuntu:latestRUN apt-get update ; apt-get -y install fortuneADD fortuneloop.sh /bin/fortuneloop.shE*TRYPOINT /bin/fortuneloop.sh/<code>

該鏡像的base鏡像為ubuntu,鏡像啟動時會執行fortuneloop.sh腳本

fortuneloop.sh腳本:

<code>[root@master ~]# more fortuneloop.sh #!/bin/bashtrap "exit" SIGINTmkdir /var/htdocswhile :do  echo $(date) Writing fortune to /var/htdocs/index.html  /usr/games/fortune > /var/htdocs/index.html  sleep 10done/<code>

該腳本主要是每10秒鐘輸出隨機短語至index.html文件中。

3. 訪問nginx

3.1 創建service

<code>[root@master ~]# more service-fortune.yaml apiVersion: v1kind: Servicemetadata:  name: my-service           #service名spec:  type: NodePort  selector:    app: prod                #pod標籤,由此定位到pod emptydir-fortune   ports:  - protocol: TCP    nodePort: 30002          #節點監聽端口,暴露靜態端口30002對外提供服務    port: 8881               #ClusterIP監聽的端口     targetPort: 80           #容器端口   sessionAffinity: ClientIP  #是否支持Session,同一個客戶端的訪問請求都轉發到同一個後端Pod [root@master ~]# kubectl apply -f service-fortune.yaml service/my-service created[root@master ~]# kubectl get svc NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGEkubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          3d17hmy-service   NodePort    10.102.191.57   <none>        8881:30002/TCP   9s/<none>/<none>/<code>

3.2 nginx訪問

<code>[root@master ~]# curl 10.102.191.57:8881Writing is easy; all you do is sit staring at the blank sheet of paper untildrops of blood form on your forehead.                -- Gene Fowler[root@master ~]# curl 172.27.9.135:30002Don't Worry, Be Happy.                -- Meher Baba/<code>
k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

結論:

  • 容器nginx成功的讀取到了容器fortune寫入存儲的內容,emptyDir卷可以實現容器間的文件共享。
  • emptyDir卷的生存週期與pod的生存週期相關聯,所以當刪除pod時,卷的內容就會丟失

三、hostPath

1. 概念

  hostPath允許掛載Node上的文件系統到Pod裡面去。如果Pod需要使用Node上的文件,可以使用hostPath。在同一個節點上運行並在其hostPath卷中使用相同路徑的pod可以看到相同的文件。

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

2. 創建pod hostpath-nginx

2.1 創建掛載目錄

在node節點上創建掛載目錄,master和各node上分別執行如下操作

<code>[root@master ~]# mkdir /data && cd /data && echo `hostname` > index.html/<code>

2.2 創建pod

<code>[root@master ~]# more hostPath-pod.yaml apiVersion: v1kind: Podmetadata:  labels:    app: prod   name: hostpath-nginx spec:  containers:  - image: nginx     name: nginx     volumeMounts:    - mountPath: /usr/share/nginx/html   #容器掛載點       name: nginx-volume                 #掛載卷nginx-volume  volumes:  - name: nginx-volume                   #卷名    hostPath:      path: /data                        #準備掛載的node上的文件系統[root@master ~]# kubectl apply -f hostPath-pod.yaml pod/hostpath-nginx created[root@master ~]# kubectl get po -o wideNAME               READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESemptydir-fortune   2/2     Running   0          40m   10.244.2.140   node02   <none>           <none>hostpath-nginx     1/1     Running   0          16s   10.244.1.140   node01   <none>           <none>/<none>/<none>/<none>/<code>

3. 訪問pod hostpath-nginx

<code>[root@master ~]# curl 10.244.1.140node01/<code>
k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

結論:

  • pod運行在node01上,訪問的內容為'node01',為掛載的文件系統/data下index.html內容,容器成功讀取到掛載的節點文件系統裡的內容。
  • 僅當需要在節點上讀取或寫入系統文件時才使用hostPath , 切勿使用它們來持久化跨pod的數據。
  • hostPath可以實現持久存儲,但是在node節點故障時,也會導致數據的丟失。

四、NFS共享存儲

1. 概念

  NFS是Network File System的縮寫,即網絡文件系統。Kubernetes中通過簡單地配置就可以掛載NFS到Pod中,而NFS中的數據是可以永久保存的,同時NFS支持同時寫操作。

  emptyDir可以提供不同容器間的文件共享,但不能存儲;hostPath可以為不同容器提供文件的共享並可以存儲,但受制於節點限制,不能跨節點共享;這時需要網絡存儲 (NAS),即既可以方便存儲容器又可以從任何集群節點訪問,本文以NFS為例做測試。

2. nfs搭建及配置

nfs搭建詳見:Centos7下NFS服務器搭建及客戶端連接配置

完成nfs服務器搭建和客戶端nfs軟件安裝安裝後,可在master和各node節點檢查nfs服務是否正常

<code>[root@master ~]# showmount -e 172.27.9.181Export list for 172.27.9.181:/backup 172.27.9.0/24/<code>

master和node01、node02節點都執行showmount命令,用於驗證nfs服務是否正常,/backup為nfs服務器對外提供的共享目錄。

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

本文測試的NFS內容:

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

3. 新建pod mongodb-nfs

<code>[root@master ~]# more mongodb-pod-nfs.yaml apiVersion: v1kind: Podmetadata:  name: mongodb-nfsspec:  containers:  - image: mongo    name: mongodb    volumeMounts:    - name: nfs-data               #掛載的卷名,與上面的mongodb-data保持一致      mountPath: /data/db          #MongoDB數據存放的路徑    ports:    - containerPort: 27017      protocol: TCP  volumes:  - name: nfs-data                 #卷名    nfs:      server: 172.27.9.181         #nfs服務器ip      path: /backup                #nfs服務器對外提供的共享目錄[root@master ~]# kubectl apply -f mongodb-pod-nfs.yaml pod/mongodb-nfs created[root@master ~]# kubectl get po -o wide                NAME          READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESmongodb-nfs   1/1     Running   0          23s   10.244.2.142   node02   <none>           <none>/<none>/<code>

注意此時pod的ip為10.244.2.142

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

4. nfs共享存儲測試

4.1 向MongoDB寫入數據

<code>[root@master ~]# kubectl exec -it mongodb-nfs mongo> use loongswitched to db loong> db.foo.insert({name:'loong576'})WriteResult({ "nInserted" : 1 })/<code>

切換至db loong,插入JSON文檔(name:'loong576')

4.2 查看寫入的數據

<code>> db.foo.find(){ "_id" : ObjectId("5d6e17b018651a21e0063641"), "name" : "loong576" }/<code>
k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

4.3 刪除pod並重建

<code>[root@master ~]# kubectl delete pod mongodb-nfs pod "mongodb-nfs" deleted[root@master ~]# kubectl apply -f mongodb-pod-nfs.yamlpod/mongodb-nfs created[root@master ~]# kubectl get po -o wide               NAME          READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESmongodb-nfs   1/1     Running   0          22s   10.244.2.143   node02   <none>           <none>/<none>/<code> 

刪除pod mongodb-nfs並重建,此時podip變為10.244.2.143,再次訪問MongoDB驗證之前寫入的文檔是否還存在。

4.4 新pod讀取共享存儲數據

<code>[root@master ~]# kubectl exec  -it mongodb-nfs  mongo> use loongswitched to db loong> db.foo.find(){ "_id" : ObjectId("5d6e17b018651a21e0063641"), "name" : "loong576" }/<code>
k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

即使pod被刪除重建仍然能訪問共享數據。

結論:

  • NFS共享存儲可持久化數據
  • NFS共享存儲可跨節點提供數據共享

五、PV and PVC

1. 概念

   PersistentVolume (持久卷, 簡稱 PV)和Persistent VolumeClaim(持久卷聲明,簡稱 PVC)使得K8s集群具備了存儲的邏輯抽象能力,使得在配置Pod的邏輯裡可以忽略對實際後臺存儲技術的配置,而把這項配置的工作交給PV的配置者,即集群的管理者。存儲的PV和PVC的這種關係,跟計算的Node和Pod的關係是非常類似的;PV和Node是資源的提供者,根據集群的基礎設施變化而變化,由K8s集群管理員配置;而PVC和Pod是資源的使用者,根據業務服務的需求變化而變化,由K8s集群的使用者即服務的管理員來配置。

  當集群用戶需要在其pod中使用持久化存儲時,他們首先創建PVC清單,指定所需要的最低容量要求和訪問模式,然後用戶將待久卷聲明清單提交給Kubernetes API服務器,Kubernetes將找到可匹配的PV並將其綁定到PVC。PVC可以當作pod中的一個捲來使用,其他用戶不能使用相同的PV,除非先通過刪除PVC綁定來釋放。

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

2. 創建PV

2.1 nfs配置

nfs服務器共享目錄配置:

<code>[root@centos7 ~]# exportfs         /backup/v1      172.27.9.0/24/backup/v2      172.27.9.0/24/backup/v3      172.27.9.0/24/<code>

master和各node節點檢查nfs配置:

<code>[root@master ~]# showmount -e 172.27.9.181Export list for 172.27.9.181:/backup/v3 172.27.9.0/24/backup/v2 172.27.9.0/24/backup/v1 172.27.9.0/24/<code>

2.2 PV創建

<code>[root@master ~]# more pv-nfs.yaml apiVersion: v1kind: PersistentVolumemetadata:  name: pv001spec:  capacity:    storage: 2Gi                             #指定PV容量為2G  volumeMode: Filesystem                     #卷模式,默認為Filesystem,也可設置為'Block'表示支持原始塊設備  accessModes:    - ReadWriteOnce                          #訪問模式,該卷可以被單個節點以讀/寫模式掛載  persistentVolumeReclaimPolicy: Retain      #回收策略,Retain(保留),表示手動回收  storageClassName: nfs                      #類名,PV可以具有一個類,一個特定類別的PV只能綁定到請求該類別的PVC  nfs:                                       #指定NFS共享目錄和IP信息    path: /backup/v1    server: 172.27.9.181---apiVersion: v1kind: PersistentVolumemetadata:  name: pv002spec:  capacity:    storage: 2Gi                             #指定PV容量為2G  volumeMode: Filesystem                     #卷模式,默認為Filesystem,也可設置為'Block'表示支持原始塊設備  accessModes:    - ReadOnlyMany                           #訪問模式,該卷可以被多個節點以只讀模式掛載  persistentVolumeReclaimPolicy: Retain      #回收策略,Retain(保留),表示手動回收  storageClassName: nfs                      #類名,PV可以具有一個類,一個特定類別的PV只能綁定到請求該類別的PVC  nfs:                                       #指定NFS共享目錄和IP信息    path: /backup/v2    server: 172.27.9.181---apiVersion: v1kind: PersistentVolumemetadata:  name: pv003spec:  capacity:    storage: 1Gi                             #指定PV容量為1G  volumeMode: Filesystem                     #卷模式,默認為Filesystem,也可設置為'Block'表示支持原始塊設備  accessModes:    - ReadWriteOnce                          #訪問模式,該卷可以被單個節點以讀/寫模式掛載  persistentVolumeReclaimPolicy: Retain      #回收策略,Retain(保留),表示手動回收  storageClassName: nfs                      #類名,PV可以具有一個類,一個特定類別的PV只能綁定到請求該類別的PVC  nfs:                                       #指定NFS共享目錄和IP信息    path: /backup/v3    server: 172.27.9.181[root@master ~]# kubectl apply -f pv-nfs.yaml persistentvolume/pv001 createdpersistentvolume/pv002 createdpersistentvolume/pv003 created[root@master ~]# kubectl get pvNAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLA*S   REASON   AGEpv001   2Gi        RWO            Retain           Available           nfs                     26spv002   2Gi        ROX            Retain           Available           nfs                     26spv003   1Gi        RWO            Retain           Available           nfs                     26s/<code> 

創建pv001、pv002、pv003,分別對應nfs的共享目錄/backup/v1、/backup/v2、/backup/v2。

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

卷可以處於以下的某種狀態:

  • Available(可用),一塊空閒資源還沒有被任何聲明綁定
  • Bound(已綁定),卷已經被聲明綁定
  • Released(已釋放),聲明被刪除,但是資源還未被集群重新聲明
  • Failed(失敗),該卷的自動回收失敗

PV的訪問模式有三種:

  • 第一種,ReadWriteOnce:是最基本的方式,可讀可寫,但只支持被單個Pod掛載。
  • 第二種,ReadOnlyMany:可以以只讀的方式被多個Pod掛載。
  • 第三種,ReadWriteMany:這種存儲可以以讀寫的方式被多個Pod共享。不是每一種存儲都支持這三種方式,像共享方式,目前支持的還比較少,比較常用的是NFS。
k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

PV不屬於任何命名空間, 它跟節點一樣是集群層面的資源,區別於pod和PVC。

3. 創建PVC

3.1 PVC創建

<code>[root@master ~]# more pvc-nfs.yaml kind: PersistentVolumeClaimapiVersion: v1metadata:  name: mypvc                       #聲明的名稱,當做pod的卷使用時會用到                          spec:  accessModes:    - ReadWriteOnce                 #訪問卷模式,篩選PV條件之一  volumeMode: Filesystem            #卷模式,與PV保持一致,指示將卷作為文件系統或塊設備使用  resources:                        #聲明可以請求特定數量的資源,篩選PV條件之一    requests:      storage: 2Gi  storageClassName: nfs             #請求特定的類,與PV保持一致,否則無法完成綁定[root@master ~]# kubectl apply -f pvc-nfs.yaml persistentvolumeclaim/mypvc created[root@master ~]# kubectl get pvcNAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGEmypvc   Bound    pv001    2Gi        RWO            nfs            22s/<code>

創建PVC mypvc,訪問卷模式為ReadWriteOnce,大小為2G;WO、ROX、RWX、RWO表示可以同時使用卷的工作節點的數量而並非pod的數量。

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

3.2 查看選中的PV

PVC篩選條件:

PV

accessModes

storage

pv001

pv002

×

pv003

×

PV查看:

<code>[root@master ~]# kubectl get pvNAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM           STORAGECLA*S   REASON   AGEpv001   2Gi        RWO            Retain           Bound       default/mypvc   nfs                     12mpv002   2Gi        ROX            Retain           Available                   nfs                     12mpv003   1Gi        RWO            Retain           Available                   nfs                     12m/<code>
k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

pv001被選中,符合PVC定義,pv002訪問模式不匹配,pv003大小不匹配。

4. pod中使用PVC

<code>[root@master ~]# more mongodb-pod-pvc.yaml                  apiVersion: v1kind: Podmetadata:  name: mongodb-pvc spec:  containers:  - image: mongo    name: mongodb    volumeMounts:    - name: pvc-data      mountPath: /data/db    ports:    - containerPort: 27017      protocol: TCP  volumes:  - name: pvc-data    persistentVolumeClaim:      claimName: mypvc          #與pvc中聲明的name保持一致[root@master ~]# kubectl apply -f mongodb-pod-pvc.yaml pod/mongodb-pvc created[root@master ~]# kubectl get po -o wide                           NAME          READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESmongodb-pvc   1/1     Running   0          16s   10.244.2.144   node02   <none>           <none>/<none>/<code>
k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

創建pod mongodb-pvc,使用PVC mypvc,測試同四-4中的nfs共享存儲測試,不再贅述。

k8s實踐(七):存儲卷數據持久化Volumes and Persistent Storage

本文所有腳本和配置文件已上傳:https://github.com/loong576/k8s-Volumes-and-Persistent-Storage.git


分享到:


相關文章: