Kubernetes 叢集的狀態管理通常採用宣告式方法,透過 YAML 檔案定義應用程式的期望狀態。相較於命令式方法,宣告式組態更易於理解、複製和版本控制。版本控制工具如 Git,以及程式碼審查流程,對於管理 Kubernetes 組態變更至關重要。良好的檔案系統組織結構,例如以目錄區分應用程式服務和子元件,有助於提高組態的可維護性。Deployment 資源是管理複製應用程式的核心,它可以根據 Pod 範本自動擴充套件和更新應用程式。在佈署過程中,使用不可變的映像檔版本標籤是最佳實踐,例如結合語義版本和建置提交的 SHA 雜湊。
在Kubernetes中管理組態檔與建立複製服務
在探討如何在Kubernetes中構建應用程式之前,瞭解如何管理組態本身是非常重要的。在Kubernetes中,一切都是以宣告式的方式呈現。這意味著你需要在叢集(通常是YAML或JSON檔案)中寫下應用程式的期望狀態,這些宣告的期望狀態定義了應用程式的所有部分。
宣告式組態管理
相較於命令式方法,宣告式方法更為可取。命令式方法會使叢集的狀態成為一系列變更的總和,這使得理解和複製叢集狀態變得困難。在宣告應用程式狀態時,人們通常更喜歡使用YAML而不是JSON,因為YAML的可讀性和可編輯性更高。
YAML與JSON的比較
- YAML比JSON更具可讀性和可編輯性
- YAML對縮排敏感,錯誤的縮排可能導致Kubernetes組態錯誤
- 大多數編輯器都支援JSON和YAML的語法高亮顯示
管理宣告式狀態
由於YAML檔案中包含的宣告式狀態是應用程式的真實來源,因此正確管理這個狀態對於應用程式的成功至關重要。在修改應用程式的期望狀態時,你需要能夠管理變更、驗證其正確性、稽核變更者,並在必要時回復變更。幸運的是,在軟體工程領域,我們已經開發出了管理宣告式狀態變更以及稽核和回復的工具。版本控制和程式碼審查的最佳實踐可以直接應用於管理應用程式的宣告式狀態。
版本控制與程式碼審查
- 大多數人將Kubernetes組態儲存在Git中
- 程式碼審查對於組態管理至關重要,應當與原始碼管理一樣受到重視
檔案系統組織
在組織應用程式的檔案系統時,使用目錄結構來組織元件是一個好方法。通常,一個單獨的目錄用於包含一個應用服務。在該目錄中,子目錄用於應用程式的子元件。
範例:日誌應用程式的檔案結構
journal/
frontend/
redis/
fileserver/
每個目錄中都包含定義服務所需的具體YAML檔案。
使用佈署建立複製服務
要描述我們的應用程式,我們將從前端開始,然後逐步向下。前端應用程式是一個使用TypeScript實作的Node.js應用程式。它在8080埠上公開了一個HTTP服務,用於處理/api/*路徑的請求,並使用Redis後端新增、刪除或傳回當前的日誌條目。
最佳實踐:映像檔管理
- 根據知名和可信的映像檔提供者建立映像檔
- 為映像檔使用不可變的版本標籤,例如結合語義版本和建置提交的SHA雜湊(例如:
v1.0.1-bfeda01f)
建立複製應用程式
由於前端應用程式是無狀態的,我們可以任意複製它而不會影響流量。在Kubernetes中,ReplicaSet資源直接管理特定版本容器化應用程式的複製。然而,由於所有應用程式的版本都會隨著程式碼修改而變化,直接使用ReplicaSet並不是最佳實踐。相反,你應該使用Deployment資源。
Deployment資源範例
apiVersion: apps/v1
kind: Deployment
metadata:
name: journal-frontend
spec:
replicas: 3
selector:
matchLabels:
app: journal-frontend
template:
metadata:
labels:
app: journal-frontend
spec:
containers:
- name: journal-frontend
image: your-container-image-name:v1.0.1-bfeda01f
ports:
- containerPort: 8080
內容解密:
apiVersion和kind定義了Kubernetes資源的型別和版本。metadata提供了資源的中繼資料,如名稱。spec定義了資源的期望狀態,包括複本數量、選擇器和容器範本。replicas指定了要執行的Pod數量。selector和template.labels用於匹配由Deployment管理的Pod。containers列出了容器規格,包括映像檔名稱和埠組態。
Kubernetes 佈署與服務設定詳解
佈署資源組態
在 Kubernetes 中,佈署(Deployment)是一種管理應用程式生命週期的資源物件。以下是一個典型的 Deployment 組態範例:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: frontend
name: frontend
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- image: my-repo/journal-server:v1-abcde
imagePullPolicy: IfNotPresent
name: frontend
resources:
requests:
cpu: "1.0"
memory: "1G"
limits:
cpu: "1.0"
memory: "1G"
內容解密:
- apiVersion 與 kind:指定 Kubernetes 資源的 API 版本和型別,這裡是
apps/v1版本的 Deployment。 - metadata:包含 Deployment 的中繼資料,如名稱、名稱空間和標籤。
- spec:定義 Deployment 的規格,包括副本數量、選擇器和容器範本。
- replicas:指定要執行的 Pod 副本數量,這裡設定為 2 以確保高用性。
- selector 和 template.labels:使用標籤選擇器將 Deployment 與其管理的 Pod 相關聯。
- containers:定義容器相關設定,包括映像檔、映像檔提取策略和資源請求與限制。
資源請求與限制的重要性
在容器設定中,requests 和 limits 是兩個重要的資源管理引數:
requests:保證容器在節點上獲得的最低資源量。limits:容器被允許使用的最大資源量。
將 requests 設定為等於 limits 可以提供可預測的應用程式行為,但可能會導致資源利用率降低。對於初學者來說,這是一個穩妥的做法。
佈署到 Kubernetes
定義好 Deployment 後,將其提交到版本控制系統並佈署到 Kubernetes 叢集:
git add frontend/deployment.yaml
git commit -m "Added deployment" frontend/deployment.yaml
kubectl apply -f frontend/deployment.yaml
採用 GitOps 實踐
為了確保叢集狀態與版本控制系統一致,建議採用 GitOps 方法,透過 CI/CD 自動化佈署。這種方法不僅能確保一致性,還能提高佈署效率和可靠性。
設定外部 Ingress 以處理 HTTP 流量
要讓外部能夠存取應用程式,需要建立 Service 和 Ingress 資源。
Service 組態範例:
apiVersion: v1
kind: Service
metadata:
labels:
app: frontend
name: frontend
namespace: default
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: frontend
type: ClusterIP
Ingress 組態與注意事項:
Ingress 需要一個 Ingress 控制器來運作。可以選擇雲端供應商提供的實作,或使用開源方案如 nginx 或 haproxy Ingress 提供者。建議使用 Helm 管理 Ingress 控制器的安裝和維護。
為什麼使用 Ingress?
Ingress 提供根據 HTTP 路徑和主機的智慧路由,即使是簡單的應用程式,使用 Ingress 也能為未來的擴充套件提供靈活性。
Kubernetes 基本服務設定進階
在前面的章節中,我們已經建立了一個基本的 Kubernetes 服務,並透過 Ingress 資源將其暴露給外部世界。本章節將探討如何使用 ConfigMaps 和 Secrets 來組態和管理應用程式。
使用 ConfigMaps 組態應用程式
每一個應用程式都需要一定的組態,例如每頁顯示的期刊條目數量、特定背景的顏色或是特殊的節日展示。將這些組態資訊與應用程式本身分離是一種最佳實踐。這樣做有幾個原因:首先,你可能需要根據不同的環境(例如歐洲或中國)使用不同的組態;其次,將組態與應用程式分離可以提高敏捷性,快速啟動或停用功能。
在 Kubernetes 中,這種組態由一個名為 ConfigMap 的資源表示。ConfigMap 包含多個鍵值對,代表組態資訊或檔案。這些組態資訊可以透過檔案或環境變數呈現給容器中的應用程式。
建立 ConfigMap
假設我們想要組態線上期刊應用程式,以顯示每頁可組態的期刊條目數量。我們可以建立一個名為 frontend-config 的 ConfigMap,如下所示:
kubectl create configmap frontend-config --from-literal=journalEntries=10
在 Deployment 中使用 ConfigMap
要在應用程式中使用 ConfigMap,我們需要在 Deployment 的容器資源中新增環境變數。例如:
# The containers array in the PodTemplate inside the Deployment
containers:
- name: frontend
...
env:
- name: JOURNAL_ENTRIES
valueFrom:
configMapKeyRef:
name: frontend-config
key: journalEntries
...
版本控制和更新 ConfigMap
在實際的 Deployment 中,我們需要定期更新 ConfigMap。為了避免直接更新 ConfigMap 導致的問題,我們可以在 ConfigMap 的名稱中加入版本號,例如 frontend-config-v1。當需要更新時,建立新的 v2 ConfigMap,並更新 Deployment 資源以使用新的組態。這樣可以觸發 Deployment 的滾動更新,並保留版本控制。
使用 Secrets 管理身份驗證
在真實的應用程式中,我們需要保護服務之間的連線安全。在本例中,Redis 資料函式庫使用簡單的密碼進行身份驗證。將密碼儲存在原始碼或映像檔中並不是一個好主意,因為這可能會洩露秘密。
建立 Secret
我們可以使用以下命令建立一個名為 redis-passwd 的 Secret:
kubectl create secret generic redis-passwd --from-literal=passwd=${RANDOM}
使用 Secret
建立 Secret 後,我們需要將其繫結到執行中的應用程式。可以使用 Kubernetes Volume 將 Secret 掛載到容器中的指定位置。
程式碼範例:ConfigMap 和 Secret 的綜合使用
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-deployment
spec:
replicas: 3
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: frontend:latest
env:
- name: JOURNAL_ENTRIES
valueFrom:
configMapKeyRef:
name: frontend-config-v1
key: journalEntries
volumeMounts:
- name: redis-passwd
mountPath: /etc/redis-passwd
readOnly: true
volumes:
- name: redis-passwd
secret:
secretName: redis-passwd
內容解密:
此 Deployment 資源定義了一個名為 frontend-deployment 的佈署,使用 frontend:latest 映象,並設定了環境變數 JOURNAL_ENTRIES 從 frontend-config-v1 ConfigMap 中取得。同時,將 redis-passwd Secret 掛載到 /etc/redis-passwd 目錄下,以供應用程式使用。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Kubernetes組態管理與複製服務佈署
package "Kubernetes Cluster" {
package "Control Plane" {
component [API Server] as api
component [Controller Manager] as cm
component [Scheduler] as sched
database [etcd] as etcd
}
package "Worker Nodes" {
component [Kubelet] as kubelet
component [Kube-proxy] as proxy
package "Pods" {
component [Container 1] as c1
component [Container 2] as c2
}
}
}
api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2
note right of api
核心 API 入口
所有操作經由此處
end note
@enduml圖表翻譯: 此圖表展示了 ConfigMap 和 Secret 如何被用於 Deployment 中。ConfigMap 透過環境變數的方式被傳遞給 Deployment,而 Secret 則是透過 Volume 的方式被掛載到容器中。這樣的設計使得應用程式的組態和秘密可以被安全地管理和使用。
在 Kubernetes 中管理身份驗證與佈署狀態服務
在容器化的應用程式中,管理敏感資訊(如密碼、API 金鑰等)是一項重要的安全任務。Kubernetes 提供了 Secrets 資源來安全地儲存和分發這些敏感資訊。
使用 Secrets 管理身份驗證
Kubernetes 中的 Secrets 允許將敏感資訊儲存在叢集中,並將其掛載到需要它的 Pod 中。這確保了即使主機被物理入侵,攻擊者也難以取得這些敏感資訊。
預設情況下,Kubernetes 中的 Secrets 是未加密儲存的
若要加密儲存 Secrets,可以與金鑰提供者整合,以獲得 Kubernetes 用於加密叢集中所有 Secrets 的金鑰。需要注意的是,雖然這可以保護 Secrets 免受對 etcd 資料函式庫的直接攻擊,但仍需確保透過 Kubernetes API 伺服器的存取是安全的。
將 Secret Volume 新增至 Deployment
要在 Deployment 中新增 Secret Volume,需要在 Deployment 的 YAML 檔案中指定兩個新的條目。第一個是 Pod 中的 Volume 條目,用於新增 Volume 至 Pod:
volumes:
- name: passwd-volume
secret:
secretName: redis-passwd
若使用 Container Storage Interface (CSI) 驅動程式,則 Volume 的設定會有所不同:
volumes:
- name: passwd-volume
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "azure-sync"
將 Volume 掛載至容器
定義好 Volume 後,需要透過容器描述中的 volumeMounts 欄位將其掛載至特定的容器中:
volumeMounts:
- name: passwd-volume
readOnly: true
mountPath: "/etc/redis-passwd"
這樣就將 Secret Volume 掛載至 /etc/redis-passwd 目錄,供客戶端程式碼存取。
組合完整的 Deployment 設定
結合上述設定,完整的 Deployment YAML 如下:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: frontend
name: frontend
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- image: my-repo/journal-server:v1-abcde
imagePullPolicy: IfNotPresent
name: frontend
volumeMounts:
- name: passwd-volume
readOnly: true
mountPath: "/etc/redis-passwd"
resources:
requests:
cpu: "1.0"
memory: "1G"
limits:
cpu: "1.0"
memory: "1G"
volumes:
- name: passwd-volume
secret:
secretName: redis-passwd
將密碼掛載至 Redis Pod
同樣地,可以將密碼掛載至 Redis Pod,並從檔案中載入密碼,以實作對 Redis 服務的身份驗證。
佈署簡單的狀態服務資料函式庫
佈署狀態服務(如資料函式庫)比佈署無狀態客戶端更為複雜,因為狀態服務需要持久化儲存。Kubernetes 中的 Pod 可能因各種原因被重新排程,這可能導致資料丟失。
使用 PersistentVolumes 管理狀態
為瞭解決這個問題,Kubernetes 使用 PersistentVolumes 來管理與應用程式相關的狀態。PersistentVolumes 可以是遠端儲存,透過某種網路協定掛載。
#### 內容解密:
在上述設定中,我們使用了 PersistentVolumeClaim 來請求儲存資源。這使得我們的 StatefulSet 可以在不同的雲端和本地環境中移植。同時,這也允許每個 Pod 獲得其自己的 PersistentVolume,確保了資料的持久化和安全性。
使用 StatefulSet 佈署 Redis 服務
StatefulSet 資源提供了比 ReplicaSet 更強的保證,例如一致的名稱和明確的擴充套件順序。對於佈署單例或複製狀態服務非常方便。
#### 內容解密:
使用 StatefulSet 和 PersistentVolumeClaim,我們可以佈署一個具有持久化儲存的 Redis 服務。這確保了即使 Pod 被重新排程,資料也不會丟失。同時,這種方法也提供了更好的可移植性和擴充套件性。