在 Kubernetes 環境中,容器化應用程式通常需要多個容器協同工作才能完整執行。利用多容器 Pod,可以將相關的容器組合在一起,分享資源、簡化管理,並提升應用程式的可靠性和效率。本文將詳細介紹如何使用多容器 Pod,包含初始化容器的應用、容器間的資料分享,以及日誌的檢索方式。首先,我們會探討 initContainers 的使用方法,它允許在主要容器啟動前執行一些必要的初始化工作,例如設定資料函式庫、下載組態檔案等。接著,我們會介紹 emptyDir 磁碟區,它提供了一種簡單的機制,讓 Pod 中的容器分享臨時資料。同時,我們也會比較 emptyDir 和 hostPath 磁碟區的特性和使用場景,並說明 hostPath 的潛在風險。最後,我們將示範如何使用 kubectl 命令檢索特定容器的日誌,以及如何利用引數篩選和限制日誌輸出。
使用多容器Pod與設計模式
在Kubernetes中,Pod是佈署和管理容器的基本單位。有時,一個Pod中執行多個容器可以更好地滿足某些應用場景的需求。本章將探討如何在一個Pod中使用多個容器,以及相關的設計模式。
初始化容器(initContainers)
初始化容器(initContainers)是一種特殊的容器,它們在Pod中的主要容器啟動之前執行。initContainers可以用於執行一些準備工作,例如下載組態檔案、安裝依賴項、等待外部服務就緒等。
initContainers的特點
- 可以有多個initContainers,但它們會按照定義的順序依次執行,而不是平行執行。
- initContainers可以擁有自己的容器映像,這使得它們可以執行特定的任務,而不需要將這些任務包含在主要容器的映像中。
- 如果initContainer失敗,Kubernetes不會啟動主要容器。
使用initContainers的例子
以下是一個YAML檔案示例,展示瞭如何使用initContainer下載網站內容並將其複製到分享卷中:
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-init-container
labels:
environment: prod
tier: frontend
spec:
restartPolicy: Never
volumes:
- name: website-volume
emptyDir: {}
initContainers:
- name: download-website
image: busybox
command:
- sh
- -c
- |
wget https://github.com/iamgini/website-demo-one-page/archive/refs/heads/main.zip -O /tmp/website.zip && \
mkdir /tmp/website && \
unzip /tmp/website.zip -d /tmp/website && \
cp -r /tmp/website/website-demo-one-page-main/* /usr/share/nginx/html
volumeMounts:
- name: website-volume
mountPath: /usr/share/nginx/html
containers:
- name: nginx-container
image: nginx:latest
volumeMounts:
- name: website-volume
mountPath: /usr/share/nginx/html
initContainers的作用
initContainers可以用於各種準備工作,例如:
- 資料函式庫初始化:設定和組態資料函式庫。
- 組態檔案下載:下載必要的組態檔案。
- 套件安裝:安裝主要容器所需的依賴項。
- 等待外部服務:確保外部服務就緒後再啟動主要容器。
- 執行前檢查:執行必要的檢查或驗證。
- 秘密管理:安全地下載和注入秘密到主要容器的環境中。
- 資料遷移:在主要容器啟動前遷移資料到資料函式庫或儲存系統。
- 自定義檔案許可權:為主要容器設定適當的檔案許可權。
如何存取特定容器的日誌
當一個Pod中包含多個容器時,可以使用kubectl logs命令來檢索特定容器的日誌。該命令可以串流特定容器的stdout屬性,從而檢索容器的應用程式日誌。
使用kubectl logs命令
要使用kubectl logs命令,需要知道容器的名稱和其父Pod的名稱。以下是命令示例:
kubectl logs -f pods/multi-container-pod --container nginx-container
在這個命令中,--container選項(或簡寫-c)指定了要檢索日誌的容器名稱。這個選項同樣適用於initContainers,只要傳遞其名稱即可檢索其日誌。
程式碼解析:
apiVersion: v1
kind: Pod
metadata:
name: nginx-with-init-container
labels:
environment: prod
tier: frontend
spec:
restartPolicy: Never
volumes:
- name: website-volume
emptyDir: {}
initContainers:
- name: download-website
image: busybox
command:
- sh
- -c
- |
wget https://github.com/iamgini/website-demo-one-page/archive/refs/heads/main.zip -O /tmp/website.zip && \
mkdir /tmp/website && \
unzip /tmp/website.zip -d /tmp/website && \
cp -r /tmp/website/website-demo-one-page-main/* /usr/share/nginx/html
volumeMounts:
- name: website-volume
mountPath: /usr/share/nginx/html
containers:
- name: nginx-container
image: nginx:latest
volumeMounts:
- name: website-volume
mountPath: /usr/share/nginx/html
內容解密:
- 定義了一個名為
nginx-with-init-container的Pod,使用busybox映像下載網站內容,並將其複製到分享卷website-volume中。 initContainers部分定義了一個名為download-website的初始化容器,使用wget下載網站內容,並使用unzip解壓縮,最後將內容複製到/usr/share/nginx/html目錄下。containers部分定義了一個名為nginx-container的主要容器,使用nginx:latest映像,並掛載了分享卷website-volume到/usr/share/nginx/html目錄下。
這個YAML檔案展示瞭如何使用initContainer下載網站內容並將其提供給NGINX伺服器。
使用多容器 Pod 與設計模式
存取多容器 Pod 中的日誌
在處理多容器 Pod 時,瞭解如何存取容器日誌是非常重要的。除了基本的 kubectl logs 命令之外,還有其他多種有用的選項可供使用。例如,若要檢索過去兩小時內寫入的日誌,可以使用以下命令:
$ kubectl logs --since=2h pods/multi-container-pod --container nginx-container
此外,可以使用 --tail 選項來檢索日誌輸出的最近幾行。以下是具體做法:
$ kubectl logs --tail=30 pods/multi-container-pod --container nginx-container
這裡,我們檢索了 nginx-container 日誌輸出的最近 30 行。
內容解密:
--since=2h引數用於指定檢索過去兩小時內的日誌,有助於篩選出特定時間範圍內的記錄。--tail=30引數用於檢索日誌的最近 30 行輸出,方便快速檢視最新的日誌資訊。--container nginx-container用於指定要檢索日誌的容器名稱,在多容器 Pod 中至關重要。
在同一個 Pod 中的容器之間分享磁碟區
在本文中,我們將學習 Kubernetes 中的磁碟區(Volume)概念及其使用方法。Docker 也有磁碟區,但與 Kubernetes 的磁碟區不同,它們滿足相同的需求但實作方式不同。
什麼是 Kubernetes 磁碟區?
Kubernetes 有兩種磁碟區:
- 磁碟區(Volume),我們將在這裡討論。
- PersistentVolume,是一種更進階的功能,我們將在第 9 章「Kubernetes 中的持久儲存」中討論。
簡而言之,Kubernetes 中的磁碟區與 Pod 的生命週期密切相關。當您例項化一個 Pod 時,可以定義並將磁碟區掛載到其中的容器。基本上,磁碟區代表與 Pod 存在相關的儲存空間。一旦 Pod 被刪除,相關聯的磁碟區也會被刪除。
建立和掛載 emptyDir 磁碟區
顧名思義,emptyDir 是一個在 Pod 建立時初始化的空目錄,您可以將其掛載到 Pod 中執行的每個容器的指定位置。這是讓容器之間分享資料最簡單的方法。
Kubernetes 支援多種磁碟區型別,包括從主機檔案系統掛載的、雲端提供商和網路儲存系統等。一些廣泛使用的解決方案包括:
- hostPath
- emptyDir
- nfs
- persistentVolumeClaim(當您需要使用 PersistentVolume 時)
內容解密:
- emptyDir 磁碟區在 Pod 建立時初始化為空目錄,並可掛載到容器中,用於容器間分享資料。
- hostPath 和 nfs 等不同型別的磁碟區提供了多樣化的儲存解決方案,能夠滿足不同的需求。
- 磁碟區的生命週期與 Pod 相關,Pod 被刪除時,相關聯的磁碟區也會被刪除,但容器當機不會導致磁碟區被刪除。
圖表說明:hostPath 和 emptyDir 磁碟區
此圖示展示了 hostPath 和 emptyDir 磁碟區的基本概念。
@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
內容解密:
- 此圖示闡述了 Pod 與 emptyDir 和 hostPath 磁碟區之間的關係。
- emptyDir 被多個容器分享,而 hostPath 直接掛載自主機檔案系統。
- 圖表清晰地展示了不同型別的磁碟區如何在 Pod 中被使用和分享。
使用多容器Pod與設計模式
在以下範例中,我們將建立一個包含兩個容器的Pod,一個是NGINX容器,另一個是Debian容器。我們將覆寫Debian容器的啟動命令,以防止它在完成後離開。這樣,我們就可以讓它無限期執行,並能夠執行額外的命令來檢查我們的emptyDir是否正確初始化。
兩個容器將分享一個掛載在/var/i-am-empty-dir-volume/的磁碟卷,這將是我們的emptyDir磁碟卷,在同一個Pod中初始化。下面是建立Pod的YAML檔案:
# multi-container-with-emptydir-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: multi-container-with-emptydir-pod
spec:
containers:
- name: nginx-container
image: nginx:latest
volumeMounts:
- mountPath: /var/i-am-empty-dir-volume
name: empty-dir-volume
- name: debian-container
image: debian
command: ["/bin/sh"]
args: ["-c", "while true; do sleep 30; done;"] # 防止容器在完成後離開
volumeMounts:
- mountPath: /var/i-am-empty-dir-volume
name: empty-dir-volume
volumes:
- name: empty-dir-volume # 磁碟卷名稱
emptyDir: {} # 初始化一個空目錄
內容解密:
apiVersion和kind定義了Kubernetes物件的版本和型別,在這裡是Pod。metadata包含了Pod的名稱。spec定義了Pod的規格,包括容器列表和磁碟卷。containers列出了Pod中的兩個容器:NGINX和Debian。volumeMounts定義了容器內掛載的磁碟卷路徑。volumes定義了Pod中的磁碟卷,在這裡是一個emptyDir。
現在,我們可以使用以下命令應用YAML檔案:
$ kubectl apply -f multi-container-with-emptydir-pod.yaml
pod/multi-container-with-emptydir-pod created
驗證Pod執行狀態
$ kubectl get po
NAME READY STATUS RESTARTS AGE
multi-container-with-emptydir-pod 2/2 Running 0 25s
確認Pod執行後,我們可以檢查兩個容器是否都能存取掛載的emptyDir:
$ kubectl exec multi-container-with-emptydir-pod -c debian-container -- ls /var
$ kubectl exec multi-container-with-emptydir-pod -c nginx-container -- ls /var
內容解密:
kubectl exec命令允許我們在容器內執行命令。-c指定了要執行命令的容器名稱。ls /var列出了/var目錄下的內容,確認emptyDir已經被正確掛載。
接下來,我們在Debian容器中建立一個檔案,並檢查它是否能在NGINX容器中被存取:
$ kubectl exec multi-container-with-emptydir-pod -c debian-container -- bin/sh -c "echo 'hello world' >> /var/i-am-empty-dir-volume/hello-world.txt"
$ kubectl exec multi-container-with-emptydir-pod -c nginx-container -- cat /var/i-am-empty-dir-volume/hello-world.txt
hello world
內容解密:
- 第一個命令在Debian容器中建立了一個名為
hello-world.txt的檔案。 - 第二個命令在NGINX容器中讀取了該檔案,證明瞭兩個容器分享了emptyDir。
使用hostPath磁碟卷
hostPath允許你將主機上的目錄掛載到Pod中的容器。這在某些情況下很有用,但由於可移植性和安全性的問題,在Kubernetes中通常被視為反模式。
建立和掛載hostPath磁碟卷
在minikube環境中,hostPath對應到本地機器的一個目錄。下面是一個使用hostPath的例子:
apiVersion: v1
kind: Pod
metadata:
name: pod-with-hostpath
spec:
containers:
- name: nginx-container
image: nginx:latest
volumeMounts:
- mountPath: /var/host-path-volume
name: host-path-volume
volumes:
- name: host-path-volume
hostPath:
path: /tmp/host-path-volume # 主機上的目錄路徑
type: DirectoryOrCreate # 如果目錄不存在,則建立它
內容解密:
hostPath定義了主機上的目錄路徑。type指定了hostPath的型別,可以是DirectoryOrCreate、Directory、FileOrCreate、File、Socket、CharDevice或BlockDevice。
總之,使用多容器Pod和不同型別的磁碟卷可以滿足多種應用場景的需求,但需要謹慎考慮可移植性和安全性。建議使用持久化卷(PV)和持久化卷宣告(PVC)來管理持久化資料,以獲得更好的可移植性和安全性。