本文是介紹Kubernetes的基本概念的系列文章之一, 在第一篇文章中,咱們簡單介紹了持久卷(Persistent Volumes)。在本文中,咱們將學習如何設置數據持久性,並將編寫Kubernetes腳本以將咱們的Pod鏈接到持久卷。在此示例中,將使用Azure文件存儲(Azure File Storage)來存儲來自咱們MongoDB數據庫的數據,但您可使用任何類型的捲來實現相同的結果(例如Azure Disk,GCE持久磁盤,AWS彈性塊存儲等)。前端
若是你想全面瞭解K8S其餘概念的話,可以先查看此前發佈的文章。git
請注意:本文提供的腳本不限定於某個平臺,所以您可使用其餘類型的雲提供商或使用具備K3S的本地集羣實踐本教程。本文建議使用K3S,由於它很是輕,全部的依賴項被打包在單個二進制中包裝大小小於100MB。它也是一種高可用的認證的Kubernetes發行版,用於在資源受限環境中的生產工做負載。想了解更多信息,請查看官方文檔:github
https://docs.rancher.cn/k3s/數據庫
在開始本教程以前,請確保已安裝Docker。同時安裝Kubectl(若是沒有,請訪問如下連接安裝:windows
https://kubernetes.io/docs/tasks/tools/#install-kubectl-on-windows後端
在kubectl Cheat Sheet.中能夠找到整個本教程中使用的kubectl命令:api
https://kubernetes.io/docs/reference/kubectl/cheatsheet/網絡
本教程中,咱們將使用Visual Studio Code,您也可使用其餘的編輯器。app
請記住,咱們有一個節點(硬件設備或虛擬機)和在節點內部,咱們有一個Pod(或多個Pod),在Pod中,咱們有容器。Pod的狀態是暫時的,因此他們神出鬼沒(時常會被刪除或從新調度等)。在這種狀況下,若是你想在Pod被刪除以後已經保存其中的數據,你須要數據移動到Pod外部。這樣它就能夠獨立於任何Pod存在。此外部位置稱爲卷,它是存儲系統的抽象。使用卷,您能夠在多個Pod保持持久化狀態。運維
當容器開始被普遍應用時,它們旨在支持無狀態工做負載,其持久性數據存儲在其餘地方。從那時起,人們作了不少努力以支持容器生態系統中的有狀態應用。
每一個項目都須要某種數據持久性,所以,您一般須要一個數據庫來存儲數據。但在簡潔的設計中,你不想依賴具體的實現;您想寫一個儘量能夠重複使用和獨立於平臺的應用程序。
一直以來,始終須要嚮應用程序隱藏存儲實現的詳細信息。但如今,在雲原生應用的時代,雲提供商建立了的環境中,想要訪問數據的應用程序或用戶須要與特定存儲系統集成。例如,許多應用程序直接使用特定存儲系統,諸如Amazon S三、AzureFile或塊存儲等,這形成了不健康的依賴。Kubernetes正在嘗試經過建立一個名爲持久卷的抽象來改變這一狀況,它容許雲原生應用程序鏈接到各類雲存儲系統,而無需與這些系統創建明確的依賴關係。這可使雲存儲的消耗更加無縫和消除集成成本。它還能夠更容易地遷移雲並採用多雲策略。
即便有時候,因爲金錢,時間或人力等客觀條件的限制,你須要作出一些妥協,將你的應用程序與特定的平臺或提供商直接耦合,您應該儘可能避免儘量多的直接依賴項。從實際數據庫實現中解耦應用程序的一種方法(還有其餘解決方案,但這些解決方案更加複雜)是使用容器(和持久捲來防止數據丟失)。這樣,您的應用程序將依賴於抽象而不是特定實現。
如今真正的問題是,咱們是否應該老是使用帶有持久性卷的容器化數據庫,或者哪些存儲系統類型不該該在容器中使用?
什麼時候使用持久卷並無通用的黃金法則,但做爲起點,您應該考慮可擴展性和集羣中節點丟失的處理。
根據可擴展性,咱們能夠有兩種類型的存儲系統:
像MySQL、Postgres、Microsoft SQL等垂直伸縮的解決方案不該進入容器。這些數據庫平臺須要高I / O、共享磁盤、塊存儲等,而且不能優雅地處理集羣中的節點丟失,這一般發生在基於容器的生態系統中。
對於水平伸縮的應用程序(Elastic、Cassandra、Kafka等),您應該使用容器,由於它們能夠承受數據庫集羣中的節點丟失,而且數據庫應用程序能夠獨立地再平衡。
一般,您能夠而且應該分佈式數據庫容器化,這些數據庫使用冗餘存儲技術,能夠承受數據庫集羣中的節點丟失(Elasticsearch是一個很是好的例子)。
咱們能夠根據其生命週期和配置方式對Kubernetes捲進行分類。
考慮到卷的生命週期,咱們能夠分爲:
根據卷的配置方式,咱們能夠分爲:
在這種狀況下,Pod將直接與Volume耦合,所以它將知道存儲系統(例如,Pod將與Azure存儲賬戶耦合)。該解決方案與雲無關,它取決於具體實施而不是抽象。所以,若是可能的話儘可能避免這樣的解決方案。它惟一的優勢是速度快,在Pod中建立Secret,並指定應使用的Secret和確切的存儲類型。
建立Secret腳本以下:
apiVersion: v1 kind: Secret metadata: name: static-persistence-secret type: Opaque data: azurestorageaccountname: "base64StorageAccountName" azurestorageaccountkey: "base64StorageAccountKey"
在任何Kubernetes腳本中,在第2行咱們指定了資源的類型。在這種狀況下,咱們稱之爲Secret。在第4行,咱們給它一個名字(咱們稱之爲靜態,由於它是由管理員手動建立的,而不是自動生成的)。從Kubernetes的角度來看,Opaque類型意味着該Secret的內容(數據)是非結構化的(它能夠包含任意鍵值對)。要了解有關Kubernetes Secrets的更多信息,能夠參閱Secrets Design Document和ConfigureKubernetes Secrets。
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/auth/secrets.md
https://kubernetes.io/docs/concepts/configuration/secret/
在數據部分中,咱們必須指定賬戶名稱(在Azure中,它是存儲賬戶的名稱)和Access鍵(在Azure中,選擇存儲賬戶下的「Settings 」,Access key)。別忘了二者應該使用Base64進行編碼。
下一步是修改咱們的Deployment腳本以使用卷(在這種狀況下,卷是Azure File Storage)。
apiVersion: apps/v1 kind: Deployment metadata: name: user-db-deployment spec: selector: matchLabels: app: user-db-app replicas: 1 template: metadata: labels: app: user-db-app spec: containers: - name: mongo image: mongo:3.6.4 command: - mongod - "--bind_ip_all" - "--directoryperdb" ports: - containerPort: 27017 volumeMounts: - name: data mountPath: /data/db resources: limits: memory: "256Mi" cpu: "500m" volumes: - name: data azureFile: secretName: static-persistence-secret shareName: user-mongo-db readOnly: false
咱們能夠發現,惟一的區別是,從第32行咱們指定了使用的卷,給它一個名稱並指定底層存儲系統的確切詳細信息。secretName必須是先前建立的Secret的名稱。
Kubernetes存儲類
要了解靜態或動態配置,首先咱們必須瞭解Kubernetes存儲類。
經過StorageClass,管理員能夠提供關於可用存儲的配置文件或「類」。不一樣的類可能映射到不一樣服務質量級別,或備份策略或由集羣管理員肯定的任意策略。
例如,你能夠有一個在HDD上存儲數據的配置文件,命名爲慢速存儲,或一個在SSD上存儲數據的配置文件,命名爲快速存儲。這些存儲的類型由供應者肯定。對於Azure,有兩種提供者:AzureFile和AzureDisk(區別在於AzureFile能夠與Read Wriite Many訪問模式一塊兒使用,而AzureDisk只支持Read Write Once訪問,當您但願同時使用多個Pod時,這多是不利因素)。您能夠在此處瞭解有關不一樣類型的Storage Classes:
https://kubernetes.io/docs/concepts/storage/storage-classes/
如下是Storage Class的腳本:
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: azurefilestorage provisioner: kubernetes.io/azure-file parameters: storageAccount: storageaccountname reclaimPolicy: Retain allowVolumeExpansion: true
Kubernetes預約義提供者屬性的值(請參閱Kubernetes存儲類)。保留回收策略意味着在咱們刪除PVC和PV以後,未清除實際存儲介質。咱們能夠將其設置爲刪除和使用此設置,一旦刪除PVC,它也會觸發相應的PV以及實際存儲介質(此處實際存儲是Azure文件存儲)的刪除。
持久卷及Persistent Volume Claim
Kubernetes對每個傳統的存儲操做活動(供應/配置/附加)都有一個匹配的原語。持久卷是供應,存儲類正在配置,而且持久卷Claim是附加的。
來自初始文檔:
*Persistent Volume(PV)是集羣中的存儲,它已由管理員配置或使用存儲類動態配置。
Persistent Volume Claim(PVC)是用戶存儲的請求。它相似於Pod。Pod消耗節點資源與PVC消耗PV資源是相似的。Pod能夠請求特定的資源級別(CPU和內存)。Claim能夠請求特定的大小和訪問模式(例如,它們能夠安裝一次讀/寫或屢次只讀)。
這意味着管理員將建立持久卷以指定Pod可使用的存儲大小、訪問模式和存儲類型。開發人員將建立Persistent Volume Claim,要求提供一個卷、訪問權限和存儲類型。這樣一來,在「開發側」和「運維側」之間就有了明顯的區分。開發人員負責要求必要的卷(PVC),運維人員負責準備和配置要求的卷(PV)。
靜態和動態配置之間的差別是,若是沒有持久卷和管理員手動建立的Secret,Kubernetes將嘗試自動建立這些資源。*
在這種狀況下,沒有手動建立的持久卷和Secret,所以Kubernetes將嘗試生成它們。Storage Class是必要的,咱們將使用在前文中建立的Storage Class。
PersistentVolumeClaim的腳本以下所示:
apiVersion: v1 kind:Persistent Volume Claim metadata: name: persistent-volume-claim-mongo spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi storageClassName: azurefilestorage
以及咱們更新的Deployment腳本:
apiVersion: apps/v1 kind: Deployment metadata: name: user-db-deployment spec: selector: matchLabels: app: user-db-app replicas: 1 template: metadata: labels: app: user-db-app spec: containers: - name: mongo image: mongo:3.6.4 command: - mongod - "--bind_ip_all" - "--directoryperdb" ports: - containerPort: 27017 volumeMounts: - name: data mountPath: /data/db resources: limits: memory: "256Mi" cpu: "500m" volumes: - name: data Persistent Volume Claim: claimName: persistent-volume-claim-mongo
如你所見,在第34行中,咱們經過名稱引用了先前建立的PVC。在這種狀況下,咱們沒有手動爲它建立持久卷或Secret,所以它將自動建立。
這種方法的最重要的優點是您沒必要手動建立PV和Secret,並且Deployment是與雲無關的。存儲的底層細節不存在於Pod的spec中。可是也有一些缺點:您沒法配置存儲賬戶或文件共享,由於它們是自動生成的,而且您沒法重複使用PV或Secret ——它們將爲每一個新Claim從新生成。
靜態和動態配置之間的惟一區別是咱們手動建立靜態配置中的持久卷和Secret。這樣,咱們就能夠徹底控制在集羣中建立的資源。
持久卷腳本以下:
apiVersion: v1 kind: PersistentVolume metadata: name: static-persistent-volume-mongo labels: storage: azurefile spec: capacity: storage: 1Gi accessModes: - ReadWriteMany storageClassName: azurefilestorage azureFile: secretName: static-persistence-secret shareName: user-mongo-db readOnly: false
重要的是,在第12行咱們按名稱引用Storage Class。此外,在第14行咱們引用了Secret,用於訪問底層存儲系統。
本文更推薦這個解決方案,即便它須要更多的工做,但它是與雲無關的(cloud-agnostic)。它還容許您應用有關角色(集羣管理員與開發人員)的關注點分離,並讓您控制命名和建立資源。
在本文中,咱們瞭解瞭如何使用Volume持久化數據和狀態,並提出了三種不一樣的方法來設置系統,即爲直接訪問、動態配置和靜態配置,並討論了每一個系統的優缺點。
做者簡介
Czako Zoltan,一位經驗豐富的全棧開發人員,在包括前端,後端,DevOps,物聯網和人工智能等多個領域都擁有豐富的經驗。