Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

20 KiB

Kubernetes cluster deployment

📌 0. 環境架構與前置條件

  • 已安裝Keepalived&HaProxy,並設置好VIP

🔹 節點規劃 (Topology)

Hostname Role IP Address OS 備註
VIP Load Balancer 10.10.0.83 HAProxy API Server 統一入口 (Port 6444)
doris-f01 Master 10.10.0.85 Ubuntu 24.04 第一台初始節點
doris-f02 Master 10.10.0.87 Ubuntu 24.04 後續加入的 Control Plane
doris-f03 Master 10.10.0.89 Ubuntu 24.04 後續加入的 Control Plane
doris-b01 Worker 10.10.0.93 Ubuntu 24.04 工作節點
doris-b02 Worker 10.10.0.94 Ubuntu 24.04 工作節點
doris-b03 Worker 10.10.0.95 Ubuntu 24.04 工作節點
doris-b04 Worker 10.10.0.96 Ubuntu 24.04 工作節點

📌 1. 基礎設定(所有節點)

🔹 設定 Hostname

若已設定就跳過

hostnamectl set-hostname <hostname>

🔹 關閉 swap

  1. Swap 當記憶體不足時,會將記憶體數據寫入速度極慢的硬碟
  2. K8s 依賴精確的 RAM (物理記憶體) 數據來排程 Pod
  3. Linux 核心會先使用 Swap 而不是觸發 Kubelet 的驅逐
sudo swapoff -a
sudo sed -i '/swap/d' /etc/fstab
  1. overlay:這是容器運行時用來創建疊加文件系統的模組(Overlay Filesystem)
  2. br_netfilter:橋接網路過濾的基礎。它允許 Linux 核心的 iptables(防火牆規則)能夠正確處理橋接網路流量。

🔹 載入核心模組

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

🔹 sysctl 設定

  1. net.ipv4.ip_forward=1:啟用 IPv4 轉發
  2. net.bridge.bridge-nf-call-iptables=1:啟用橋接流量的 iptables 處理
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables=1
net.ipv4.ip_forward=1
EOF

sudo sysctl --system

📌 2. 安裝 containerd(所有節點)

  1. Containerd 是一個標準化的、核心的Container Runtime
  2. 負責管理容器生命週期、並讓容器「跑起來」的軟體

🔹 安裝 containerd

sudo apt update
sudo apt install -y containerd

🔹 建立預設設定:

sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml

🔹 啟用 SystemdCgroup:

  1. Cgroup : Linux用來限制及分配資源的工具
  2. Kubelet 預設使用 systemd 作為 Cgroup driver。
  3. 需確保 Containerd 也使用 systemd,否則會導致不穩定。
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

🔹 載入設定&設定開機啟動:

sudo systemctl restart containerd
sudo systemctl enable containerd

📌 3. 安裝 Kubernetes(所有主機)

🔹 新增 repository

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo apt-key add -
echo 'deb https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update

