← 返回上一頁
Kubernetes

使用 kubeadm 在本地環境部署 Kubernetes v1.28.3 叢集完整教學

本頁目錄
Kubernetes 元件概覽 - Master Node 與 Worker Node 架構
Kubernetes 叢集架構圖 - Control Plane 與 Worker Node
Kubernetes 叢集架構概覽(圖片來源:K21Academy)

最近花了一些時間在本地環境用 kubeadm 把 Kubernetes v1.28.3 叢集架起來,整個過程雖然不算太複雜,但細節蠻多的,稍有疏忽就可能卡在某個環節。這篇文章把我實際操作的完整流程記錄下來,希望對想要自己動手搭建 K8s 叢集的朋友有所幫助。

環境概述

這次部署採用的是 CentOS 衍生發行版,像是 Anolis OS 8.8、Rocky Linux 9.3、AlmaLinux 9.3 都適用。我自己用的是 Anolis OS 8.8,核心版本為 Linux Kernel 5.10.134-13.an8.x86_64

以下是這次部署涉及的主要元件與版本:

元件名稱版本
containerd(容器運行時)v1.7.8
runcv1.1.9
crictlv1.27.0
kubeadm / kubectl / kubeletv1.28.3
kube-apiserver / kube-scheduler / kube-controller-managerv1.28.3
etcdv3.5.9
flannel(CNI 網路元件)v0.23.0
kubernetes-dashboardv2.7.0

節點規劃

節點角色主機名IP 位址Pod 網段Service 網段
Master(Control Plane)c1192.168.31.3110.15.0.0/1610.16.0.0/16
Worker Nodec2192.168.31.3210.15.0.0/1610.16.0.0/16
Worker Nodec3192.168.31.3310.15.0.0/1610.16.0.0/16

系統初始化設定

在正式安裝 K8s 元件之前,需要先做好系統層面的基礎配置。這部分每個節點都要執行。

設定主機名解析

# 在所有節點上配置 hosts
cat >> /etc/hosts << EOF
192.168.31.31 c1
192.168.31.32 c2
192.168.31.33 c3
EOF

核心模組與參數調整

Kubernetes 需要載入 overlaybr_netfilter 這兩個核心模組,同時也需要開啟一些網路轉發相關的核心參數:

# 設定開機自動載入核心模組
cat << EOF > /etc/modules-load.d/99-k8s.conf
overlay
br_netfilter
EOF

# 調整核心參數
cat << EOF > /etc/sysctl.d/99-k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
user.max_user_namespaces=28633
EOF

sysctl -p /etc/sysctl.d/99-k8s.conf

停用 SELinux 與 Swap

setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=Disabled/' /etc/selinux/config
sed -i '/swap/ s/^/# /' /etc/fstab

防火牆設定

這邊有兩種做法。正式環境建議只開放必要的連接埠;測試環境為了方便可以直接關閉防火牆。

方式一:精確開放連接埠(適用於正式環境)

# Master 節點
firewall-cmd --permanent --add-port={6443,2379,2380,10250,10251,10252,10257,10259,179}/tcp
firewall-cmd --permanent --add-port=4789/udp
firewall-cmd --reload

# Worker 節點
firewall-cmd --permanent --add-port={179,10250,30000-32767}/tcp
firewall-cmd --permanent --add-port=4789/udp
firewall-cmd --reload

方式二:關閉防火牆(適用於測試環境)

systemctl stop firewalld && systemctl disable firewalld

設定完成後,記得重啟所有節點讓配置生效。

安裝容器運行時 Containerd

Kubernetes 從 v1.24 開始已經移除了對 Docker 的直接支援,所以我們這邊採用 containerd 作為容器運行時。

下載並安裝

wget https://github.com/containerd/containerd/releases/download/v1.7.8/cri-containerd-cni-1.7.8-linux-amd64.tar.gz
tar -zxvf cri-containerd-cni-1.7.8-linux-amd64.tar.gz -C /

自訂 Containerd 配置

mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml

接著需要修改 /etc/containerd/config.toml 中的幾個關鍵配置:

# 將 cgroup driver 改為 systemd(使用 cgroup v2 時此項必須為 true)
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  SystemdCgroup = true

