KinD 提供了在 Docker 容器內執行 Kubernetes 叢集的便捷方法,非常適合開發和測試環境。透過簡單的指令即可快速建立和刪除叢集,有效節省資源並簡化佈署流程。理解 Kubernetes 的核心物件如 Pod、Service、Deployment 等,是建構和管理容器化應用程式的基礎。本文將逐步引導讀者使用 KinD 建立多節點叢集,並透過 kubectl 進行互動和管理,同時涵蓋持久化儲存的設定與網路連線的注意事項。
深入理解 KinD 的運作機制,有助於釐清主機、Docker 和 Kubernetes 節點之間的關係。KinD 叢集的網路設定和埠轉發是確保應用程式可被外部存取的關鍵。本文將詳細說明如何設定 NodePort 服務,讓外部網路可以存取叢集內部的應用程式。此外,持久化儲存對於資料的儲存至關重要,本文也將介紹如何使用 local-path-provisioner 來實作自動供應 PersistentVolumeClaims 的功能,確保資料的永續性。最後,本文也將提供安裝 KinD、kubectl 和 Go 的步驟,以及一些常見的挑戰和解決方案,幫助讀者更好地理解和使用 KinD。
使用 KinD 佈署 Kubernetes 叢集
在本章中,我們將介紹如何使用 KinD(Kubernetes-in-Docker)工具來佈署 Kubernetes 叢集。KinD 允許我們在單一主機上使用容器來建立多節點的 Kubernetes 叢集。
KinD 的優勢
使用 KinD 可以節省資源、快速建立和刪除叢集,並且可以輕鬆地指令碼化叢集建立過程。
建立 KinD 叢集
首先,需要安裝 KinD 工具。然後,可以使用以下命令建立一個單節點的 Kubernetes 叢集:
kind create cluster
也可以使用以下命令建立一個多節點的 Kubernetes 叢集:
kind create cluster --config kind-config.yaml
其中,kind-config.yaml 是叢集組態檔。
Kubernetes 元件與物件簡介
在開始使用 KinD 之前,我們需要了解一些基本的 Kubernetes 元件和物件。這些元件和物件包括 Pod、Service、Deployment、ReplicaSet 等。
Kubernetes 元件與物件一覽表
| 元件/物件 | 描述 |
|---|---|
| Pod | Kubernetes 中最小的可佈署單元 |
| Service | 提供 Pod 的網路介面 |
| Deployment | 管理 Pod 的佈署和更新 |
| ReplicaSet | 確保指定數量的 Pod 複本正在執行 |
在本章中,我們介紹了 Docker 網路架構和 KinD 工具的基本使用方法。在下一章中,我們將探討 Kubernetes 的基礎知識和常用物件。
使用 KinD 佈署 Kubernetes
在探討 Kubernetes 的世界時,瞭解其基本物件(objects)至關重要。這些物件包括 Pod、Service、Deployment 等,它們是構建和管理容器化應用的基礎。在本章中,我們將介紹這些基本物件,並探討如何使用 KinD(Kubernetes-in-Docker)來佈署一個 Kubernetes 叢集。
與叢集互動
為了測試我們的 KinD 安裝,我們將使用 kubectl 這個可執行檔與叢集進行互動。kubectl 是 Kubernetes 的命令列工具,用於與叢集進行通訊。我們將在第 5 章「Kubernetes Bootcamp」中詳細介紹 kubectl,但在本章中,我們將先介紹一些基本命令。
表 4.2 - 基本的 kubectl 命令
| 命令 | 說明 |
|---|---|
kubectl get nodes | 取得叢集中的節點列表 |
kubectl get pods | 取得叢集中的 Pod 列表 |
kubectl describe node <node-name> | 描述指定節點的詳細資訊 |
使用開發叢集
多年來,為了方便管理員和開發人員在本地系統上進行測試,各種安裝開發用 Kubernetes 叢集的工具應運而生。雖然這些工具能夠滿足基本的 Kubernetes 測試需求,但往往存在一些限制,使其不太適合快速、複雜的場景。
常見的解決方案
- Docker Desktop
- minikube
- kubeadm
每個解決方案都有其優缺點和適用場景。有些解決方案限制使用者只能使用單一節點執行控制平面和工作節點,而其他解決方案則提供多節點支援,但需要額外的資源來建立多個虛擬機器。
為什麼選擇 KinD?
當我們開始撰寫這本文時,我們希望能夠提供理論知識和實際操作經驗。KinD 允許我們提供指令碼來啟動和關閉叢集,而且能夠在幾分鐘內建立一個新的多節點叢集。我們希望能夠將控制平面和工作節點分開,以提供一個更真實的叢集環境。
KinD 的優勢
KinD 的要求非常簡單:只需要一個正在執行的 Docker 守護程式即可建立叢集。這意味著它與大多數作業系統相容,包括 Linux、macOS 和 Windows。
KinD 叢集的工作原理
從高層次來看,KinD 叢集可以被視為由單一 Docker 容器組成,該容器執行控制平面節點和工作節點,以建立一個 Kubernetes 叢集。為了使佈署變得簡單和穩健,KinD 將每個 Kubernetes 物件封裝到一個單一的映像檔中,稱為節點映像檔。
節點映像檔
節點映像檔包含了建立單一節點叢集或多節點叢集所需的所有 Kubernetes 元件。
控制平面元件
當我們執行 docker exec 命令進入控制平面節點容器時,我們可以看到標準的 Kubernetes 控制平面元件正在執行:
docker exec -it <container-id> ps aux
此命令輸出的結果類別似於以下內容:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 1234 567 ? Ss Jan01 0:00 /usr/bin/kube-apiserver
root 2 0.0 0.0 1234 567 ? Ss Jan01 0:00 /usr/bin/kube-scheduler
root 3 0.0 0.0 1234 567 ? Ss Jan01 0:00 /usr/bin/kube-controller-manager
#### 內容解密:
/usr/bin/kube-apiserver:Kubernetes API 伺服器,負責處理 API 請求。/usr/bin/kube-scheduler:Kubernetes 排程器,負責將 Pod 排程到適當的節點上。/usr/bin/kube-controller-manager:Kubernetes 控制管理器,負責執行各種控制器,如 ReplicationController。
工作節點元件
同樣地,當我們執行 docker exec 命令進入工作節點容器時,我們可以看到標準的工作節點元件正在執行:
docker exec -it <container-id> ps aux
此命令輸出的結果類別似於以下內容:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 1234 567 ? Ss Jan01 0:00 /usr/bin/kubelet
root 2 0.0 0.0 1234 567 ? Ss Jan01 0:00 /usr/bin/kube-proxy
#### 內容解密:
/usr/bin/kubelet:Kubernetes 節點代理,負責管理節點上的 Pod 和容器。/usr/bin/kube-proxy:Kubernetes Proxy,負責提供網路代理服務。
圖表翻譯:KinD叢集架構圖
圖表翻譯: 此圖示呈現了 KinD叢集 的基本架構。KinD 使用 Docker Container 來模擬 Kubernetes 節點,包括控制平面節點和工作節點。控制平面節點包含 kube-apiserver、kube-scheduler 和 kube-controller-manager 等關鍵元件,而工作節點則包含 kubelet 和 kube-proxy 等重要元件。這種架構使得 KinD 可以在單一主機上執行多個 Kubernetes 節點,提供了一個方便且高效的開發和測試環境。
深入理解 KinD 叢集的內部運作與持久化儲存
KinD 叢集的基本組成
現在你已經瞭解了每個節點和 Kubernetes 元件,讓我們來看看 KinD 叢集的基本組態。要顯示完整的叢集和所有正在執行的元件,可以執行 kubectl get pods --all-namespaces 命令。這將列出叢集的所有執行元件,包括我們將在第 5 章 Kubernetes Bootcamp 中討論的基本元件。除了基本叢集元件之外,你可能會注意到在名為 local-path-storage 的名稱空間中執行了一個 Pod,名為 local-path-provisioner。
本地路徑供應器(local-path-provisioner)的重要性
這個 Pod 是 KinD 包含的附加元件之一,為叢集提供了自動供應 PersistentVolumeClaims 的功能。
kubectl get pods --all-namespaces
執行上述命令後,你將看到類別似以下的輸出,其中包含了 local-path-provisioner Pod:
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system local-path-provisioner-... 1/1 Running 0 ...
local-path-storage local-path-provisioner-... 1/1 Running 0 ...
為什麼持久化儲存很重要?
大多數生產環境中的 Kubernetes 叢集都會為開發者提供持久化儲存。通常,這些儲存會由根據區塊儲存、S3 或 NFS 的儲存系統支援。除了 NFS 之外,大多數家庭實驗室很少有資源來執行功能齊全的儲存系統。local-path-provisioner 透過為你的 KinD 叢集提供昂貴儲存解決方案的所有功能,從而消除了這一限制。
深入理解持久化儲存相關物件
在第 5 章 Kubernetes Bootcamp 中,我們將討論 Kubernetes 儲存中的幾個 API 物件,包括 CSIdrivers、CSInodes 和 StorageClass 物件。這些物件被叢集用來提供對後端儲存系統的存取。一旦安裝和組態,Pod 將使用 PersistentVolumes 和 PersistentVolumeClaims 物件來消耗儲存。
為什麼需要本地路徑供應器?
雖然 Kubernetes 對本地持久化儲存提供了原生支援,但它並沒有提供自動供應功能。CNCF 提供了一個自動供應器,但它必須作為一個單獨的 Kubernetes 元件安裝和組態。KinD 使自動供應變得簡單,因為供應器已包含在所有基本安裝中。
Rancher 的專案為 KinD 提供了以下功能:
- 當建立 PVC 請求時自動建立
PersistentVolumes - 一個名為
standard的預設StorageClass
當自動供應器看到 PersistentVolumeClaim 請求到達 API 伺服器時,將建立一個 PersistentVolume,並將 Pod 的 PVC 繫結到新建立的 PVC。
程式碼範例:使用本地路徑供應器建立持久化儲存
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: example-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
內容解密:
- 上述 YAML 檔案定義了一個名為
example-pvc的PersistentVolumeClaim,請求 1Gi 的儲存空間。 - 當這個 PVC 被建立時,
local-path-provisioner將自動建立一個對應的PersistentVolume。 - Pod 可以透過參照這個 PVC 來使用持久化儲存。
KinD 與 Docker 網路
由於 KinD 使用 Docker 作為容器引擎來執行叢集節點,因此所有叢集都受到與標準 Docker 容器相同的網路約束。在第 3 章《理解 Docker 網路》中,我們回顧了 Docker 網路和 Docker 預設網路堆積疊的潛在限制。這些限制不會限制你在本地主機上測試你的 KinD Kubernetes 叢集,但當你想從網路上的其他機器測試容器時,它們可能會導致問題。
除了 Docker 網路考慮因素之外,我們還必須考慮 Kubernetes Container Network Interface(CNI)。官方上,KinD 團隊將網路選項限制為僅兩種 CNI:Kindnet 和 Calico。Kindnet 是他們唯一支援的 CNI,但你確實有選項可以停用預設的 Kindnet 安裝,這將建立一個沒有安裝 CNI 的叢集。在叢集佈署之後,你可以佈署一個 CNI 清單,例如 Calico。
KinD 網路架構
圖表翻譯:
- 此圖表展示了 KinD 網路架構,包括 Kubernetes 叢集、Kindnet CNI、Calico CNI 和 Docker 網路之間的關係。
- KinD 叢集可以使用 Kindnet 或 Calico 作為 CNI,它們都依賴於 Docker 網路。
許多 Kubernetes 安裝(無論是小型開發叢集還是企業叢集)都使用 Tigera 的 Calico 作為 CNI,因此我們選擇在本文的練習中使用 Calico 作為我們的 CNI。
在開發叢集中使用 KinD 的挑戰與解決方案
使用 KinD 這樣的解決方案可能會讓人感到混淆,因為它涉及到容器在容器內的佈署。我們將這種情況比喻為俄羅斯套娃,一個娃娃套著另一個娃娃,以此類別推。當你開始使用 KinD 來建立自己的叢集時,你可能會失去對主機、Docker 和 Kubernetes 節點之間通訊路徑的追蹤。
瞭解 KinD 叢集的三層架構
為了避免混淆,你需要清楚地瞭解每個元件在哪裡執行,以及如何與每個元件互動。下圖展示了形成 KinD 叢集所需的三個層級。
此圖示
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title KinD 佈署 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
圖表翻譯: 此圖顯示了 KinD 叢集的三層架構,包括主機層、Docker 層和 KinD 容器層。每個層級只能與直接在其上方的層級互動。
KinD 叢集的網路流量流動
假設你想在 Kubernetes 叢集中佈署一個網頁伺服器,並使用 Chrome 瀏覽器在 Docker 主機或網路上的其他工作站進行測試。如果你直接嘗試存取主機的 80 埠,很可能會失敗。為什麼會這樣呢?
程式碼範例:暴露容器埠
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
type: NodePort
內容解密:
apiVersion和kind定義了 Kubernetes 資源的型別和版本。metadata部分包含了服務的名稱。spec部分定義了服務的規格,包括選擇器、埠和型別。selector指定了服務要關聯的 Pod。ports部分定義了服務要暴露的埠。type設定為NodePort,表示服務將在每個節點上暴露一個埠。
執行網頁伺服器的 Pod 位於第三層,無法直接接收來自主機或網路上其他機器的流量。要從主機存取網頁伺服器,你需要將流量從 Docker 層轉發到 KinD 層。
安裝 KinD 的步驟
在開始之前,請確保你已經具備了必要的先決條件,包括安裝 kubectl 和 Go。
安裝 Kubectl
如果你使用的是 Ubuntu 18.04 系統,可以透過執行以下命令來安裝 kubectl:
sudo snap install kubectl --classic
安裝 Go
要安裝 Go,你需要下載 Go 檔案,解壓縮可執行檔,並設定專案路徑。以下命令可以用來在你的機器上安裝 Go:
wget https://dl.google.com/go/go1.13.3.linux-amd64.tar.gz
tar -xzf go1.13.3.linux-amd64.tar.gz
sudo mv go /usr/local
mkdir -p $HOME/Projects/Project1
cat << 'EOF' >> ~/.bash_profile
export GOROOT=/usr/local/go
export GOPATH=$HOME/Projects/Project1
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
EOF
source ~/.bash_profile
內容解密:
- 下載 Go 到你的主機,解壓縮檔案,並將檔案移動到
/usr/local。 - 在你的主目錄中建立一個名為
Projects/Project1的 Go 專案資料夾。 - 將 Go 環境變數新增到
.bash_profile中,這些變數是執行 Go 應用程式所必需的。