🔹 安裝 kubeadm / kubectl / kubelet

  1. Kubeadm:官方提供的 集群快速啟動工具 (只在建置時用)。
    1. 證書管理 (PKI Certificates):Kubernetes 的組件之間通訊都需要加密(HTTPS)。Kubeadm 會自動生成並分發 CA 根證書、API Server 證書、Kubelet 證書等。這在以前手動做是非常痛苦且容易出錯的。
    2. 生成核心組件配置 (Manifests):它會自動產生 API Server, Controller Manager, Scheduler 和 Etcd 的 YAML 檔案,並以 Static Pod 的形式在 Master 節點上運行。
    3. 節點加入 (Bootstrap Tokens):它提供了一套簡單的 Token 機制,讓 Worker 節點只需要執行一行指令就能加入集群,並自動完成 TLS 認證。
    4. kubeadm 主要負責最後這兩個關鍵步驟:
      1. kubeadm init (只在 Master / Control Plane 執行)
        • 檢查系統環境(Pre-flight check)。
        • 生成證書 (CA, API server certs...)。
        • 生成 kubeconfig 文件 (/etc/kubernetes/admin.conf)。
        • 啟動 Control Plane 組件 (Etcd, API Server...)。
        • 產出: 最後會吐出一行 kubeadm join ... 的指令給您。
      2. kubeadm join (在所有 Worker Node 執行)
        • Worker 節點拿著 Token 向 Master 報到。
        • Master 驗證後,發給 Worker 專屬的證書。
        • Worker 節點正式納入管理,準備接客(跑 Pod)。
    5. Kubeadm 不做的事:
      1. 不負責安裝環境依賴:它不會裝 Docker/Containerd、也不會關 Swap等等。
      2. 不負責安裝 CNI 網絡插件:kubeadm init 跑完後,集群雖然起來了,但在安裝 CNI (如 Calico, Flannel) 之前,CoreDNS 都不會運作,節點狀態會是 NotReady。
  2. Kubectl:給管理員用的「指令工具」,用來對集群下達命令
    1. 發號施令:輸入指令(如 kubectl get pods, kubectl apply -f ...)。
    2. 翻譯官:它會把輸入的指令,轉換成標準的 REST API 請求,發送給 Kubernetes 的大腦 (API Server)。
  3. Kublet:運行在所有節點上的「代理人」,負責指揮 Containerd 啟動容器,並向 Master 匯報狀態
    1. 接單:它會一直監聽 Master (API Server) 發來的指令。
    2. 執行:收到指令後,命令自己節點上的Containerd去下載鏡像、啟動容器。
    3. 匯報:它會定期向 Master 匯報:「我還活著,容器也都健康」。
sudo apt-get install -y kubelet kubeadm kubectl

🔹鎖定版本:

  1. apt-mark hold : 防止在執行 apt-get upgrade 更新系統時,不小心自動升級了 K8s 元件。
  2. K8s 的升級通常需要特定的流程(先升級 Master 再升級 Node),自動升級會導致集群崩潰。
sudo apt-mark hold kubelet kubeadm kubectl

🔹設定開機啟動:

sudo systemctl enable kubelet

📌 4. 初始化 Control Plane(第一台master)

初始化整個cluster的第一台master

🔹建立設定檔

sudo vi /kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
# ==================== 1. 集群基本資訊 ====================
kubernetesVersion: v1.30.14               # 請確保與安裝的 kubeadm 版本一致
controlPlaneEndpoint: "10.10.0.83:6444"   # VIP:HAProxy端口 (所有節點透過此溝通)

# ==================== 2. 網路設定 ====================
networking:
  podSubnet: "10.244.0.0/16"              # Pod 網段 (Flannel 預設)
  serviceSubnet: "10.96.0.0/12"           # Service 網段 (ClusterIP) default值
  dnsDomain: cluster.local                # default值

# ==================== 3. API Server 設定 ====================
apiServer:
  certSANs:                               # 憑證需包含的所有 IP/域名
    - "10.10.0.83"                        # VIP (最重要!)
    - "10.10.0.85"                        # F01 IP
    - "10.10.0.87"                        # F02 IP
    - "10.10.0.89"                        # F03 IP
    - "127.0.0.1"
  extraArgs:
    authorization-mode: "Node,RBAC"       # default值

---
# ==================== 4. 本機初始化設定 ====================
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: "10.10.0.85"          # **當前節點 (F01) 的 IP**
  bindPort: 6443                          # API Server 本機監聽 Port (default值)
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock # default值 建議保留
  name: doris-f01                         # 當前節點 Hostname 前面步驟已設定 保險起見這裡可以再設定一次
  taints:                                 # Master 污點 (不讓應用跑在 Master) default值
    - effect: NoSchedule
      key: node-role.kubernetes.io/control-plane

---
# ==================== 5. Kubelet 全域設定 ====================
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd                     # 關鍵!確保與 Containerd 一致 (default值 建議保留)
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration

# ==================== 基本信息 ====================
kubernetesVersion: v1.30.14              # K8s 版本,建議與 kubeadm 版本一致

