1. 程式人生 > >Kubernetes之存儲卷

Kubernetes之存儲卷

cpu 選擇器 sel reclaim 插件 rfs sphere 策略 概述

存儲卷概述

容器磁盤上的文件的生命周期是短暫的,這就使得在容器中運行重要應用時會出現一些問題。首先,當容器崩潰時,kubelet 會重啟它,但是容器中的文件將丟失——容器以幹凈的狀態(鏡像最初的狀態)重新啟動。其次,在 Pod 中同時運行多個容器時,這些容器之間通常需要共享文件。Kubernetes 中的 Volume 抽象就很好的解決了這些問題。在原docker環境中也有存儲卷的概念,但docker環境的存儲卷調度在宿主機上的目錄,當docker重新創建的時候存儲卷還會掛載統一宿主機上,但我們知道Kubernetes是分布式集群,當我們銷毀一個pod的時候,可能pod會在其他節點上啟動,但其他節點宿主機上並沒有這個目錄,這樣就不會掛載到原來的數據了。為此Kubernetes不同類型的持久卷。

我們可以通過kubectl explain pods.spec.volumes來查看支持的存儲卷:

  • hostPath 主機目錄
  • emptyDir 空目錄(pod銷毀也隨之銷毀)
  • rbd 分布式存儲之ceph塊存儲
  • local 卷表示掛載的本地存儲設備,如磁盤、分區或目錄
  • cephfs 分布式存儲之cephfs
  • awsElasticBlockStore aws雲存儲
  • azureDisk azure雲存儲
  • azureFile azure雲存儲
  • glusterfs 分布式存儲之glusterfs
  • downwardAPI 卷用於使向下 API 數據(downward API data)對應用程序可用。它掛載一個目錄,並將請求的數據寫入純文本文件。
  • cinder OpenStack 塊存儲
  • configMap 配置中心
  • fc 卷允許將現有的 fc 卷掛載到 pod 中。您可以使用卷配置中的 targetWWN 參數指定單個或多個目標全球通用名稱(World Wide Name)。如果指定了多個 WWN,則 targetWWN 期望這些 WWN 來自多路徑連接。
  • flexVolume 抽象的存儲服務,存儲服務的管理軟件
  • flocker 是一款開源的集群容器數據卷管理器。它提供了由各種存儲後端支持的數據卷的管理和編排。
  • gcePersistentDisk 谷歌雲上
  • gitRepo 卷是一個可以演示卷插件功能的示例。它會掛載一個空目錄並將 git 存儲庫克隆到您的容器中。
  • iscsi iscsi 卷允許將現有的 iSCSI卷掛載到容器中。不像 emptyDir,刪除 Pod 時 iscsi 卷的內容將被保留,卷僅僅是被卸載。這意味著 iscsi 卷可以預先填充數據,並且這些數據可以在 pod 之間“切換”。
  • nfs nfs Nas存儲
  • persistentVolumeClaim 卷用於將 PersistentVolume 掛載到容器中。PersistentVolumes 是在用戶不知道特定雲環境的細節的情況下“聲明”持久化存儲(例如 GCE PersistentDisk 或 iSCSI 卷)的一種方式。
  • photonPersistentDisk
  • portworxVolume 是一個與 Kubernetes 一起,以超融合模式運行的彈性塊存儲層
  • projected 卷將幾個現有的卷源映射到同一個目錄中
  • quobyte 卷允許將現有的 Quobyte 卷掛載到容器中。
  • scaleIO ScaleIO 是一個基於軟件的存儲平臺,可以使用現有的硬件來創建可擴展的共享塊網絡存儲集群
  • secret 加密文件
  • storageos 動態存儲
  • vsphereVolume 配置了 vSphere Cloud Provider 的 Kubernetes

emptyDir

kubectl explain pod.spec.volumes.emptyDir 指定emptyDir存儲卷

  • medium 指定媒介類型 disk Memory 兩種
  • sizeLimit 現在資源使用情況

kubectl explain pod.spec.containers.volumeMounts 指定掛載哪些存儲卷

  • mountPath 掛載那個路徑
  • name 指定掛載的volumes名稱
  • readOnly 是否只讀掛載
  • subPath 是否掛載子路徑

下面實例為 一個pod中的兩個容器共享同一個存儲

