在 Kubernetes 環境中,確保 Ingress 控制器的穩定性至關重要。本文將探討如何使用 HAProxy 作為自定義負載平衡器,提升 NGINX Ingress 的高用性。實際操作中,我們會發現單節點 Ingress 控制器存在風險,而 HAProxy 可以監控後端 Ingress Pod 的健康狀態,並自動調整流量路由,避免單點故障。透過模擬 kubelet 服務中斷,我們可以驗證 HAProxy 如何自動切換流量到健康的 Ingress Pod,確保服務不間斷。此方法適用於任何需要高用性的 Ingress 控制器佈署場景,有效提升服務的穩定性和可靠性。

為Ingress新增自定義負載平衡器

在前面的章節中,我們已經瞭解瞭如何使用KinD佈署Kubernetes叢集。在這個章節中,我們將探討如何為Ingress新增自定義的負載平衡器。

瞭解當前叢集組態

首先,我們來看看當前叢集的組態。與之前的兩節點叢集不同,這個叢集的worker節點沒有暴露在任何主機埠上。這是因為我們已經有了一個新的HAProxy伺服器在執行。如果我們檢視建立的HAProxy容器,會發現它暴露在主機的80和443埠上。這意味著任何到達主機80或443埠的請求都會被導向自定義的HAProxy容器。

預設NGINX佈署的問題

預設的NGINX佈署只有一個副本,這意味著Ingress控制器執行在單一節點上。如果我們檢視HAProxy容器的日誌,會看到一些有趣的資訊:

[NOTICE] 093/191701 (1) : New worker #1 (6) forked
[WARNING] 093/191701 (6) : Server ingress_https/worker is DOWN, reason: Layer4 connection problem, info: "SSL handshake failure (Connection refused)", check duration: 0ms. 2 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
[WARNING] 093/191702 (6) : Server ingress_https/worker3 is DOWN, reason: Layer4 connection problem, info: "SSL handshake failure (Connection refused)", check duration: 0ms. 1 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.

內容解密:

  • 這段日誌顯示了HAProxy容器的執行狀態和後端伺服器的健康檢查結果。
  • [NOTICE]表示新的worker程式被fork出來。
  • [WARNING]表示後端伺服器ingress_https/workeringress_https/worker3不可用,原因是SSL握手失敗或連線被拒絕。
  • check duration: 0ms表示健康檢查的耗時。
  • 2 active and 0 backup servers left表示目前有2個活動伺服器和0個備份伺服器。

分析HAProxy日誌

從日誌中可以看到,HAProxy正在檢查後端伺服器的狀態。由於NGINX只執行在一個pod中,而我們的HAProxy後端組態包含了所有三個節點,因此HAProxy會檢查每個節點上的埠。任何未能回應的節點都不會被用來負載平衡流量。

模擬Kubelet故障

為了證明HAProxy為NGINX提供了高用性,我們可以模擬一個節點故障。由於KinD節點是短暫的,簡單地停止容器可能會導致它在重啟時失敗。因此,我們可以透過停止某個節點上的kubelet服務來模擬故障。

docker exec cluster01-worker2 systemctl stop kubelet

執行此命令後,如果等待幾分鐘讓叢集接收更新的節點狀態,可以透過檢視節點列表來驗證節點是否已關閉:

kubectl get nodes

模擬Kubelet故障流程

圖表翻譯: 此圖示展示了模擬Kubelet故障的流程。首先停止worker2上的kubelet服務,然後等待叢集更新節點狀態。接著,使用kubectl get nodes檢查節點狀態。如果worker2處於NotReady狀態,則刪除nginx-ingress-controller pod,促使HAProxy更新後端列表。

驗證高用性

刪除nginx-ingress-controller pod以強制重新排程:

kubectl get pods -n ingress-nginx
nginx-ingress-controller-7d6bf88c86-r7ztq
kubectl delete pod nginx-ingress-controller-7d6bf88c86-r7ztq -n ingress-nginx

這將強制排程器在另一個worker節點上啟動容器。同時,HAProxy容器會更新後端列表,因為NGINX控制器已經移動到另一個worker節點。

再次檢視HAProxy日誌,可以看到HAProxy已經更新了後端列表,包括cluster01-worker3,並且移除了cluster01-worker2

[WARNING] 093/194006 (6) : Server ingress_https/worker3 is UP, reason: Layer7 check passed, code: 200, info: "OK", check duration: 4ms. 2 active and 0 backup servers online. 0 sessions requeued, 0 total in queue.

內容解密:

  • 這段日誌顯示了後端伺服器ingress_https/worker3已經可用,原因是Layer7檢查透過,傳回碼200。
  • check duration: 4ms表示健康檢查的耗時。
  • 2 active and 0 backup servers online表示目前有2個活動伺服器和0個備份伺服器線上。

Kubernetes 與 KinD 叢集佈署實戰

在上一章中,我們探討了 KinD(Kubernetes-in-Docker)的基礎知識及其優勢。現在,我們將深入瞭解如何利用 KinD 佈署一個高可用性的 Kubernetes 叢集,並介紹 Kubernetes 的基本物件。

