iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 20
5
DevOps

Kubernetes 30天學習筆記系列 第 20

[Day 20] 如何保存 Container 中資料 - Volumes

前言

在前幾天的學習筆記中,我們使用到的 Pod 物件都是 stateless,代表著 Pod 物件中的 container 儲存的資料會隨著 container 的生命週期消失而消失,而無法被保存下來。而今天的學習筆記中,將介紹 Kubernetes 的另一個套件 Volumes,讓我們可以輕鬆打造一個 statefulPod。讓這個 Pod 中的 container 即便因為某些因素而 crash ,資料仍可完整的被保存下來,讓新產生的 container 能延續使用

今天的學習筆記如下:

  • 介紹什麼是 Volumes
  • 實作:在 AWS Kubernetes Cluster 上綁定 AWS EBS Volumes

小提醒:今天的程式碼都可以在 demo-volumes 中找到

什麼是 Volumes

Volumes 可以當成是 Kubernetes Cluster 中專們用來儲存資料的地方。不但能將 container 的資料儲存下來,也可以透過掛載(mounting)的方式,供許多個 Pods 同時存取。而 Kubernetes 也提供非常多種的 Volumes 類型,在 Kubernetes 官網中,對每個類型也都有非常詳細的介紹,若有興趣的讀者不妨參考看看。

而今天的學習筆記中,將介紹四種常用的 Volume 類型:

  • emptyDir
  • hostPath
  • Cloud Storage
  • NFS (Network FileSystem)

emptyDir

每當我們建立一個新的 Pod 物件時,Kubernetes 就會在這個 Pod 裏建立一個 emptyDir該 Pod 中所有的 container 都可以讀寫 emptyDir 中的資料。當 Pod 從 Node 中被移除時,emptyDir 也會隨之消失,emptyDir 有以下幾個用途:

  • 暫時性儲存空間
    例如某些應用程式運行時需要一些臨時而無需永久保存的資料夾
  • 共用儲存空間
    正如上述提到,同一個 Pod 中所有的 containers 都可以讀寫 emptyDir,也可以將 emptyDir 當作是這些 containers 的共用目錄

範例如下:

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

hostPath

Pod 物件上,掛載 Node 的資料夾或檔案。hostPath 的生命週期與 Node 相同,當 Pod 因某些原因而須重啟時,檔案仍保存在 Node 的檔案系統(file system)底下,直到該 Node 物件被 Kubernetes Cluster 移除,資料才會消失

hostpath-example.yaml 為例,

apiVersion: v1
kind: Pod
metadata:
  name: apiserver
spec:
  containers:
  - name: apiserver
    image: zxcvbnius/docker-demo
    volumeMounts:
    - mountPath: /tmp
      name: tmp-volume
    imagePullPolicy: Always
  volumes:
  - name: tmp-volume
    hostPath:
      path: /tmp
      type: Directory

在這個 YAML 檔中,我們把 Node 的 /tmp 掛在 apiserver 的 /tmp。當 apiserver 的 /tmp 新增檔案時,可以從 Node 的 /tmp 中底下找到該檔案,因為兩者存取相同的資源。

kubectl create 創建 apiserver 物件,指令如下:

$ kubectl create -f ./hostpath-example.yaml
pod "apiserver" created

接著,進到 apiserver 的 shell 中,找到 /tmp,並新增一個 test.txt 的檔案,

接著進到 minikube 的 shell 中,可以找到剛剛我們建立的 test.txt 檔案,

若該 Pod 遭刪除,仍會保存在 /tmp/test.txt 中供新的 Pod 物件使用。

Cloud Storage

此外,Kubernetes 也支援 AWS EBSGoogle DiskMicrosoft Azure Disk 等雲端硬碟類型的 Volumes。在今天的實作中,會介紹如何將 AWS EBS 掛載在 minikube 的 Pod 上。

NFS (Network FileSystem)

此外,Kubernetes Volumes 也支援 NFS,以 nfs-example.yaml 為例,

apiVersion: v1
kind: Pod
metadata:
  name: apiserver
spec:
  containers:
  - name: apiserver
    image: zxcvbnius/docker-demo
    ports:
      - name: api-port
        containerPort: 3000
    volumeMounts:
      - name: nfs-volumes
        mountPath: /tmp
  volumes:
  - name: nfs-volumes
    nfs:
     server: {YOUR_NFS_SERVER_URL}
     path: /

關於 Kubernetes 上更多 NFS 的範例,可參考該連結