# ==================== 控制平面 HA 配置 ====================
controlPlaneEndpoint: "10.10.0.83:6444" # VIP:HAProxy端口
                                         # 所有節點將通過這個地址訪問 API Server
                                         # 這是 HA 的關鍵配置

# ==================== 網路配置 ====================
networking:
  podSubnet: "10.244.0.0/16"            # Pod 網段,給 CNI 使用
                                         # Calico/Flannel 會從這個範圍分配 Pod IP
                                         # 不要與現有網路衝突!
  
  serviceSubnet: "10.96.0.0/12"         # Service 網段 (ClusterIP)
                                         # K8s 內部服務的虛擬 IP 範圍
                                         # 預設值,一般不需要改

# ==================== API Server 配置 ====================
apiServer:
  certSANs:                              # 證書 Subject Alternative Names
    - "10.10.0.83"                       # VIP - 必須加入!
    - "10.10.0.85"                       # F01 IP
    - "10.10.0.87"                       # F02 IP
    - "10.10.0.89"                       # F03 IP
    # - "k8s-api.yourdomain.com"         # 如果有 DNS 也可以加
  
  extraArgs:                             # API Server 額外參數
    bind-address: "0.0.0.0"              # 監聽所有 IP (預設是 0.0.0.0)
    advertise-address: "10.10.0.85"      # **重要**: 此節點對外宣告的 IP
                                          # F01 用 .85, F02 用 .87, F03 用 .89
    secure-port: "6443"                   # API Server 實際監聽端口
                                          # 避免與 HAProxy 的 6443 衝突

# ==================== etcd 配置 ====================
#etcd:
#  external:                              # 使用外部 etcd cluster
#    endpoints:                           # etcd 節點列表
#      - https://10.10.0.93:2379          # B01
#      - https://10.10.0.94:2379          # B02
#      - https://10.10.0.95:2379          # B03
#    
#    # etcd TLS 證書 - 需要預先準備
#    caFile: /etc/kubernetes/pki/etcd/ca.crt         # etcd CA 證書
#    certFile: /etc/kubernetes/pki/etcd/client.crt   # etcd 客戶端證書
#    keyFile: /etc/kubernetes/pki/etcd/client.key    # etcd 客戶端私鑰

---
# ==================== 初始化配置 (僅第一個 master 需要) ====================
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration

localAPIEndpoint:
  advertiseAddress: "10.10.0.85"         # **此節點的 IP** (F01)
  bindPort: 6443                          # API Server 監聽端口

nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock  # 容器運行時
  name: doris-f01                        # 節點名稱
  taints:                                # 污點,防止 Pod 調度到 master
    - effect: NoSchedule
      key: node-role.kubernetes.io/control-plane

---
# ==================== Join 配置 (其他 master 加入時使用) ====================
apiVersion: kubeadm.k8s.io/v1beta3
kind: JoinConfiguration

discovery:
  bootstrapToken:
    apiServerEndpoint: "10.10.0.83:6444"  # VIP 地址
    token: <token>                         # 從 kubeadm init 輸出獲取
    caCertHashes:
      - "sha256:<hash>"                    # CA 證書 hash
    
controlPlane:                             # 標記為 control plane 節點
  localAPIEndpoint:
    advertiseAddress: "10.10.0.87"        # **F02 的 IP** (F03 用 .89)
    bindPort: 6443
  certificateKey: <key>                    # 證書加密 key (kubeadm init 輸出)

nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
  name: doris-f02                         # 節點名稱
  taints:
    - effect: NoSchedule
      key: node-role.kubernetes.io/control-plane
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration

# K8s 版本 (確保與 kubeadm 版本一致)
kubernetesVersion: v1.30.14

# 控制平面 HA 端點 (HAProxy VIP)
controlPlaneEndpoint: "10.10.0.83:6444"

# 網路配置
networking:
  podSubnet: "10.244.0.0/16"      # Pod 網段 (Calico 使用)
  serviceSubnet: "10.96.0.0/12"   # Service 網段

