Kubernetes對有狀態或者對數據須要持久化的應用,不只須要將容器內的目錄掛載到宿主機的目錄或者empDir臨時存儲卷,並且須要更加可靠的存儲來保存應用產生的重要數據,以便於容器應用重建之後,仍然可使用以前的數據。爲了可以屏蔽底層存儲實現的細節,讓用戶方便使用,同時能讓管理員方便管理,kubernetes從v1.0版本就引入了persistentVolume和persistentVolumeCliam兩個資源對象來實現對存儲的管理。
persistentVolume(PV)是對底層網絡共享存儲的抽象,將共享存儲定義爲一種「資源」,好比節點也是一種容器應用能夠消費的資源。PV由管理員進行建立和配置,它與共享存儲的具體實現直接相關,例如:GlusterFS、iSCSI、RBD或者GEC/AWS公有云提供的共享存儲,經過插件式的機制完成與共享存儲的對接,以供應用訪問和使用。 persistentVolumeCliam(PVC)則是用戶對於存儲資源的一個「申請」。就像Pod「消費」node的資源同樣,PVC會「消費」PV資源。PVC能夠申請特定的存儲空間和訪問模式。
使用PVC「申請」到必定的存儲空間仍然不足以知足應用對於存儲設備的各類需求。一般應用程序都會對存儲設備的特性和性能有不一樣的要求。包括讀寫速度、併發性能、數據冗餘等更高的要求,kubernetes從v1.4開始引入了一個新的資源對象storageClass,用於標記存儲資源的特性和性能。到v1.6版本時,storageClass和動態資源應用機制獲得了完善,實現了存儲卷的按需建立。
那麼下面小編將對PV、PVC、storageClass和動態資源供應等共享存儲管理機制進行詳細說明。html
PV做爲存儲資源,主要包括存儲能力、訪問模式、存儲類型、回收策略、後端存儲類型等關鍵信息的設置。如下面配置爲例:node
apiVersion: v1 kind: PersistentVolume metadata: name: pv1 spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: slow nfs: path: /tmp server: 172.17.0.2
上面這個例子就建立了一個5G空間,訪問模式爲ReadWriteOnce,存儲類型爲」slow」(這裏須要要求系統已經建立了名爲slow的storageClass 資源對象),回收策略爲「recycle」,而且後端存儲類型爲nfs(並設置了NFS server的IP和路徑)
Kubernetes支持的PV的類型以下:
GCEPersistentDisk #GEC公有云提供的PersistentDisk
AWSElasticBlockStore #AWS公有云提供的ElasticBlockStore
AzureFile #Azure公有云提供的File
AzureDisk #AzureDisk提供的Disk
FC (Fibre Channel)
Flexvolume
Flocker
NFS #網絡文件系統
iSCSI
RBD (Ceph Block Device) #Ceph存儲塊
CephFS
Cinder (OpenStack block storage) #openStack Cinder塊存儲
Glusterfs
VsphereVolume
Quobyte Volumes
HostPath #宿主機目錄,僅用於單機測試
Portworx Volumes
ScaleIO Volumes
StorageOSjson
① 存儲能力(capacity)
描述存儲設備具有的能力,目前僅支持對存儲空間的設置(storage:xxx)後端
② 訪問模式(Access Modes)
對PV進行訪問模式的設置,用於描述用戶應用對存儲資源的訪問權限。訪問模式以下:
ReadWriteOnce:讀寫權限,而且只能被單個node掛載
ReadOnlyMany:只讀權限,能夠被多個node掛載
ReadWriteMany:讀寫權限,能夠被多個node掛載
注意:PV能夠可能支持多種訪問模式,但PV在掛載時只能使用一種訪問模式,多種訪問模式不能同時生效。
對於不一樣類型的PV有不一樣的訪問模式,在PV的定義時須要與他們匹配:centos
③ 存儲類別(class)
PV能夠設定其存儲的類別,經過storageClassName參數指定一個storageClass資源對象的名稱。具備特定「類別」的PV只能與請求了該「類別」的PVC進行綁定。未設定「類別」的PV則只能與不請求任何「類別」的PVC進行綁定。storageClass資源對象會在後面的動態資源供應中大展神威。api
④ 回收策略(Reclaim Policy)
目前支持如下三種回收策略:
保留(Retain):保留數據,須要手工處理
回收空間(Recycle):簡單清除文件的操做(例如執行rm -rf /xx/*)
刪除(Delete):與PV相連的後端存儲完成volume的刪除操做(如AWS EBS、GCE PD、Azure Disk、OpenStack Cinder等設備的內部volume清理)
注意:目前只有NFS和hostPath支持「Recycle」,AWS EBS、GCE PD、Azure Disk、OpenStack Cinder支持「Delete」。安全
某個PV在生命週期中,可能處於如下4個節點之一:
Available:可用狀態,還與某個PVC綁定
Bound:已經與某個PVC綁定
Released:綁定的PVC已經刪除,資源已經釋放,但沒有被集羣回收
Failed:自動資源回收失敗bash
在將一個PV掛載到一個node上時,根據後端存儲的特色,可能須要設置額外的掛載參數,目前能夠經過在PV的定義中,設置一個名爲「volume.beta.kubernetes.io/mount/options」的annotation來實現。下面小編經過一個gcePersistentDisk設置掛載參數爲例:網絡
apiVersion: "v1" kind: PersistentVolume metadata: name: gce-disk-1 annotations: volume.beta.kubernetes.io/mount/options: discard sepc: capacity: storage: 10Gi accessModes: - ReadWriteOnce gcePersistentDisk: fsType: ext4 pdName: gce-disk-1
上面咱們瞭解了PV的定義,這裏咱們就使用它,這時就須要PVC了。PVC做爲用戶對存儲資源的需求申請,主要包括存儲空間申請、訪問模式。PV選擇條件和存儲類別等信息的設置。
接下來小編也是經過一個例子,向你們介紹若是定義PVC去使用PV:架構
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: myclaim sepc: accessModes: - ReadWriteOnce resources: requests: storage: 8Gi storageClassName: slow selector: matchLabels: release: "stable" matchExpressions: - {key: environment, operator: In, values: [dev]}
申請8G空間,訪問模式爲「ReadWriteOnce」、PV選擇條件包括標籤爲「release=stable」而且包含條件爲「environment in dev」的標籤,存儲類別爲slow(系統中已經存在)。
其中對PVC的關鍵配置詳細介紹:
資源請求(resources):僅支持存儲空間大小請求
資源請求(resources):僅支持存儲空間大小請求
PV的選擇條件:經過label selector去篩選可使用的PV,系統將根據標籤找到合適獲得PV,而且將PV與PVC綁定
存儲類別:PVC在定義時能夠設定須要的後端存儲的類別,以下降對後端存儲特性的依賴。只有設置了該class的PV才能被系統篩選出來,而且與該PVC綁定
這裏針對PVC是否設置class需求,小編進行詳細的說明一下:
這裏分爲兩種狀況:
系統啓用了defaultStorageClass
若是啓用了defaultStorageClass可是,系統中不存在默認的storageClass,那麼等效於不啓用defaultStorageClass的狀況
若是啓用了defaultStorageClass而且系統中有默認的storageClass,則系統自動的爲PVC建立一個PV(使用默認的defaultStorageClass),並將它們綁定
系統未啓用defaultStorageClass
若是設置了storageClass爲「」或者沒有設置storageClass字段,那麼只能選擇未設定storageclass的PV與之進行匹配和綁定
設置默認的storageClass的方法是,在storageClass上定義一個annotation「storageclass.kubernetes.io/is-default-class=true」,可是不能給多個storageClass都設置annotation,若是這樣的話因爲不惟一,系統沒法爲PVC建立相應的PV。
使用PV與PVC綁定的注意項:
PV和PVC都受namespace的 限制,只有相同namespace中的PV和PVC才能綁定,並只有相同namespace下pod才能掛載PVC。
當在PVC定義中同時設置了selector和storageClassName,只有兩者同時知足條件才能將PV和PVC綁定。
PV能夠看作可用的存儲資源,PVC則是對存儲資源的請求,PV和PVC的相互關係以下圖所示:
接下來由圖咱們逐一介紹:
Kubernetes支持兩種資源供應模式:靜態模式和動態模式。資源供應的結果就是建立好的PV。
靜態模式:集羣管理員手工建立許多PV,在定義PV時須要將後端存儲的特性進行設置。
動態模式:集羣管理員無須手動建立PV,而是經過storageClass的設置對後端存儲進行描述,標記爲某種「類型」。此時要求PVC對存儲的類型進行聲明,系統將自動完成PV的建立於PVC的綁定。
在用戶定義好PVC以後,系統將根據PVC對存儲資源的請求在已經存在的PV中選擇一個知足PVC要求的PV,一旦找到,就將該PV與用戶定義的PVC進行綁定,而後用戶的應用就可使用這個PVC。若是系統中沒有知足PVC要求的PV,PVC則會無限期的處於pending狀態,直到等待系統管理員建立了一個符合其要求的PV。PV一旦綁定到某個PVC上,就被這個PVC獨佔,不能與其餘的PVC進行綁定了。這樣的話容易形成資源的浪費,若是使用的是動態模式,則系統在爲PVC找到合適的storageClass後將自動建立一個PV並完成與PVC的綁定。
Pod使用volume的定義,將PVC掛載到容器內的某個路徑進行使用。Volume的類型爲「persistentVolumeClaim」,在後面的示例中再進行詳細的說明。在容器應用掛載了一個PVC以後,就能被持續獨佔使用。不過,多個pod能夠掛載同一個PVC。
當用戶對存儲資源使用完畢以後,用戶能夠刪除PVC,與該PVC綁定的PV將會被標價爲「已釋放」,但還不能馬上與其餘PVC進行綁定。經過以前PVC寫入的數據可能還留在存儲設備上,只有在清除以後該PV才能再次使用。
對於PV,管理員能夠設置回收策略,用於設置與之綁定的PVC釋放資源以後,對於遺留數據如何處理。只有PV的存儲空間完成回收,才能供新的PVC綁定和使用。
最後小編經過兩幅圖,來介紹一下靜態資源供應模式和動態資源供應模式的原理,爲下面一節內容作鋪墊:
靜態模式下的PV和PVC原理
動態模式下storageClass、PV、PVC原理
StorageClass做爲對存儲資源的抽象定義,對用戶設置的PVC申請屏蔽後端存儲的細節,一方面減輕用戶對於存儲資源細節的關注,另外一方面也減輕了管理員手工管理PV的工做,由系統自動完成PV的建立和綁定,實現了動態的資源供應。
對於StorageClass的定義主要包括:名稱、後端存儲的提供者和後端存儲的相關參數配置。StorageClass一旦被建立出來,將沒法修改。如須要修改,只能刪除原先建立的StorageClass從新構建。下面是一個定義StorageClass的例子:
kind: storageClass apiVersion: storage.k8s.io/v1 metadata: name: standard provisioner: kubernetes.io/aws-ebs parameters: type: gp2
上面的例子就定義了一個名爲「standard」,提供者爲「aws-ebs」,其參數爲gp2的StorageClass。
其中定義StorageClass中有兩個重點參數:
provisioner(提供者):描述存儲資源的提供者,也能夠看作是後端存儲驅動。目前provisioner都是以「Kubernetes.io/」爲開頭
parameters(參數):後端資源提供者的參數設置,不一樣的provisioner包括不一樣的參數設置
①AWS EBS存儲卷
kind: storageClass apiVersion: storage.k8s.io/v1 metadata: name: slow provisioner: kubernetes.io/aws-ebs parameters: type: io1 zone: us-east-1d iopsPerGB: "10"
參數說明:
type:可選有:io一、gp二、sc一、st1,默認是gp2
zone:AWS zone名稱
iopPerGB:僅用於io1類型的volume,意爲每秒每G的I/O操做數量
encrypted:是否加密
kmsKeyId:加密時的Amazon Resource Name
② GCE PD存儲卷
kind: storageClass apiVersion: storage.k8s.io/v1 metadata: name: slow provisioner: kubernetes.io/gce-pd parameters: type: pd-standard zone: us-centrall-a
參數說明:
type:可選項有:pd-standard、pd-ssd,默認是pd-standard
zone:GCE zone名稱
③ GlusterFS存儲卷
apiVersion: storage.k8s.io/v1 kind: storageClass metadata: name: slow provisioner: kubernetes.io/glusterfs parameters: resturl: "http://127.0.0.1:8081" clusterid: 44ad5as1fd5ae1fde1fwe1d5we1d5 restauthenabled: "true" restuser: "admin" secreNamespace: "default" secreName: "heketi-sercret" gidMin: "40000" gidMax: "50000" volumetype: "replicate:3"
參數說明:
resturl:Gluster REST服務(Heketi)URL地址,用於自動完成GlusterFSvolume的設置
restauthenabled:訪問Gluster REST服務啓用安全機制
restuser:訪問Gluster REST服務的用戶名
secretNamespace和secretName:保存訪問Gluster REST服務密碼的Secret的資源對象名
clustered:GlusterFS 的cluster ID
gidMin和gidMax:storageClass的GID的範圍,用於動態建立資源供應時PV設置的GID
volumetype:GlusterFS的volume類型設置,例如:replicate:3表示replicate類型3個副本
④ OpenStack Cinder存儲卷
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: gold provisioner: kubernetes.io/cinder parameters: type: fast availability: nova
參數說明:
type:cinder的volumetype,默認爲空
availability:availability zone ,默認爲空
要在系統中設置一個默認的storageClass,首先須要啓動名爲「DefaultStorageClass」的admission controller,即在kube-apiserver的命令參數中的--admission-control中增長:DefaultStorageClass
例:--admission-control=「xxx,xxx,xxx, DefaultStorageClass」
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: gold annotations: storageclass.beta.kubernetes.io/is-default-class="true" provisioner: kubernetes.io/gce-pd parameters: type: pd-ssd
而後建立這個storageClass,此時咱們在經過命令可查看:
[::root]kubelet get sc -n=xxx
注意:默認的storageClass只能設置一個,不然系統會由於多個default引發衝突,而不知道篩選哪個爲默認的,最終致使默認的storageClass不生效。
這個案例從定義storageClass、建立storageFS和Heketi服務、用戶申請PVC到建立Pod使用存儲資源,對storageClass和動態資源分配進行詳細說明,進一步分析kubernetes的存儲機制。
這裏的案例是參考至:
https://www.cnblogs.com/xiaoqshuo/p/10096682.html 和《kubernetes權威指南》
GlusterFS是Scale-Out存儲解決方案Gluster的核心,它是一個開源的分佈式文件系統,具備強大的橫向擴展能力,經過擴展可以支持數PB存儲容量和處理數千客戶端。GlusterFS藉助TCP/IP或InfiniBand RDMA網絡將物理分佈的存儲資源彙集在一塊兒,使用單一全局命名空間來管理數據。GlusterFS基於可堆疊的用戶空間設計,可爲各類不一樣的數據負載提供優異的性能。
GlusterFS支持運行在任何標準IP網絡上標準應用程序的標準客戶端,用戶能夠在全局統一的命名空間中使用NFS/CIFS等標準協議來訪問應用數據。GlusterFS使得用戶可擺脫原有的獨立、高成本的封閉存儲系統,可以利用普通廉價的存儲設備來部署可集中管理、橫向擴展、虛擬化的存儲池,存儲容量可擴展至TB/PB級。
GlusterFS以原始數據格式(如EXT三、EXT四、XFS、ZFS)儲存數據,並實現多種數據自動修復機制。
架構圖:
這裏只是帶你們瞭解一下GlusterFS,便於理解後面PVC掛載的內容,無需過多深刻。
Heketi服務是一個提供REST ful API管理GlusterFS卷框架,並可以在kubernetes、openstack等雲平臺上實現動態存儲資源供應,支持GlusterFS多集羣管理,便於管理員對GlusterFS進行操做,以下圖簡單介紹了Heketi服務的做用:
① 在各個計劃用於GlusterFS的node上安裝GlusterFS客戶端
#yum install glusterfs glusterfs-fuse -y
② 在master的kube-apiserver服務和待啓動GlusterFS的各個node上的kubelet服務的啓動參數中入:--allow-privileged=true
③ 載入指定的個別模塊
modprobe dm_snapshot modprobe dm_mirror modprobe dm_thin_pool
④ 爲要部署GlusterFS的node打上標籤,爲了將GlusterFS容器定向部署到安裝了GlusterFS的node上
[root@k8s-master01 ~]# kubectl label node k8s-node-1 storagenode=glusterfs node/k8s-node-1 labeled [root@k8s-master01 ~]# kubectl label node k8s-node-2 storagenode=glusterfs node/k8s-node-2 labeled [root@k8s-master01 ~]# kubectl label node k8s-node-3 storagenode=glusterfs node/k8s-node-3 labeled
⑤ 建立GlusterFS管理服務容器集羣
#glusterfs-daemonset.yaml:
kind: DaemonSet apiVersion: extensions/v1beta1 metadata: name: glusterfs labels: glusterfs: daemonset annotations: description: GlusterFS DaemonSet tags: glusterfs spec: template: metadata: name: glusterfs labels: glusterfs-node: pod spec: nodeSelector: storagenode: glusterfs hostNetwork: true containers: - image: gluster/gluster-centos:latest name: glusterfs volumeMounts: - name: glusterfs-heketi mountPath: "/var/lib/heketi" - name: glusterfs-run mountPath: "/run" - name: glusterfs-lvm mountPath: "/run/lvm" - name: glusterfs-etc mountPath: "/etc/glusterfs" - name: glusterfs-log mountPath: "/var/log/glusterfs" - name: glusterfs-config mountPath: "/var/lib/glusterd" - name: glusterfs-dev mountPath: "/dev" - name: glusterfs-misc mountPath: "/var/lib/misc/glusterfsd" - name: glusterfs-cgroup mountPath: "/sys/fs/cgroup" readOnly: true - name: glusterfs-ssl mountPath: "/etc/ssl" readOnly: true securityContext: capabilities: {} privileged: true readinessProbe: timeoutSeconds: 3 initialDelaySeconds: 60 exec: command: - "/bin/bash" - "-c" - systemctl status glusterd.service livenessProbe: timeoutSeconds: 3 initialDelaySeconds: 60 exec: command: - "/bin/bash" - "-c" - systemctl status glusterd.service volumes: - name: glusterfs-heketi hostPath: path: "/var/lib/heketi" - name: glusterfs-run - name: glusterfs-lvm hostPath: path: "/run/lvm" - name: glusterfs-etc hostPath: path: "/etc/glusterfs" - name: glusterfs-log hostPath: path: "/var/log/glusterfs" - name: glusterfs-config hostPath: path: "/var/lib/glusterd" - name: glusterfs-dev hostPath: path: "/dev" - name: glusterfs-misc hostPath: path: "/var/lib/misc/glusterfsd" - name: glusterfs-cgroup hostPath: path: "/sys/fs/cgroup" - name: glusterfs-ssl hostPath: path: "/etc/ssl"
#kubelet create -f glusterfs-daemonset.yaml #建立 #kubectl get pods #查看 NAME READY STATUS RESTARTS AGE glusterfs-fvxh7 1/1 Running 0 47m glusterfs-jjw7b 1/1 Running 0 47m glusterfs-td875 1/1 Running 0 47m
⑥建立Heketi服務
在部署Heketi以前,須要爲他建立一個ServiceAccount對象:
#heketi-service-account.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: heketi-service-account
#kubelet create -f heketi-service-account.yaml
#heketi-deployment-svc.yaml
kind: Deployment apiVersion: extensions/v1beta1 metadata: name: deploy-heketi labels: glusterfs: heketi-deployment deploy-heketi: heketi-deployment annotations: description: Defines how to deploy Heketi spec: relicas: 1 template: metadata: name: deploy-heketi labels: glusterfs: heketi-pod spec: ServiceAccountName: heketi-service-account containers: - image: heketi/heketi:dev name: deploy-heketi env: - name: HEKETI_EXECUTOR value: kubernetes - name: HEKETI_FSTAB value: "/var/lib/heketi/fstab" - name: HEKETI_SNAPSHOT_LIMIT value: "14" - name: HEKETI_KUBE_GLUSTER_DAEONSET value: "y" ports: - containerPort: 8080 volumeMounts: - name: db mountPath: "/var/lib/heketi" readinessProbe: timeoutSeconds: 3 initialDelaySeconds: 3 httpGet: path: "/hello" port: 8080 livenessProbe: timeoutSeconds: 3 initialDelaySeconds: 30 httpGet: path: "/hello" port: 8080 volumes: - name: db hostPath: path: "/heketi-data" --- kind: Service apiVersion: v1 metadata: name: deploy-heketi labels: glusterfs: heketi-service deploy-heketi: support annotations: description: Exposes Heketi Service spec: selector: name: deploy-heketi ports: - name: deploy-heketi port: 8080 targetPort: 8080
#kubelete create -f heketi-deployment-svc.yaml
⑦ 爲Heketi設置GlusterFS集羣
在Heketi能管理GlusterFS集羣以前,須要爲其設置GlusterFS集羣信息。可使用json配置文件傳入,而且Heketi要求一個GlusterFS集羣至少有3各節點。
#topology.json
{ "clusters": [ { "nodes": [ { "node": { "hostnames": { "manage": [ "k8s-node-1" ], "storage": [ "192.168.2.100" ] }, "zone": 1 }, "devices": [ { "name": "/dev/sdb" } ] }, { "node": { "hostnames": { "manage": [ "k8s-node-2" ], "storage": [ "192.168.2.101" ] }, "zone": 1 }, "devices": [ { "name": "/dev/sdc" } ] }, { "node": { "hostnames": { "manage": [ "k8s-node-3" ], "storage": [ "192.168.2.102" ] }, "zone": 1 }, "devices": [ { "name": "/dev/sdb" } ] } ] } ] }
而後進入Heketi的容器中,執行:
#export HEKETI_CLI_SERVER=http://localhost:8080 #heketi-cli topology load –json= topology.json
完成以上操做,Heketi就完成了GlusterFS集羣的建立,同時在GlusterFS集羣的各個節點上的/dev/sdb盤上成功建立了PV和VG。
注意:/dev/sdb必定要是未建立文件系統的裸設備。
#查看GFS信息
[root@k8s-node-1 kubernetes]# heketi-cli topology info
集羣建立成功以後,固然咱們要試試,storageClass的功能能不能用啊:
① 定義storageClass
#storageclass-gluster-heketi.yaml
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: gluster-heketi provisioner: kubernetes-io/glusterfs parameters: resturl: "http://172.17.2.2:8080" restauthenabled: "false"
② 定義PVC
#pvc-gluster-heketi.yaml(使用動態資源供應模式)
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pvc-gluster-heketi spec: storageClassName: gluster-heketi accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
#能夠經過命令查看pv,和自動建立的PVC
#kubelet get pvc #kubelet get pv
③ 使用pod掛載PVC
#pod-use-pvc.yaml
apiVersion: v1 kind: Pod metadata: name: pod-use-pvc spec: containers: - name: pod-use-pvc image: busybox command: - sleep - "3600" volumeMounts: - name: gluster-volume mountPath: "/pv-data" readOnly: false volumes: - name: gluster-volume persistentVolumeClaim: claimName: pvc-gluster-heketi
#kubelet create -f pod-use-pvc.yaml #建立這個pod
而後進入容器:
#kubelet exec -it pod-use-pvc /bin/sh
在其中的/pv-data 目錄建立文件,而後驗證文件在GlusterFS集羣中是否生效!
文章內容參考至《kubernetes權威指南》