在介紹完幾項不同類型的 Volumes 後,今天的學習筆記將帶讀著在 minikube 上掛載 Amazon Elastic Block Store

實作:在 AWS Kubernetes Cluster 上綁定 AWS EBS Volumes

若是還不熟悉怎麼在 AWS 上架設 Kubernetes 或還沒安裝 aws-cli 的讀者,不妨先閱讀 [Day 15] 介紹 kops - 在 AWS 上打造 Kubernetes Cluster (上)

透過 aws-cli 我們在本機上創建一個架設在 Oregon 且大小為 1GB 的 EBS, 指令如下:

$ aws ec2 create-volume \
> --size 1 \
> --region us-west-2 \
> --availability-zone us-west-2a \
> --volume-type gp2

{
    "VolumeId": "vol-0b29e0a08749ccef3",
    "SnapshotId": "",
    "Size": 1,
    "VolumeType": "gp2",
    "State": "creating",
    "Iops": 100,
    "CreateTime": "2018-01-08T04:38:58.885Z",
    "AvailabilityZone": "us-west-2a",
    "Encrypted": false
}

AWS 提供 5 種不同類型的 Volumes,若有興趣的讀者可以參考該連結,而在這次的實作中我們使用 一般用途的 SSD (gp2)。創建好後,我們可以在 AWS console 的 EC2 頁面中看到我們剛剛建立好的 EBS,

或是,可以從 aws ec2 指令查詢新創建的 ebs 的詳細資料,指令如下,

$ aws ec2 describe-volumes --region us-west-2

{
    "Volumes": [
        {
            "Size": 1,
            "SnapshotId": "",
            "VolumeId": "vol-0b29e0a08749ccef3",
            "Attachments": [],
            "CreateTime": "2018-01-08T04:38:58.885Z",
            "AvailabilityZone": "us-west-2a",
            "VolumeType": "gp2",
            "State": "available",
            "Encrypted": false,
            "Iops": 100
        }
    ]
}

建立好 ebs 物件後,我們需要透過架設在 AWS 的 Kubernetes Cluster 中建立一個 pod,且這個 pod 掛載 ebs。以 aws-ebs-example.yaml 內容為例:

apiVersion: v1
kind: Pod
metadata:
  name: apiserver
spec:
  containers:
  - name: apiserver
    image: zxcvbnius/docker-demo
    ports:
      - name: api-port
        containerPort: 3000
    volumeMounts:
      - name: aws-ebs-volumes
        mountPath: /tmp
  volumes:
  - name: aws-ebs-volumes
    awsElasticBlockStore:
     # replace to your volumeID
     volumeID: vol-0b29e0a08749ccef3

在這個設定檔中,我們希望這個 vol-0b29e0a08749ccef3 物件掛載在 apiserver/tmp 資料夾底下。透過 kubectl create 創建,

$ kubectl create -f ./aws-ebs-example.yaml
pod "apiserver" created

成功之後,用 kubectl describe 查看,可以發現在

$ kubectl describe pod apiserver

....
Volumes:
  aws-ebs-volumes:
    Type:  AWSElasticBlockStore 
    VolumeID:   vol-0b29e0a08749ccef3

Volumes 欄位底下看到我們掛載的 vol-0b29e0a08749ccef3。如此一來,當我們在 apiserver/tmp 資料夾底下,新增或修改的檔案都會存放在 EBS 中。即便 apiserver 不存在了,當下次新的 Pod 一樣可以從 vol-0b29e0a08749ccef3 找到資料。

最後但也是最重要的是,AWS Elastic Block Store 使用上有一個很大的限制是:AWS EBS 只能被綁定在 EC2 中,也就是 Node 一定要架設在 AWS 上,才能綁定 EBS。請讀者在使用 EBS 時務必留意囉。

總結

在最後的實作中,我們透過 aws-cli 的指令來產生一個 AWS EBS 物件。明天的學習筆記中將介紹, Kuberntes 提供了我們另一個方式,讓我們不再需要透過外部指令,可以從 Kebuctl 指令 會 YAML 設定檔動態產生我們需要的 Volumes。對運維以及管理多個 Volumes,也非常有幫助!

Q&A

最後,歡迎大家給予建議與討論,如果能按個讚給些鼓勵也是很開心唷 :)

參考連結


上一篇
[Day 19] 在 Kubernetes 中實現負載平衡 - Ingress Controller
下一篇
[Day21] 如何動態提供 & 管理儲存資源 - Storage Class & PersistentVolumeClaim
系列文
Kubernetes 30天學習筆記30

尚未有邦友留言

立即登入留言