使用 KinD 佈署 Kubernetes

當您計劃使用 KinD 佈署一個高可用性的 Kubernetes 叢集時,您需要考慮多個工作節點的佈署以及如何將流量導向這些節點。在本文中,我們將介紹如何使用 HAProxy 作為負載平衡器來實作這一目標。

設定 HAProxy 負載平衡器

docker run -d --name HAProxy-workers-lb \
  -p 80:80 \
  -p 443:443 \
  haproxy:latest

組態 HAProxy

在設定 HAProxy 時,您需要建立一個組態檔案,定義如何將流量導向後端的工作節點。

frontend http
    bind *:80
    default_backend workers-http

backend workers-http
    mode http
    balance roundrobin
    server worker1 <worker1_ip>:80 check
    server worker2 <worker2_ip>:80 check

內容解密:

  1. 負載平衡器的作用:HAProxy 在此扮演負載平衡器的角色,將進入的 HTTP 請求分配到後端的工作節點。
  2. 設定檔解析:在 frontend 部分,我們定義了 HAProxy 監聽的埠;在 backend 部分,我們定義了後端伺服器的組態,包括伺服器的 IP 地址和健康檢查機制。
  3. 動態負載平衡:透過 balance roundrobin,HAProxy 將請求輪流分配到不同的後端伺服器,實作負載平衡。

刪除 KinD 叢集與 HAProxy 容器

當您完成測試後,可能需要刪除 KinD 叢集和相關的 HAProxy 容器。刪除 KinD 叢集的命令如下:

kind delete cluster --name=<cluster_name>

刪除 HAProxy 容器的命令如下:

docker rm HAProxy-workers-lb --force

內容解密:

  1. 刪除叢集:使用 kind delete cluster 命令可以刪除指定的 KinD 叢集。
  2. 刪除容器:使用 docker rm 命令可以強制刪除指定的 Docker 容器。

Kubernetes 基本物件總覽

在本章中,我們將介紹 Kubernetes 的基本物件,包括 Pod、Service、Deployment、ReplicaSet、StatefulSet 和 DaemonSet 等。這些物件是構建和管理 Kubernetes 應用程式的基礎。

Kubernetes 元件概述

Kubernetes 叢集由多個元件構成,包括控制平面和工作節點。控制平面負責管理叢集的狀態,而工作節點則執行實際的應用程式。

此圖示顯示了 Kubernetes 叢集的架構:

graph LR
    A[控制平面] -->|管理| B[工作節點]
    B -->|執行| C[Pod]
    C -->|包含| D[容器]

圖表翻譯: 此圖示展示了 Kubernetes 的基本架構,包括控制平面如何管理工作節點,以及工作節點上執行的 Pod 和容器。這種架構使得 Kubernetes 可以高效地管理和排程容器化應用。

常見問題

  1. 在建立 PersistentVolumeClaim 之前,必須建立哪個物件?

    • A. PVC
    • B. Disk
    • C. PersistentVolume
    • D. VirtualDisk

    答案:C. PersistentVolume

  2. KinD 包含一個動態磁碟供應器,它是由哪家公司建立的?

    • A. Microsoft
    • B. CNCF
    • C. VMware
    • D. Rancher

    答案:B. CNCF

  3. 如果您建立了一個具有多個工作節點的 KinD 叢集,您會安裝什麼來將流量導向每個節點?

    • A. Load balancer
    • B. Proxy server
    • C. Nothing
    • D. Network load balancer

    答案:A. Load balancer

  4. True or false:一個 Kubernetes 叢集只能安裝一個 CSIdriver。

    • A. True
    • B. False

    答案:B. False

Kubernetes 控制平面的重要組成元件

Kubernetes 的控制平面是叢集的核心,負責管理叢集的所有方面。如果控制平面故障,叢集將無法正常運作。控制平面主要由多個元件組成,包括 kube-apiserver、Etcd、kube-scheduler、kube-controller-manager 和 cloud-controller-manager。

Kubernetes API 伺服器(kube-apiserver)

kube-apiserver 是 Kubernetes 叢集的入口,所有請求都透過 API 伺服器進行處理。kubectl 指令實際上是透過呼叫 API 端點來與 kube-apiserver 進行互動。例如,當執行 kubectl get nodes 指令時,實際上是向 kube-apiserver 發送了一個 API 請求,取得叢集中的節點列表。

https://10.240.100.100:6443/api/v1/nodes?limit=500

內容解密:

  • 此 API 請求是透過 HTTPS 協定傳送到 kube-apiserver。
  • 請求的端點是 /api/v1/nodes,用於取得節點列表。
  • limit=500 引數限制了傳回的結果數量。

Etcd 資料函式庫

Etcd 是 Kubernetes 用於儲存所有叢集資料的分散式鍵值資料函式庫。叢集中的每個資源都有一個對應的鍵儲存在 Etcd 中。可以使用 etcdctl 命令列工具查詢 Etcd 中的資料。

EtcdCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
--cert=/etc/kubernetes/pki/etcd/server.crt \
get / --prefix --keys-only

