博客園出海記-組裝集裝箱:搭建 Kubernetes 集群

在開篇中我們宣布了博客園出海計劃的啟航,出海航船選擇了阿里云。
第一件準備工作是在航船上組裝集裝箱 —— 搭建 Kubernetes 集群。
出海根據地選在了阿里云新加坡機房,Kubernetes 集群用阿里云 ECS 自己搭建,沒有使用阿里云容器服務 ACK。
首先購買一臺 ECS 用于部署 Control Plane 節點,Control Plane 是指揮協調控制中心,不干具體活,所以不需要很高的配置,選擇了2核4G的經濟型 ECS 實例(ecs.e-c1m2.large),操作系統選用了 Ubuntu 24.04,加入新建的 kube 安全組(集群中的節點服務器都會加入這個安全組),主機名是 kube-cp-01。
準備工作
安裝 k8s 三駕馬車
安裝 kubelet + kubeadm + kubectl,使用的版本是 1.33.4
安裝所需的軟件包
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gnupg
添加 k8e 安裝源的簽名秘鑰
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
添加 k8e 安裝源
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
chmod 644 /etc/apt/sources.list.d/kubernetes.list
apt-get 命令安裝三駕馬車
apt-get update
apt-get install -y kubelet kubectl kubeadm
確認版本
~# kubelet --version
Kubernetes v1.33.4
~# kubectl version
Client Version: v1.33.4
~# kubeadm version -o short
v1.33.4
配置網絡
開啟 IPv4 包轉發
echo "net.ipv4.ip_forward = 1" | tee /etc/sysctl.d/k8s.conf
sysctl --system
安裝容器運行時 containerd
采用手動安裝方式,安裝的 containerd 版本是 2.1.4
下載并解壓至 /usr/local
wget -c https://github.com/containerd/containerd/releases/download/v2.1.4/containerd-2.1.4-linux-amd64.tar.gz
tar Cxzvf /usr/local containerd-2.1.4-linux-amd64.tar.gz
通過 systemd 自動運行 containerd
mkdir -p /usr/local/lib/systemd/system
wget -c https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -O /usr/local/lib/systemd/system/containerd.service
systemctl daemon-reload
systemctl enable --now containerd
安裝 runc
wget -c https://github.com/opencontainers/runc/releases/download/v1.3.1/runc.amd64
install -m 755 runc.amd64 /usr/local/sbin/runc
安裝 CNI 插件
wget -c https://github.com/containernetworking/plugins/releases/download/v1.8.0/cni-plugins-linux-amd64-v1.8.0.tgz
mkdir -p /opt/cni/bin
tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.8.0.tgz
生成 containerd 配置
mkdir /etc/containerd
containerd config default > /etc/containerd/config.toml
在 /etc/containerd/config.toml 中啟用 SystemdCgroup
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc]
...
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
SystemdCgroup = true
重啟 containerd 使配置生效
systemctl restart containerd
安裝 containerd 命令行工具 nerdctl
wget -c https://github.com/containerd/nerdctl/releases/download/v2.1.4/nerdctl-2.1.4-linux-amd64.tar.gz
tar -zxf nerdctl-2.1.4-linux-amd64.tar.gz
mv nerdctl /usr/bin/nerdctl
將 nerdctl 的默認命名空間設置為 k8s.io
mkdir /etc/nerdctl
echo 'namespace = "k8s.io"' | tee /etc/nerdctl/nerdctl.toml
創建高可用集群
在 /etc/hosts 中添加 control-plane-endpoint 的主機名解析
127.0.0.1 kube-api
用 kubeadm 命令創建集群
kubeadm init \
--control-plane-endpoint "kube-api:6443" \
--upload-certs \
--pod-network-cidr=10.0.0.0/8 \
--skip-phases=addon/kube-proxy
注:沒有安裝 kube-proxy 是因為會用 cilium 取代它
出現下面的輸出說明集群創建成功了
Your Kubernetes control-plane has initialized successfully!
...
注:上面的輸出內容中包含加入 control-plane 與 worker 節點的命令,后面會用到
用 nerdctl ps 命令查看容器運行情況
root@kube-cp-01 ~ # nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
f54d0fc6215a registry.k8s.io/kube-proxy:v1.33.4 "/usr/local/bin/kube…" About a minute ago Up
73cbd7ab3d69 registry.k8s.io/kube-scheduler:v1.33.4 "kube-scheduler --au…" About a minute ago Up
5ff05420d284 registry.k8s.io/kube-controller-manager:v1.33.4 "kube-controller-man…" About a minute ago Up
7031f91cfc16 registry.k8s.io/kube-apiserver:v1.33.4 "kube-apiserver --ad…" About a minute ago Up
2c79907098d4 registry.k8s.io/etcd:3.5.21-0 "etcd --advertise-cl…" About a minute ago Up
975b724b2814 registry.k8s.io/pause:3.10 "/pause" About a minute ago Up
添加 kubectl 用到的配置文件
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
查看節點運行情況
root@kube-cp-01 ~ # kubectl get nodes
NAME STATUS ROLES AGE VERSION
kube-cp-01 Ready control-plane 2m41s v1.33.4
注:這里 control-plane node 處于 Ready 狀態,如果用了 kube-proxy,要等完成安裝 CNI 網絡插件才會處于 Ready 狀態
查看 pod 運行情況
root@kube-cp-01 ~ # kubectl get pods -n kube-system 1 ?
NAME READY STATUS RESTARTS AGE
coredns-674b8bbfcf-994fx 0/1 Pending 0 2m40s
coredns-674b8bbfcf-bsgdd 0/1 Pending 0 2m40s
etcd-kube-cp-01 1/1 Running 0 2m46s
kube-apiserver-kube-cp-01 1/1 Running 0 2m45s
kube-controller-manager-kube-cp-01 1/1 Running 0 2m44s
kube-proxy-vlvt9 1/1 Running 0 2m40s
kube-scheduler-kube-cp-01 1/1 Running 0 2m44s
coredns 處于 Pending 狀態是因為還沒安裝 CNI 網絡插件
安裝 CNI 網絡插件
選用 cilium 作為 CNI(容器網絡接口) 插件
安裝 cilium cli
wget -c https://github.com/cilium/cilium-cli/releases/download/v0.18.7/cilium-linux-amd64.tar.gz
tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
安裝 cilium
root@kube-cp-01 ~ # cilium install --version 1.18.1 \
--namespace kube-system \
--set bpf.masquerade=true \
--set kubeProxyReplacement=true
?? Using Cilium version 1.18.1
?? Auto-detected cluster name: kubernetes
?? Auto-detected kube-proxy has not been installed
?? Cilium will fully replace all functionalities of kube-proxy
檢查 cillium 的運行情況
root@kube-cp-01 ~ # cilium status --wait
/ˉˉ\
/ˉˉ\__/ˉˉ\ Cilium: OK
\__/ˉˉ\__/ Operator: OK
/ˉˉ\__/ˉˉ\ Envoy DaemonSet: OK
\__/ˉˉ\__/ Hubble Relay: disabled
\__/ ClusterMesh: disabled
DaemonSet cilium Desired: 1, Ready: 1/1, Available: 1/1
DaemonSet cilium-envoy Desired: 1, Ready: 1/1, Available: 1/1
Deployment cilium-operator Desired: 1, Ready: 1/1, Available: 1/1
Containers: cilium Running: 1
cilium-envoy Running: 1
cilium-operator Running: 1
clustermesh-apiserver
hubble-relay
Cluster Pods: 2/2 managed by Cilium
Helm chart version: 1.18.1
確認 cilium 已取代 kube-proxy
root@kube-cp-01 ~ # kubectl -n kube-system exec ds/cilium -- cilium-dbg status | grep KubeProxyReplacement
KubeProxyReplacement: True [eth0 172.21.49.56 fe80::216:3eff:fe0d:c8fe (Direct Routing)]
確認已啟用 eBPF Host-Routing
root@kube-cp-01 ~ # kubectl -n kube-system exec ds/cilium -- cilium-dbg status | grep BPF
Routing: Network: Tunnel [vxlan] Host: BPF
Masquerading: BPF [eth0] 10.0.0.0/24 [IPv4: Enabled, IPv6: Disabled]
Cillium 成功部署后,coredns pod 也隨之正常運行
root@kube-cp-01 ~ # kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-674b8bbfcf-994fx 1/1 Running 0 8m46s
coredns-674b8bbfcf-bsgdd 1/1 Running 0 8m46s
添加更多 Control Plane 節點
一共部署 3 個 control plane 節點,準備 2 臺與 kube-cp-01 同樣配置的2核4G阿里云 ecs,加入 kube 安全組,主機名分別為 kube-cp-02 與 kube-cp-03,用 kube-cp-01 的鏡像創建系統。
分別登錄這2臺服務器,修改主機名,重置已有的 k8s 配置
hostnamectl set-hostname kube-cp-02
kubeadm reset
在 /etc/hosts 中添加 kube-api 的解析,解析到 kube-cp-01 的 IP 地址
172.21.49.56 kube-api
通過下面 kubeadm join 命令將服務器加入集群成為 control plane 節點
kubeadm join kube-api:6443 --token xxxxxx \
--discovery-token-ca-cert-hash sha256:yyyyyy \
--control-plane --certificate-key zzzzzz \
-v=6
注:如果忘記之前 kubeadm init 創建集群時生成的 join 命令所需的 token + hash + key,可以通過下面的命令在 kube-cp-01 上生成
kubeadm init phase upload-certs --upload-certs
kubeadm token create --print-join-command
在 /etc/hosts 中將 kube-api 解析到 127.0.0.1
127.0.0.1 kube-api
這時通過 kubectl 命令就可以看到3個 control plane 節點
root@kube-cp-03 ~ # kubectl get nodes
NAME STATUS ROLES AGE VERSION
kube-cp-01 Ready control-plane 2d6h v1.33.4
kube-cp-02 Ready control-plane 48m v1.33.4
kube-cp-03 Ready control-plane 6m18s v1.33.4
指揮協調控制中心三人組就這樣組建好了。
接下來添加真正干活的 worker 節點,添加之前要部署負載均衡,worker 節點通過負載均衡訪問 control plane 的 api server,按照 control plane 的指令與目標干活。
部署負載均衡
選用了阿里云網絡型負載均衡(NLB),創建一個名為 kube-api 的私網 NLB