apiVersion: v1
kind: Pod
metadata:
  name: my-demo
  namespace: default
  labels:
    name: myapp
    tier: appfront
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: appindex
      mountPath: /usr/share/nginx/html/
  - name: busybox
    image: busybox
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: appindex
      mountPath: /data/
    command:
    - "/bin/sh"
    - "-c"
    - "while true; do echo $(date) >> /data/index.html; sleep 2; done"
  volumes:
  - name: appindex
    emptyDir: {}

驗證

curl 10.244.3.14
Mon Sep 17 06:03:53 UTC 2018
Mon Sep 17 06:03:55 UTC 2018
Mon Sep 17 06:03:57 UTC 2018
Mon Sep 17 06:03:59 UTC 2018
Mon Sep 17 06:04:01 UTC 2018
Mon Sep 17 06:04:03 UTC 2018

hostPath

kubectl explain pod.spec.volumes.hostPath

  • path 指定宿主機的路徑
  • type DirectoryOrCreate 宿主機上不存在創建此目錄 Directory 必須存在掛載目錄 FileOrCreate 宿主機上不存在掛載文件就創建 File 必須存在文件

目錄自動創建

apiVersion: v1
kind: Pod
metadata:
  name: my-demo
  namespace: default
  labels:
    name: myapp
    tier: appfront
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: appindex
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: appindex
    hostPath:
      path: /data/pod/myapp
      type: DirectoryOrCreate

NFS

kubectl explain pod.spec.volumes.nfs

  • path 源目錄
  • readOnly 是否只讀 默認false
  • server NFS服務地址
apiVersion: v1
kind: Pod
metadata:
  name: my-demo-nfs
  namespace: default
  labels:
    name: myapp
    tier: appfront
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: appindex
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: appindex
    nfs:
      server: 172.16.132.241
      path: /data

手動在/data目錄下增加一個index.html

驗證

kubectl get pods -o wide 
NAME                          READY     STATUS    RESTARTS   AGE       IP            NODE
my-demo                       1/1       Running   0          3h        10.244.2.4    k8s-node02
my-demo-nfs                   1/1       Running   0          2m        10.244.3.15   k8s-node03

$ curl 10.244.3.15
nfs

PVC如何使用的

我們前面提到kubernetes提供那麽多儲存接口,但是首先kubernetes的各個Node節點能管理這些存儲,但是各種存儲參數也需要專業的存儲工程師才能了解,由此我們的kubernetes管理變的更加復雜的。由此kubernetes提出了PV和PVC的概念,這樣開發人員和使用者就不需要關註後端存儲是什麽,使用什麽參數等問題。如下圖:

技術分享圖片

當我們pod中定義volume的時候,我們只需要使用pvs存儲卷就可以,pvc必須與對應的pv建立關系,pvc會根據定義去pv申請,而pv是由存儲空間創建出來的。pv和pvc是kubernetes抽象出來的一種存儲資源。

技術分享圖片

PV介紹:

PersistentVolume 是由管理員設置的存儲,它是群集的一部分。就像節點是集群中的資源一樣,PV 也是集群中的資源。 PV 是 Volume 之類的卷插件,但具有獨立於使用 PV 的 Pod 的生命周期。此 API 對象包含存儲實現的細節,即 NFS、iSCSI 或特定於雲供應商的存儲系統。可根據上圖看清他們之間的關系

PV有兩種配置方式:動態和靜態

靜態:

集群管理員創建一些 PV。它們帶有可供群集用戶使用的實際存儲的細節。

動態:

當管理員創建的靜態 PV 都不匹配用戶的 PersistentVolumeClaim 時,集群可能會嘗試動態地為 PVC 創建卷。此配置基於 StorageClasses:PVC 必須請求存儲類,並且管理員必須創建並配置該類才能進行動態創建。聲明該類為 "" 可以有效地禁用其動態配置。

要啟用基於存儲級別的動態存儲配置,集群管理員需要啟用 API server 上的 DefaultStorageClass 準入控制器。例如,通過確保 DefaultStorageClass 位於 API server 組件的 --admission-control 標誌,使用逗號分隔的有序值列表中,可以完成此操作。

kubectl explain pv.spec

  • accessModes 訪問模式
  1. ReadWriteOnce(RWO) 單節點讀寫
  2. ReadOnlyMany(ROX) 多節點只讀
  3. ReadWriteMany(RWX) 多節點讀寫
  • capacity 定義pv使用多少資源

定義一個nfs格式的pv

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv01
  labels:
    name: pv01
spec:
  nfs:
    path: /data/pv/01
    server: 172.16.132.241
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv02
  labels:
    name: pv02
