在 Kubernetes 環境中,管理容器的儲存空間和網路連線至關重要。HostPath 提供了將主機目錄掛載到 Pod 的方法,但需注意 Pod 與節點的緊密耦合性可能帶來的排程問題。為瞭解決應用程式與外部服務的互動,Ambassador 設計模式提供了一個優雅的解決方案,透過代理容器簡化連線管理。Sidecar 設計模式則允許在不修改主容器程式碼的情況下,擴充額外的功能,例如日誌收集和監控。Kubernetes 原生 Sidecar 容器的出現,更進一步提升了 Sidecar 的生命週期管理,使其與主容器更加協同工作。此外,名稱空間、資源配額和限制的運用,能有效提升多租戶環境下的資源管理和安全性,確保叢集的穩定執行。
使用 HostPath 掛載主機目錄至容器
在 Kubernetes 中,Pod 設計的初衷是易於刪除並在其他工作節點上重新排程,而不應受到任何限制。然而,使用 hostPath 會在 Pod 與工作節點之間建立緊密的關聯,這可能導致嚴重的問題,如果 Pod 發生故障並被重新排程到另一個沒有所需主機路徑的節點上。
建立 HostPath
假設我們在工作節點上有一個檔案位於 worker-node/nginx.conf,並希望將其掛載到 nginx 容器的 /var/config/nginx.conf 路徑下。以下是一個範例的 YAML 檔案:
# multi-container-with-hostpath.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: multi-container-with-hostpath
spec:
containers:
- name: nginx-container
image: nginx:latest
volumeMounts:
- mountPath: /foo
name: my-host-path-volume
- name: debian-container
image: debian
command: ["/bin/sh"]
args: ["-c", "while true; do sleep 30; done;"] # 防止容器完成後離開
volumes:
- name: my-host-path-volume
hostPath:
path: /tmp # 工作節點上的路徑
type: Directory
內容解密:
apiVersion和kind:定義了 Kubernetes 資源的版本和型別,這裡是Pod。metadata:提供了 Pod 的中繼資料,例如名稱。spec.containers:定義了 Pod 中的容器,包括nginx-container和debian-container。volumeMounts:將my-host-path-volume掛載到nginx-container的/foo目錄。volumes.hostPath:指定了主機上的路徑/tmp,並將其型別設為Directory,表示該路徑必須在主機上存在。
在執行 YAML 清單檔案之前,需要在主機上建立所需的路徑和檔案:
$ echo "Hello World" >> /tmp/hello-world.txt
如果是使用 minikube,需要在 minikube 虛擬機器內執行上述命令:
$ minikube ssh
docker@minikube:~$ echo "Hello World" > /tmp/hello-world.txt
docker@minikube:~$ exit
若 minikube 是使用 Podman 容器建立的,則登入 minikube Pod 並建立檔案:
$ sudo podman exec -it minikube /bin/bash
root@minikube:/# cat /tmp/hello-world.txt
接著,套用 YAML 檔案到 Kubernetes 叢集,並檢查 Pod 是否正確建立:
$ kubectl apply -f multi-container-with-hostpath.yaml
pod/multi-container-with-hostpath created
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
multi-container-with-hostpath 2/2 Running 0 11s
驗證檔案是否成功掛載到容器內:
$ kubectl exec multi-container-with-hostpath -c nginx-container -- cat /foo/hello-world.txt
Hello World
大使設計模式
在大使設計模式中,多容器 Pod 被用來解決特定需求。這種模式涉及兩個容器:主容器和大使容器。主容器負責主要的應用邏輯,而大使容器則作為代理,將主容器的請求轉發到外部服務。
大使設計模式的工作原理
- 主容器:執行主要的應用程式邏輯,可能需要與外部服務(如資料函式庫)進行通訊。
- 大使容器:作為代理,接收來自主容器的請求,並將其轉發到外部服務。
此圖示說明瞭大使設計模式在 Kubernetes 中的應用: 此圖示展示了主容器如何透過大使容器與外部資料函式庫進行通訊。
內容解密:
- 主容器與大使容器的協作:主容器將請求傳送給大使容器,由大使容器負責處理和轉發。
- 外部服務的存取:大使容器負責與外部服務(如資料函式庫)進行通訊,並將結果傳回給主容器。
這種設計模式的好處在於,它允許開發人員將複雜的外部通訊邏輯與主要的應用邏輯分離,從而提高應用的可維護性和可擴充套件性。##### 重點回顧
hostPath的使用:- 將主機上的目錄或檔案掛載到容器中。
- 需要在主機上預先建立對應的目錄或檔案。
- 可能會導致 Pod 與特定節點之間的強依賴關係。
大使設計模式:
- 由主容器和大使容器組成。
- 大使容器作為代理,將主容器的請求轉發至外部服務。
- 有助於簡化應用程式與外部服務之間的通訊邏輯。
在未來的 Kubernetes 應用中,可以進一步探索其他設計模式,例如:
- Sidecar 模式:用於日誌收集、監控等輔助功能。
- Adapter 模式:統一不同介面之間的通訊標準。
這些設計模式能夠幫助開發者更好地構建和管理複雜的分散式系統。
多容器Pod與設計模式的應用
在Kubernetes中,多容器Pod的設計模式提供了靈活且強大的功能,能夠滿足不同的應用需求。其中,Ambassador(大使)與Sidecar(邊車)設計模式是兩種常見且重要的模式。
Ambassador設計模式
Ambassador容器作為代理,能夠幫助主容器存取外部資源,如資料函式庫或API。這種模式的主要優點包括:
- 將SQL組態解除安裝至Ambassador容器
- 管理SSL/TLS憑證
建立Ambassador SQL代理的範例
以下是一個YAML檔案範例,用於建立一個包含兩個容器的Pod:
nginx-app,使用nginx:latest映像sql-ambassador-proxy,使用mysql-proxy:latest映像
# ~/nginx-with-ambassador.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-ambassador
spec:
containers:
- name: mysql-proxy-ambassador-container
image: mysql-proxy:latest
ports:
- containerPort: 3306
env:
- name: DB_HOST
value: mysql.xxx.us-east-1.rds.amazonaws.com
- name: nginx-container
image: nginx:latest
內容解密:
此YAML檔案定義了一個名為nginx-with-ambassador的Pod,包含兩個容器。mysql-proxy-ambassador-container作為SQL代理,將請求轉發至指定的資料函式庫主機。nginx-container則執行NGINX服務,需組態應用程式碼以透過Ambassador容器存取資料函式庫。
Sidecar設計模式
Sidecar容器作為主容器的擴充套件,能夠提供額外的功能,如日誌收集或監控代理。這種模式的主要特點是:
- 主容器無需修改即可獲得新功能
- Sidecar容器可獨立執行,不影響主容器
Sidecar設計模式的範例
以下圖示展示了一個簡單的Sidecar設計模式,主容器執行應用程式,Sidecar容器負責收集日誌:
此圖示展示了Sidecar設計模式的基本架構。
使用Sidecar設計模式的時機
Sidecar容器在以下場景中特別有用:
- 網路代理:如Istio的“Envoy”代理,用於提供網路服務
- 增強日誌收集:Sidecar容器可持續收集日誌,即使在Pod當機的情況下也能保證日誌的完整性
- 工作任務(Jobs):Sidecar容器可與Kubernetes Jobs一起佈署,不影響任務的完成
- 憑證管理:許多第三方憑證管理平台利用Sidecar容器注入和管理憑證,提供安全的憑證輪換和復原機制
多容器Pod與設計模式的應用
在Kubernetes中,多容器Pod的設計模式提供了多種靈活的方式來組織和管理容器之間的協作。本章節將探討Sidecar和Adapter這兩種重要的設計模式,並透過實際範例來說明如何在Kubernetes叢集中有效地使用它們。
Sidecar設計模式
Sidecar設計模式透過在同一個Pod中執行多個容器,能夠增強主容器的功能而不改變其原始程式碼。Sidecar容器通常負責輔助性的任務,如日誌收集、監控或網路代理等。
Sidecar多容器Pod範例
以下是一個使用NGINX作為主容器,Fluentd作為Sidecar容器的範例。這個Pod定義了兩個容器分享同一個卷(Volume),用於儲存NGINX的日誌檔案。
# nginx-with-fluentd-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-sidecar
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: log-volume
mountPath: /var/log/nginx
- name: fluentd-sidecar
image: fluent/fluentd:v1.17
volumeMounts:
- name: log-volume
mountPath: /var/log/nginx
volumes:
- name: log-volume
emptyDir: {}
Fluentd組態
為了使Fluentd正常工作,需要透過ConfigMap傳遞組態。以下是一個典型的Fluentd組態範例,用於收集NGINX日誌並將其轉發到Elasticsearch。
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config-map
namespace: default
data:
fluentd.conf: |
<source>
@type tail
path /var/log/nginx/*.log
pos_file /var/log/nginx/nginx.log.pos
tag nginx
<parse>
@type nginx
</parse>
</source>
<match nginx.**>
@type elasticsearch
host elastic.lab.example.com
port 9200
logstash_format true
logstash_prefix fluentd
logstash_dateformat %Y.%m.%d
</match>
內容解密:
- Sidecar容器定義:在Pod定義中,除了NGINX容器外,還定義了一個Fluentd Sidecar容器,用於收集NGINX的日誌。
- 分享卷:兩個容器透過一個名為
log-volume的emptyDir卷分享日誌檔案,這使得Fluentd能夠讀取NGINX的日誌。 - Fluentd組態:透過ConfigMap組態Fluentd,使其能夠正確地收集、解析和轉發NGINX的日誌到指定的Elasticsearch伺服器。
Adapter設計模式
Adapter設計模式用於將資料從一種格式轉換為另一種格式。在Kubernetes中,這通常透過在Pod中執行一個Adapter容器來實作,該容器負責資料格式的轉換。
Adapter多容器Pod範例
以下是一個範例,展示了一個Pod中包含一個主容器(alpine-writer)和一個Adapter容器(log-adapter)。主容器寫入日誌到分享卷,Adapter容器則讀取這些日誌並將其轉換為另一種格式。
# alpine-with-adapter.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-with-adapter
spec:
containers:
- name: alpine-writer
image: alpine:latest
command: [ "sh", "-c", "i=1; while true; do echo \"$(date) - log $i\" >> /var/log/app/app.log; i=$((i+1)); sleep 5; done" ]
volumeMounts:
- name: log-volume
mountPath: /var/log/app
- name: log-adapter
image: alpine:latest
command: [ "sh", "-c", "while true; do cat /logs/app.log | sed 's/$/ PROCESSED/' > /logs/processed_app.log; cat /logs/processed_app.log; sleep 10; done" ]
volumeMounts:
- name: log-volume
mountPath: /logs
volumes:
- name: log-volume
emptyDir: {}
內容解密:
- 主容器與Adapter容器:
alpine-writer容器寫入日誌到/var/log/app/app.log,而log-adapter容器讀取這些日誌,並在每行末尾新增“PROCESSED”字樣後輸出到/logs/processed_app.log。 - 分享卷的使用:兩個容器透過名為
log-volume的分享卷交換資料。 - 資料轉換邏輯:Adapter容器使用簡單的shell命令實作日誌格式的轉換,展示了Adapter模式的簡單而有效的應用。
使用多容器Pod與設計模式
在前面的章節中,我們學習瞭如何在Kubernetes中使用Pod來管理多個容器。本章節將探討多容器Pod的應用以及相關的設計模式。
側車容器(Sidecar Containers)與原生側車容器(Kubernetes Native Sidecars)
傳統上,Kubernetes中的側車容器是與主要應用程式一起佈署在Pod中的常規容器。這種方法提供了額外的功能,但也存在一些限制。例如,側車容器可能會在主要應用程式離開後繼續執行,浪費資源。此外,Kubernetes本身並不完全瞭解側車容器及其與主要應用程式的關係。
為瞭解決這些限制,Kubernetes v1.28引入了一個新概念:原生側車容器。這些容器利用現有的初始化容器(init containers)並進行特殊組態。這允許您在Pod的initContainers部分為容器定義restartPolicy。這些特殊的側車容器可以獨立啟動、停止或重新啟動,而不會影響主要應用程式或其他初始化容器,從而提供對其生命週期的更精細控制。
以下是一個Deployment定義檔案的範例,展示瞭如何在Kubernetes中組態原生側車容器:
spec:
containers:
- name: myapp
image: alpine:latest
command: ['sh', '-c', 'while true; do echo "logging" >> /opt/logs.txt; sleep 1; done']
volumeMounts:
- name: data
mountPath: /opt
initContainers:
- name: logshipper
image: alpine:latest
restartPolicy: Always
command: ['sh', '-c', 'tail -F /opt/logs.txt']
volumeMounts:
- name: data
mountPath: /opt
volumes:
- name: data
emptyDir: {}
內容解密:
spec.containers中定義了主要應用程式容器myapp,它不斷地向/opt/logs.txt寫入日誌。spec.initContainers中定義了側車容器logshipper,它負責跟蹤/opt/logs.txt檔案的變化。restartPolicy: Always確保logshipper容器在離開後總是重新啟動。- 兩個容器都掛載了名為
data的卷,以實作資料分享。
這種方法確保了側車容器與主要容器的同步啟動和關閉,從而最佳化了資源使用。更重要的是,Kubernetes能夠更好地理解側車容器在Pod中的角色,從而可能在未來實作更緊密的整合。
名稱空間(Namespaces)、配額(Quotas)和限制(Limits)在Kubernetes中的多租戶應用
到目前為止,我們已經學習了Kubernetes的一些關鍵概念,包括如何在叢集中啟動物件並觀察其行為。然而,隨著叢集規模的增長,保持叢集的整潔和組織將變得越來越困難。這時,Kubernetes的名稱空間就派上用場了。
在本章節中,我們將學習名稱空間,它幫助我們透過按應用程式或環境分組資源來保持叢集的良好組織。Kubernetes名稱空間是Kubernetes管理的一個重要方面,掌握它們非常重要!
本章節主要內容
- Kubernetes名稱空間簡介
- 名稱空間如何影響您的資源和服務
- 在名稱空間級別組態資源配額(ResourceQuota)和限制(Limits)
技術要求
- 一個可用的Kubernetes叢集(本地或根據雲,不重要)
- 一個可用的
kubectl命令列工具,組態為與叢集通訊
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Kubernetes容器掛載與多容器Pod設計模式
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此圖示展示了名稱空間、資源配額和限制之間的關係。名稱空間是資源配額和限制的基礎,而資源配額和限制則用於管理和控制名稱空間中的資源使用。
圖示內容解密:
- 名稱空間是Kubernetes中用於隔離資源的邏輯劃分。
- 資源配額用於限制名稱空間中的資源使用總量。
- 限制用於控制名稱空間中Pod的資源使用。
- 組態資源配額和限制可以幫助管理員更好地管理叢集資源。
透過本章節的學習,您將能夠更好地理解和使用Kubernetes的名稱空間、資源配額和限制,從而提高叢集的管理效率和安全性。