創建 NLB 服務器組,將 3 臺 control-plane 節點服務器加入服務器組

創建監聽,監聽協議是 TCP,端口是 6443,關聯服務器組選擇前一步創建的服務器組。

k8s 集群的 control-plane-endpoint 主機名是 kube-api,NLB 的 endpoint 主機名是下面這個很長的三級域名,需要部署內網 dns 服務器進行 CNAME 解析
nlb-uaohnyerknl7eraukw2.ap-southeast-1.nlb.aliyuncsslbintl.com
選用了阿里云「云解析 PrivateZone」,在控制臺添加一個域名,然后添加一個 CNAME 解析記錄,將 kube-api 解析到阿里云負載均衡綁定的主機名

登錄到 kube-cp-01 服務器測試一下解析
ping kube-api
PING nlb-uaohnyerknl7eraukw2.ap-southeast-1.com (172.21.49.53) 56(84) bytes of data.
64 bytes from 172.21.49.53: icmp_seq=1 ttl=102 time=0.378 ms
解析成功,負載均衡部署完成。
添加 Worker 節點
準備一臺4核8G的阿里云 ecs 作為 worker 節點,加入 kube 安全組,主機名設置為 kube-worker-01,也是用之前的鏡像創建系統。
登錄 kube-worker-01 服務器,刪除 /etc/hosts 中的 kube-api 解析,之前部署的內網 dns 服務器會自動進行解析。
用 kubeadm reset 命令重置 k8s 配置,通過 kubeadm join 命令將這臺服務器作為 worker 節點加入集群
kubeadm join kube-api:6443 --token xxxxxx \
--discovery-token-ca-cert-hash sha256:yyyyyy
出現下面的輸出,說明成功加入
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
登錄到其中一臺 control-plane 查看集群中的節點情況
root@kube-cp-01 ~ # kubectl get nodes
NAME STATUS ROLES AGE VERSION
kube-cp-01 Ready control-plane 2d12h v1.33.4
kube-cp-02 Ready control-plane 6h45m v1.33.4
kube-cp-03 Ready control-plane 87m v1.33.4
kube-worker-01 Ready <none> 54m v1.33.4
3 個 control-plane 節點,1 個 worker 節點都運行正常,k8s 集群部署完成,集裝箱準備就緒,下一步就是往集裝箱中裝包裹(部署 pod),會在后續的博文中分享。
搭建中遇到的問題
開始安裝的是最新版 kubernetes 1.34,在部署最新版 cilium 1.18.1 時發現 cilium 不兼容 k8s 1.34,只能換成 k8s 1.33.4。
本來想參考這篇博文試試 cilium 的高科技,用 k8s service 取代阿里云負載均衡作為 control plane 的負載均衡,但實驗失敗,等以后找時間再研究。
結語
讓大家久等了,出海記第2篇博文姍姍來太遲,因為這段時間太忙了,有時搭建到中途,竟然連續幾天抽不出時間繼續搭建。
接下來會更忙,這段時間和華為達成了 HarmonyOS 的推廣和專區建設合作,接下來要重點忙于 HarmonyOS 專區的搭建與運營,出海記的分享會更受影響,會考慮螞蟻搬家式地一點一點分享,比如部署 redis 分享一篇,部署 dapr 分享一篇,直到找到負責 HarmonyOS 合作項目的運營人才加入團隊,出海的步伐才能加快。
另外,園子辦公室隔壁的「云棲開發者基地」裝修好了,以后杭州的園友可以有固定的地方線下交流了,園子的出海也可以在線下探討交流了。
浙公網安備 33010602011771號