spec:
  nfs:
    path: /data/pv/02
    server: 172.16.132.241
  accessModes: ["ReadOnlyMany","ReadWriteOnce"]
  capacity:
    storage: 5Gi

查看詳細

kubectl get pv 
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
pv01      2Gi        RWO,RWX        Retain           Available                                      1m
pv02      5Gi        RWO,ROX        Retain           Available                                      1m

回收策略(RECLAIM POLICY

當pod結束 volume 後可以回收資源對象刪除PVC,而綁定關系就不存在了,當綁定關系不存在後這個PV需要怎麽處理,而PersistentVolume 的回收策略告訴集群在存儲卷聲明釋放後應如何處理該卷。目前,volume 的處理策略有保留、回收或刪除。

保留:

此策略允許手動回收資源,當pvc被刪除後,pv依然存在,volume 被視為“已釋放”。但是由於前一個聲明人的數據仍然存在,所以還不能馬上進行其他聲明。管理員可以通過以下步驟手動回收卷。

  • 刪除 PV。在刪除 PV 後,外部基礎架構中的關聯存儲空間(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)仍然存在。
  • 手動清理相關存儲空間上的數據
  • 手動刪除關聯的存儲空間,或者如果要重新使用相同的存儲空間,請使用存儲空間定義創建新的 PersistentVolume

回收:

在 volume上執行情況數據(rm -rf /thevolume/*),可以再次被其他pvc調度

刪除:

對於支持刪除回收策略的卷插件,刪除操作將從 Kubernetes 中刪除 PV 對象,並刪除外部基礎架構(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中的關聯存儲空間。動態配置的卷繼承其 StorageClass 的回收策略,默認為 Delete。管理員應該根據用戶的期望來配置 StorageClass,否則就必須要在 PV 創建後進行編輯或修補。

PVC介紹:

PersistentVolumeClaim 是用戶存儲的請求。它與 Pod 相似。Pod 消耗節點資源,PVC 消耗 PV 資源。Pod 可以請求特定級別的資源(CPU 和內存)。聲明可以請求特定的大小和訪問模式(例如,可以以讀/寫一次或 只讀多次模式掛載)。

雖然 PersistentVolumeClaims 允許用戶使用抽象存儲資源,但用戶需要具有不同性質(例如性能)的 PersistentVolume 來解決不同的問題。集群管理員需要能夠提供各種各樣的 PersistentVolume,這些PersistentVolume 的大小和訪問模式可以各有不同,但不需要向用戶公開實現這些卷的細節。對於這些需求,StorageClass 資源可以實現。可根據上圖看清他們之間的關系

kubectl explain pvc.spec

  • accessModes 訪問模式 是遞延pv的accessModes的子集,例如:pv中accessModes 定義["ReadWriteMany","ReadWriteOnce"],pvc中的也只能定義["ReadWriteMany","ReadWriteOnce"] 或其中的一個。
  • resources 資源限制
  • selector  標簽選擇器
  • storageClassName 動態存儲名稱
  • volumeMode 後端存儲卷的模式
  • volumeName 指定卷(pv)的名稱

定義pvc資源對象

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: my-demo-pvc
  namespace: default
  labels:
    name: myapp
    tier: appfront
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: appindex
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: appindex
    persistentVolumeClaim:
      claimName: mypvc

查看

$ kubectl get pv 
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM           STORAGECLASS   REASON    AGE
pv02      5Gi        RWO,ROX        Retain           Bound     default/mypvc                            1h
$ kubectl describe pod my
-demo-pvc Name: my-demo-pvc Namespace: default Priority: 0 PriorityClassName: <none> Node: k8s-node02/172.16.138.42 Start Time: Thu, 20 Sep 2018 05:23:04 -0400 Labels: name=myapp tier=appfront Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"name":"myapp","tier":"appfront"},"name":"my-demo-pvc","namespace":"default"},"s... Status: Running IP: 10.244.2.6 Containers: myapp: Container ID: docker://6727e1b45fba703f98d7a11f16a60706b8f5c2925026707b412c13ef80f5ac52 Image: ikubernetes/myapp:v1 Image ID: docker-pullable://ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513 Port: 80/TCP Host Port: 0/TCP State: Running Started: Thu, 20 Sep 2018 05:23:06 -0400 Ready: True Restart Count: 0 Environment: <none> Mounts: /usr/share/nginx/html/ from appindex (rw) /var/run/secrets/kubernetes.io/serviceaccount from default-token-lplp6 (ro) ......

Kubernetes之存儲卷