# 替換 sandbox image 為國內鏡像源
[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"

修改完成後啟動 containerd:

systemctl enable --now containerd.service
Kubernetes 官方 Logo
Kubernetes — 容器編排的業界標準

安裝 kubeadm、kubectl、kubelet

透過 dnf 套件管理器來安裝 Kubernetes 核心元件:

# 新增 Kubernetes yum 倉庫
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF

# 安裝元件
dnf install kubelet kubeadm kubectl --disableexcludes=kubernetes -y
dnf install iproute-tc ipvsadm -y

# 啟用 kubelet
systemctl enable --now kubelet

使用 kubeadm 初始化叢集

這是整個部署流程中最關鍵的一步。我習慣用 YAML 配置檔來自訂 kubeadm 的初始化參數,這樣比較好管理也方便日後回溯。

準備 kubeadm 配置檔

建立 kubeadm.yml,內容涵蓋了 API Server 監聽位址、叢集網段、cgroup driver 以及 KubeProxy 模式等重要配置:

apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
bootstrapTokens:
- groups:
   - system:bootstrappers:kubeadm:default-node-token
   token: ********
   ttl: 24h0m0s
   usages:
   - signing
   - authentication
localAPIEndpoint:
   advertiseAddress: 192.168.31.31
   bindPort: 6443
nodeRegistration:
   criSocket: unix:///var/run/containerd/containerd.sock
   imagePullPolicy: IfNotPresent
   name: c1
   taints:
   - effect: PreferNoSchedule
     key: node-role.kubernetes.io/master
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
clusterName: kubernetes
kubernetesVersion: v1.28.3
imageRepository: registry.aliyuncs.com/google_containers
apiServer:
   timeoutForControlPlane: 4m0s
certificatesDir: /etc/kubernetes/pki
networking:
   dnsDomain: cluster.local
   podSubnet: 10.15.0.0/16
   serviceSubnet: 10.16.0.0/16
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
clusterDNS:
- 10.16.0.10
clusterDomain: cluster.local
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs

特別注意:networking.podSubnet 設定的 Pod 網段,務必與後續部署的 CNI 網路元件(如 Flannel)配置一致,否則 Pod 之間無法正常通訊。

執行初始化

kubeadm init --config=kubeadm.yml

初始化成功後,設定 kubectl 的存取權限:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

將 Worker 節點加入叢集

kubeadm join 192.168.31.31:6443 \
  --token ******** \
  --discovery-token-ca-cert-hash sha256:********

重置叢集(如需重來)

kubeadm reset
rm /etc/cni/net.d/* -rf
rm $HOME/.kube/config -rf
ipvsadm --clear
iptables -F -t filter
iptables -F -t nat
iptables -F -t mangle
iptables -F -t raw

部署 Flannel 網路元件

叢集初始化完成後,Pod 之間還沒辦法互相通訊,需要安裝一個 CNI 網路元件。我這邊選用 Flannel:

wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
kubectl apply -f kube-flannel.yml

# 備份 containerd 預設網路配置
cd /etc/cni/net.d/ && mv 10-containerd-net.conflist 10-containerd-net.conflist.bak

Flannel 配置說明

Flannel 部署後會自動產生網路配置,格式如下:

# /etc/cni/net.d/10-flannel.conflist
{
  "name": "cbr0",
  "cniVersion": "0.3.1",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}

如果需要自訂 Flannel 的後端模式,可以在 kube-flannel.yml 中修改 net-conf.json 區段:

net-conf.json: |
   {
     "Network": "10.15.0.0/16",
     "Backend": {
       "Type": "vxlan",
       "Directrouting": true
     }
   }

這裡 Directrouting: true 的意思是:當叢集節點在同一個子網路時,跨節點 Pod 通訊會走直接路由(類似 host-gw 模式),省去 VXLAN 封裝的開銷;如果不在同一子網路則自動回退到 VXLAN 封裝。

安裝 Kubernetes Dashboard

Dashboard 提供了一個圖形化介面來管理叢集,對於日常監控和除錯蠻方便的。

wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

下載後需要修改 Service 類型為 NodePort,這樣才能從外部存取:

spec:
   type: NodePort
   ports:
     - port: 443
       targetPort: 8443
       nodePort: 30443
kubectl apply -f recommended.yaml

建立管理員帳號

Dashboard 預設的 token 權限有限,建議另外建立一個具備 cluster-admin 權限的 ServiceAccount:

cat > kubernetes-dashboard-admin.yml << EOF
apiVersion: v1
kind: ServiceAccount
metadata:
   name: admin-user
   namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
   name: admin-user
roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: ClusterRole
   name: cluster-admin
subjects:
- kind: ServiceAccount
   name: admin-user
   namespace: kubernetes-dashboard
EOF

kubectl apply -f kubernetes-dashboard-admin.yml

# 取得管理員 token
kubectl -n kubernetes-dashboard create token admin-user

完成後,透過瀏覽器存取 https://<任意節點IP>:30443/ 即可進入 Dashboard。

驗證叢集狀態

所有元件部署完成後,來確認一下叢集是否正常運作。

節點狀態

節點狀態角色版本內部 IP作業系統容器運行時
c1Readycontrol-planev1.28.3192.168.31.31Anolis OS 8.8containerd://1.7.8
c2Readyworkerv1.28.3192.168.31.32Anolis OS 8.8containerd://1.7.8
c3Readyworkerv1.28.3192.168.31.33Anolis OS 8.8containerd://1.7.8

系統 Pod 運行狀態

命名空間Pod 名稱狀態所在節點
kube-flannelkube-flannel-ds-*Runningc1, c2, c3
kube-systemcoredns-*Runningc2
kube-systemetcd-c1Runningc1
kube-systemkube-apiserver-c1Runningc1
kube-systemkube-controller-manager-c1Runningc1
kube-systemkube-proxy-*Runningc1, c2, c3
kube-systemkube-scheduler-c1Runningc1
kubernetes-dashboarddashboard-metrics-scraper-*Runningc3
kubernetes-dashboardkubernetes-dashboard-*Runningc3

三個節點都是 Ready 狀態,所有系統 Pod 都正常運行,叢集搭建完成!

快速測試

簡單跑個容器驗證一下:

kubectl create deployment --image rockylinux:9.2 --replicas 2 rockylinux -- tail -f /dev/null

小結

用 kubeadm 搭建 K8s v1.28.3 叢集的完整流程大致就是這樣。幾個容易踩坑的地方提醒一下:

  • containerd 的 SystemdCgroup 一定要設為 true,尤其是使用 cgroup v2 的系統
  • Pod 網段要與 CNI 元件的配置保持一致
  • 如果存取不了外部鏡像倉庫,記得把 sandbox_image 換成國內鏡像源
  • KubeProxy 建議用 IPVS 模式,效能比 iptables 模式好很多

有任何問題歡迎在下方留言討論,下次我再來分享更多 Kubernetes 實戰經驗。

分享這篇
X LinkedIn Facebook Hacker News Reddit

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料