內容解密:

  • EtcdCTL_API=3 指定使用的 Etcd API 版本。
  • --endpoints 指定 Etcd 服務的端點。
  • --cacert--key--cert 用於驗證和加密連線。
  • get / --prefix --keys-only 用於取得所有鍵。

kube-scheduler

kube-scheduler 負責排程新的 Pod 到適當的節點上。當建立一個新的 Pod 時,kube-scheduler 會根據多個條件(如主機資源和叢集策略)決定將 Pod 排程到哪個節點上。

kube-controller-manager

kube-controller-manager 是一個包含多個控制器的二進位制檔案,這些控制器執行在一個單一的程式中。它包括 node、replication、endpoints 和 service account/token 控制器。每個控制器都有其特定的功能,用於維護叢集的期望狀態。

cloud-controller-manager

cloud-controller-manager 與 kube-controller-manager 類別似,但它專門用於與雲端服務提供商互動。它包含 node、route、service 和 volume 控制器,用於管理與雲端服務提供商相關的資源。

工作節點元件

工作節點負責執行工作負載。當 kube-scheduler 排程一個新的 Pod 時,它會根據從工作節點收集的資訊來決定將 Pod 排程到哪個節點上。工作節點元件包括:

主要元件

  • kubelet:負責在節點上執行和管理 Pod。
  • kube-proxy:負責提供網路代理和負載平衡功能。

這些元件共同工作,確保 Kubernetes 叢集能夠高效、可靠地執行。瞭解這些元件的功能和工作原理對於管理和維護 Kubernetes 叢集至關重要。

圖表翻譯: 此圖表展示了 Kubernetes 控制平面和工作節點的主要元件。控制平面包括 kube-apiserver、Etcd、kube-scheduler、kube-controller-manager 和 cloud-controller-manager。工作節點包括 kubelet 和 kube-proxy。這些元件共同構成了 Kubernetes 叢集的核心架構。

與 Kubernetes API 伺服器互動

Kubernetes 的工作節點(worker node)通常被稱為 kubelet。kubelet 是一個代理程式,執行在所有工作節點上,負責執行實際的容器。

Kubernetes 元件簡介

  • kubelet:執行在所有工作節點上的代理程式,負責執行容器。
  • kube-proxy:負責在 Pod 和外部網路之間進行網路通訊路由。儘管名稱中有 “proxy”,但它並不是一個代理伺服器。
  • 容器執行環境(Container Runtime):每個節點都需要一個容器執行環境來執行容器。雖然 Docker 是最常見的容器執行環境,但並不是唯一選擇。CRI-O 和 containerd 是 Docker 的兩種主要替代方案。

使用 kubectl 與 Kubernetes 互動

kubectl 是一個單一的可執行檔,允許使用者透過命令列介面(CLI)與 Kubernetes API 互動。kubectl 支援大多數主要作業系統和架構,包括 Linux、Windows 和 Mac。

安裝 kubectl

  1. 下載最新版本的 kubectl:

curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl

2.  使檔案可執行:
    ```bash
chmod +x ./kubectl
  1. 將可執行檔移到系統路徑中:

sudo mv ./kubectl /usr/local/bin/kubectl


#### 版本控制

Kubernetes 每 3 個月更新一次,包括基礎叢集元件和 kubectl 工具。使用者可能會遇到叢集和 kubectl 版本不符的情況。執行 `kubectl version` 命令可以檢查客戶端和伺服器的版本。

```plaintext
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.1", GitCommit:"d224476cd0730baca2b6e357d144171ed74192d6", GitTreeState:"clean", BuildDate:"2020-01-14T21:04:32Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.0", GitCommit:"70132b0f130acc0bed193d9ba59dd186f0e634cf", GitTreeState:"clean", BuildDate:"2020-01-14T00:09:19Z", GoVersion:"go1.13.4", Compiler:"gc", Platform:"linux/amd64"}

詳細輸出選項

使用 -v--v 選項可以獲得更多關於 API 請求和回應的資訊。詳細輸出級別從 0 到 9,數字越大,輸出越詳細。

kubectl 命令型別

kubectl 命令可以分為**指令式(imperative)宣告式(declarative)**兩種。

  • 指令式命令:告訴 Kubernetes 要做什麼,例如 kubectl run nginx --image nginx
  • 宣告式命令:告訴 Kubernetes 你想要什麼,通常透過 YAML 清單檔案來宣告。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Ingress自定義負載平衡器實戰

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 使用者如何透過 kubectl 或 YAML 清單檔案與 Kubernetes API 互動,最終影響 Kubernetes 叢集的狀態。

內容解密:

這段程式碼展示了使用 curl 下載最新版本的 kubectl,並使其可執行,最後將其移到系統路徑中的過程。透過這種方式,使用者可以在 Linux 系統上安裝 kubectl 工具,以便與 Kubernetes 叢集進行互動。

在實際操作中,使用者需要確保系統具有必要的許可權和網路連線,以便成功下載和安裝 kubectl。此外,使用者還需要注意版本控制,以確保 kubectl 和 Kubernetes 叢集的版本相容。