# API Server 配置
apiServer:
  # 證書 SAN 列表 (所有可能訪問 API Server 的地址)
  certSANs:
    - "10.10.0.83"                # VIP (必須!)
    - "10.10.0.85"                # F01
    - "10.10.0.87"                # F02
    - "10.10.0.89"                # F03
    - "127.0.0.1"                 # localhost
    - "kubernetes"
    - "kubernetes.default"
    - "kubernetes.default.svc"
    - "kubernetes.default.svc.cluster.local"
  
  extraArgs:
    # API Server 監聽在所有網路介面
    bind-address: "0.0.0.0"
    # 此節點對外宣告的 IP (F01)
    advertise-address: "10.10.0.85"
    # API Server 實際監聽端口 (避免與 HAProxy 6443 衝突)
    secure-port: "6443"
    # 審計日誌 (可選,用於安全審計)
    audit-log-path: /var/log/kubernetes/audit.log
    audit-log-maxage: "30"
    audit-log-maxbackup: "10"
    audit-log-maxsize: "100"

# 使用外部 etcd cluster (B01-B03)
#etcd:
#  external:
#    endpoints:
#      - https://10.10.0.93:2379   # B01
#      - https://10.10.0.94:2379   # B02
#      - https://10.10.0.95:2379   # B03
#    # etcd TLS 證書路徑
#    caFile: /etc/kubernetes/pki/etcd/ca.crt
#    certFile: /etc/kubernetes/pki/etcd/client.crt
#    keyFile: /etc/kubernetes/pki/etcd/client.key

# Controller Manager 配置
controllerManager:
  extraArgs:
    bind-address: "0.0.0.0"
    # Node 心跳超時時間
    node-monitor-grace-period: "40s"
    # Pod 驅逐超時時間
    pod-eviction-timeout: "5m0s"

# Scheduler 配置
scheduler:
  extraArgs:
    bind-address: "0.0.0.0"

# DNS 配置
dns:
  imageRepository: registry.k8s.io/coredns
  imageTag: v1.10.1

# 鏡像倉庫 (如果使用國內鏡像)
# imageRepository: registry.aliyuncs.com/google_containers

---
# 初始化配置 (僅第一個 master 需要)
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration

# 本地 API Server 端點配置
localAPIEndpoint:
  advertiseAddress: "10.10.0.85"  # F01 的 IP
  bindPort: 6443                  # 監聽端口

# 節點註冊配置
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
  name: doris-f01                  # 節點名稱
  # Master 節點污點 (防止普通 Pod 調度)
  taints:
    - effect: NoSchedule
      key: node-role.kubernetes.io/control-plane
  # 節點標籤
  kubeletExtraArgs:
    node-labels: "node-role.kubernetes.io/control-plane="

# Bootstrap Token 配置 (用於節點加入)
bootstrapTokens:
  - groups:
      - system:bootstrappers:kubeadm:default-node-token
    ttl: 24h0m0s
    usages:
      - signing
      - authentication

---
# Kubelet 配置
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration

# 容器運行時
cgroupDriver: systemd

# 資源預留
systemReserved:
  cpu: "500m"
  memory: "1Gi"
  ephemeral-storage: "1Gi"

kubeReserved:
  cpu: "500m"
  memory: "1Gi"
  ephemeral-storage: "1Gi"

# 驅逐閾值
evictionHard:
  memory.available: "200Mi"
  nodefs.available: "10%"
  imagefs.available: "15%"

# 日誌配置
logging:
  format: json

# 序列化 image pulls (適合網路較慢的環境)
serializeImagePulls: false
maxParallelImagePulls: 3

🔹kubeadm執行初始化

# 建議先預拉映像檔,避免初始化超時
sudo kubeadm config images pull --config kubeadm-config.yaml

# 正式初始化 
# --upload-certs:將憑證加密上傳,讓後續加入的 Master 節點能自動下載使用
sudo kubeadm init --config kubeadm-config.yaml --upload-certs

命令成功後會得到:

add master node 指令:

sudo kubeadm join 10.10.0.83:6444 --token <token> \
    --discovery-token-ca-cert-hash sha256:<hash> \
    --control-plane --certificate-key <key> \
    --apiserver-advertise-address=<F02或F03的IP> \
    --apiserver-bind-port=6443

add worker node:

sudo kubeadm join 10.10.0.83:6444 --token <token> \
    --discovery-token-ca-cert-hash sha256:<hash>

🔹 設定 kubeconfig:

目的: 將集群的管理員憑證 (admin.conf) 複製到使用者的預設目錄,讓 kubectl 能夠讀取並取得控制權限

  1. 建立目錄kubectl 預設會去 ~/.kube/ 找設定檔
  2. 複製憑證:將 kubeadm 產生的最高權限設定檔 (admin.conf) 複製過來
  3. 變更權限:將檔案擁有者改為目前使用者,避免每次執行 kubectl 都要打 sudo
  4. etc/kubernetes/admin.conf:集群最高權限身分證 (Master Key), 由kubaadmi init自動生成,裡面包含:
    1. Cluster: API Server 的網址 (例如 https://10.10.0.83:6444) 和 CA 根憑證。
    2. User: 一個名為 kubernetes-admin 的使用者,以及它的 客戶端憑證 (Client Certificate) 和 私鑰 (Key)。這個憑證擁有 system:masters 群組權限(K8s 裡的上帝視角)。
    3. Context: 把上面的 Cluster 和 User 綁定在一起。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

📌 5. 安裝 Pod 網路(Flannel)

Kubernetes 本身不提供 Pod 之間的網路通訊功能,它只定義了介面 (CNI)。我們必須安裝網路插件來實現以下功能:

  1. 指派 IP:根據我們在初始化時設定的 podSubnet (10.244.0.0/16),為每一個 Pod 分配唯一的 IP 地址。
  2. 建立覆蓋網路 (Overlay Network):在現有的實體網路之上,建立一層虛擬網路,讓不同節點上的 Pod 覺得彼此在同一個區域網路內。
  3. 激活節點:CoreDNS 與節點狀態依賴於網路插件。未安裝前,執行 kubectl get nodes 會看到狀態為 NotReady
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

檢查: 執行 kubectl get nodes,doris-f01 的狀態應該會從 NotReady 變成 Ready。

補充知識

  • 同一台節點內: 其實不用 Flannel,Docker/Containerd 本身就能讓同一台節點上的容器互通(透過本機的 Bridge)。

  • 跨節點: 這是困難點。當 Node A 的 Pod (IP 10.244.1.2) 想找 Node B 的 Pod (IP 10.244.2.3) 時,連線節點的路由器(無論是實體路由或 VM 的 vSwitch) 看不懂這些 10.244 的 Pod IP,它只認得 10.10 的節點 IP。

  • Flannel 的工作: 它負責把這些封包「包裝」起來(封裝),偽裝成節點對節點的流量,透過節點網路傳送到對面,再由對面的 Flannel「拆開」,交給目標 Pod。


📌 6. 加入 Master 節點

在要加入 master 的機器執行 kubeadm 給的 kubeadm join:

sudo kubeadm join 10.10.0.83:6444 --token <token> \
    --discovery-token-ca-cert-hash sha256:<hash> \
    --control-plane --certificate-key <key> \
    --apiserver-advertise-address=<F02或F03的IP> \
    --apiserver-bind-port=6443

設定 Kubeconfig (讓 kubectl 可用) 加入成功後,必須配置憑證才能使用 kubectl 指令

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config # kubeadm join 會自動在 /etc/kubernetes/ 產生這份檔案
sudo chown $(id -u):$(id -g) ~/.kube/config

📌 7. 加入 Worker 節點

在每台 worker 機器執行 kubeadm 給的 kubeadm join:

sudo kubeadm join 10.10.0.83:6444 --token <TOKEN>   --discovery-token-ca-cert-hash sha256:<HASH>

到master node上檢查節點:

kubectl get nodes -o wide