這篇文章主要介紹在 k8s 如何建立能夠保存資料的服務
當我們需要讓運行的服務資料狀態能夠在服務重開後也能保存
就需要以下 3種元件
Persistent Volume, Persistent Volume Claim, Storage Class
接下來的章節會更細部的去說明每個元件如何建立運作
在 k8s 叢集裡, 對於 storage 會有以下需求
1 Storage 不會被 Pod 的生命周期影響, 也就是與 Pod 不同生命周期
2 可以被所有結點都可以存取
3 需要能夠保存下來, 即使 k8s 叢集毀損
k8s 透過 PersistentVolume 元件來符合3個條件
Persistent Volume 是 k8s 設計來與實際 Storage 互動的介面
實體連接的類型可以是 k8s 叢集所在本機實體硬碟, 可以遠端的網路硬碟系統例如 nfs server, 或是雲端硬碟
使用 NFS storage 的設定檔案如下:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-name
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessMode:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.0
nfs:
path: /dir/path/on/nfs/server
server: nfs-server-ip-address
使用 google cloud storage 設定如下:
apiVersion: v1
kind: PersistentVolume
metadata:
name: test-volume
labels:
failure-domain.beta.kubernetes.io/zone: us-central1-a__us-central1-b
spec:
capacity:
storage: 400Gi
accessModes:
- ReadWriteOnce
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
而使用 local storage 的設定檔案如下:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
spec:
capacity:
storage: 100Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- example-node
可以看到, 關鍵在於 spec 部份
除了 capacity 設定是類似的
其他選項會根據實際連結的 Storage 不同而改變
k8s 支援的 Storage 可以在官網 查到
這邊不做細部解說
而關於 PersistentVolume 設定檔細節會鐵人30天後續的章節講到, 這邊只說概念性的講解
這邊要注意的是 PersistentVolume 不屬於 namespace 之內
所以基本上在 k8s 叢集, 所有 namespace 都可以存取的到 PersistentVolume 的資源
把 k8s 支援的 Volume 類型把實連接的儲存實體是否在cluster本機來分
可分為 Local 跟 Remote
其中 Local 類的不符合一開始所說的 Storage 需求第2, 3項
因此如果要建制資料庫類的資料建議使用 Remote 類型較好
k8s Administrator 負責架設 k8s 叢集, 並且負責維護 k8s 叢集的人
k8s User 指的是使用 k8s 叢集建立應用資源 ,發佈應用在 k8s 叢集上的人, 通常會是應用開發者
而 Storage 資源必須要在發佈應用之前就設定好, 因此建立 Storage 配置跟建制 PersistentVolume 是 k8s Administractor 的工作
這個元件是用來跟叢集宣告應用需要哪些 Storage 資源
以下是 PersistentVolumeClaim 的設定檔範例
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-name
spec:
storageClassName: manual
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
一旦 PersistentVolumeClaim 設定好
k8s 叢集就會自動分配符合需求的 PersistentVolume 給那個使用對應 PersistentVolumeClaim 的 Pod
而在 Pod 設定檔裡可以指定要使用哪個 PersistentVolumeClaim
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfronennd
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolume:
claimName: pvc-name
整個 Volume 對應流程如下圖:
特別要注意的是 Pod 跟 PersistentVolumeClaim 需要在同一個 Namespace
而 PersistentVolume 則是叢集內的全域物件
從以下的設定檔
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfronennd
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolume:
claimName: pvc-name
可以知道掛載的部份
分為兩個階段
第一階段, 透過 PersistentVolumeClaim 的名稱 pvc-name
k8s 叢集會把 Volume 掛載到 Pod
第二階段, 在 Container 的 volumeMount 透過名稱 mypd
k8s 叢集會把掛載到 Pod 的 Volume 掛載到 Container 上
對開發應者來說, 可以專注在應用層的開發, 不需要去擔憂 Storage 的來源或是設定
只要在應用端寫出應用所需的 Storage 資源給 k8s 資源及可
在前面有提過這兩個元件
這兩個元件屬於 Local Volume
而不是透過 PersistentVolume 與 PersistentVolumeClaim 產生出來的
由 k8s 叢集自行管理
對於 prometheus 這類需要設定檔跟機敏資料檔的應用
假設需要一個在運行去時去存取
就是使用 ConfigMap 跟 Secret
然後掛載到 Pod 跟 Container 內
而掛載範例如下:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: busybox-container
image: busybox
volumeMounts:
- name: config-dir
mountPath: /etc/config
volumes:
- name: config-dir
configMap:
name: bb-configmap
另外, 可以同時在一個同時使用多種類型的 Volume
如前面所述, 每當 k8s User 需要 Storage
需要跟 k8s Administractor 去要求開出需要的 PersistentVolume
給次都要這樣做會變成很煩瑣的過程
因此, k8s 提供一個選項 Storage Class
讓 PersistentVolume 能夠動態新增當 k8s User 發出 PersistentVolumeClaim 時
以下是 StorageClass 的範例
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: storage-class-name
provisioner: kubernetes.io/aws-ebs
parameters:
type: io1
iopsPerGB: "10"
fsType: ext4
注意的是 provisioner 是代表 Storage 的後台伺服器
每個 Storage 後台服務都有屬於自己的 provisioner, 可以查詢k8s 官網文件
當有 PersistentVolumeClaim 發出時, StorageClass 就會跟 provisioner 發請求新增 PersistentVolume
provisioner 分為兩種一種是 internal provisioner(只要是 kubernete.io 開頭的)
另一種則是 external provisioner
parameter 部份則是對於 storage 的一些需求規格
基本上會在 PersistentVolumeClaim 宣告
範例如下:
apiVersion: v1
kind: PersistenVolumeClaim
metadata:
name: mypvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: storage-class-name
實際運作flow 如下圖: