Kubernetes - 到處碰壁的 K8s 架設記錄
前言
最近開始學習 K8s,想說來架設一個環境來練習,沒想到架設過程中碰到了不少問題。
官方文件寫得有點複雜,網路上的教學也是各種版本,而且有些教學是過時的無法使用。
因此決定寫下這篇文章,來記錄一下架設過程。
K8s 簡介
Kubernetes(簡稱 K8s,由來是 K 和 s 之間有 8 個字母)。
是用於自動部署、擴充和管理「容器化(containerized)應用程式」的開源系統。
在 Production 環境中,需要管理執行應用程式的容器並確保不會出現停機。
例如,如果一個容器發生故障,則需要啟動另一個容器。
而 Kubernetes 提供了一個彈性運作分散式系統的框架。負責應用程式的擴展和故障轉移,提供部署模式等等。
提供的功能
- 服務發現(Service discovery)與負載平衡
Kubernetes 可以使用 DNS 名稱或使用自己的 IP 位址公開容器。
如果容器的流量很高,Kubernetes 能夠進行負載平衡並分配網路流量,使部署穩定。 - 儲存協調
Kubernetes 可讓您自動掛載您選擇的儲存系統,例如:本機儲存、公有雲等。 - 自動佈署與回滾
您可以使用 Kubernetes 來描述已部署容器的所需狀態,並且它可以以受控的速率將實際狀態變更為所需狀態。 - 自動資源打包
Kubernetes 可以將容器安裝到您的節點上,以充分利用您的資源。 - 自我修復
Kubernetes 會重新啟動發生故障的容器、替換容器、終止不回應使用者定義的運作狀況檢查的容器。 - 機密資料與設置管理
Kubernetes 可讓您儲存和管理敏感資訊。 - 批次執行
Kubernetes 還可以管理您的批次和 CI 工作負載,並根據需要替換失敗的容器。 - 水平縮放 (Horizontal scaling)
使用簡單的指令、UI 或根據 CPU 使用情況自動增加、減少部屬的應用程式數量。 - IPv4/IPv6 雙堆疊
將 IPv4 和 IPv6 位址指派給 Pod 和服務。 - 專為可擴充性而設計
無需更改上游原始碼即可為 Kubernetes Cluster 新增功能。
架構
Control Plane
Control Plane 是 Kubernetes Cluster 的大腦。
負責制訂全域的策略(如:調度)以及 Cluster 狀態(如:工作負載)的維護。
Control Plane 由以下元件組成:
- kube-apiserver
API 伺服器是一個關鍵元件,使用 Kubernetes 來提供 Kubernetes 的內部和外部介面。 - etcd
Kubernetes 所有 Cluster 資料的備援儲存。 - kube-scheduler
負責 Cluster 的資源調度。 - kube-controller-manager
與 API 伺服器進行通訊以在需要時建立、更新和刪除他們管理的資源。
Node
Node 是 Kubernetes Cluster 的工作機器,可以是虛擬機器或物理機器。
每個 Node 包括以下元件:
- kubelet
在 Cluster 中的每個 Node 上執行,負責與 API 伺服器通訊並管理 Pod 和容器。 - kube-proxy
是 Kubernetes Service 的網路代理,負責管理 Node 的網路通訊。 - Container Runtime Interface (CRI)
Node 上運行容器的軟體,支援 Docker、Containerd、CRI-O。
環境準備
這邊安裝的是正式的 K8s,不是 Minikube 或 MicroK8s,因為這兩個是單一節點的架構,相對單純。
本文使用 VMware Workstation 來建立虛擬機器,並使用 Ubuntu Server 24.04 作為作業系統。
本文將不詳細介紹 VMware Workstation 的虛擬機器的安裝、網路設定與 Ubuntu 作業系統的安裝。
安裝的是最新的 K8s 版本 1.29.3,使用 kubeadm 安裝。
最低需求
Control Plane
- 2 CPU
- 4 GB RAM
Node
- 1 CPU
- 2 GB RAM
安裝 K8s
安裝前置作業(所有節點)
更新作業系統
1
2sudo apt update
sudo apt upgrade關閉 swap
kubelet 目前不支援 swap,因此需要關閉 swap。1
2sudo swapoff -a # 關閉 swap
sudo vim /etc/fstab # 永久關閉 swap將 swap 的那一行註解掉。
設定 hosts (可選)
為了方便管理,可以設定 hosts。1
sudo vim /etc/hosts
加入以下內容:
1
<ip> <hostname>
例如:
1
2192.168.129.21 k8s-master
192.168.129.22 k8s-node-1依需求設定網卡
網卡名稱需為
eth0
(for calico cni)
可以使用以下指令查看網卡名稱:1
ip a
若網卡名稱不是
eth0
,則需要修改網卡名稱。
這邊直接修改系統的網卡命名模式:1
sudo vim /etc/default/grub
在
GRUB_CMDLINE_LINUX
新增net.ifnames=0
。
然後更新 grub:1
sudo grub-mkconfig -o /boot/grub/grub.cfg
接著同步更新 netplan 的網卡名稱,將原本的
ens33
改為eth0
。1
sudo vim /etc/netplan/00-installer-config.yaml
之後重新啟動。1
sudo reboot
之後再次查看網卡名稱,就能發現網卡名稱已經改為
eth0
。1
ip a
轉送 IPv4 並讓 iptables 查看橋接流量
直接根據官方文件執行以下指令來新增核心模組與設定:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# sysctl params required by setup, params persist across reboots
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# Apply sysctl params without reboot
sudo sysctl --system之後透過以下指令驗證模組是否載入成功:
1
2lsmod | grep br_netfilter
lsmod | grep overlay
以及驗證以下設定的值是否都為1
:1
sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward
安裝 Container Runtime Interface (CRI)
這邊使用的 CRI 是 Containerd,透過 docker 官方的 repository 來安裝:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# Add Docker's official GPG key:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
# Install containerd
sudo apt install containerd.io1
2
3wget https://github.com/containernetworking/plugins/releases/download/v1.4.1/cni-plugins-linux-amd64-v1.4.1.tgz
sudo mkdir -p /opt/cni/bin
sudo tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.4.1.tgz建立 Containerd 的設定檔。
1
2
3
4# 備份原本的設定檔
sudo cp /etc/containerd/config.toml /etc/containerd/config.toml.backup
# 建立預設設定檔
containerd config default | sudo tee /etc/containerd/config.toml編輯
/etc/containerd/config.toml
,將runc.options
裡面的SystemdCgroup
改成true
。1
sudo vim /etc/containerd/config.toml
1
2
3
4[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
之後啟動 Containerd 並將其設定為開機啟動。1
sudo systemctl enable --now containerd
安裝 kubeadm
直接根據官方文件安裝kubelet
、kubeadm
以及kubectl
,並且鎖定版本,因為 K8s 需要特殊的升級流程。1
2
3
4
5
6
7sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl修改 calico 的預設 CIDR
因為 calico 的預設 CIDR 是192.168.0.0/16
與我們的網段衝突,因此需要修改 calico 的設定。先用 wget 下載 calico 的 YAML 下來更改。
找到192.168.0.0/16
之後,取消註解並改成172.30.0.0/16
(或其他未使用的網段)。1
2wget https://docs.projectcalico.org/manifests/calico.yaml
vim calico.yaml
安裝 Control Plane (僅 Control Plane 節點)
正式初始化 Control Plane。
1 | sudo kubeadm init --pod-network-cidr=172.30.0.0/16 --apiserver-advertise-address=192.168.129.21 |
pod-network-cidr
為 calico 的網段,用來分配給 Pod 使用。apiserver-advertise-address
為 API Server 的 IP 位址。
出現以下訊息代表完成安裝。
此時可以根據提示執行以下指令,讓你的 user 可以控制 k8s。另請記下以下指令,這是用來讓 Node 加入 Cluster 的指令(此指令會在 24 小時候到期)。1
2
3mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
安裝 Node (僅 Node 節點)
貼上剛剛在 Control Plane 上的指令(記得加上 sudo),讓 Node 加入 Cluster。
1 | sudo kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash> |
例如:
1 | sudo kubeadm join 192.168.129.21:6443 --token nvfpx7.tj0px32qh0i7a7fc --discovery-token-ca-cert-hash sha256:4c6eee8f79716a71d5f2b270b23748b4ed92d6362506048a0c74e5b0b324a781 |
之後,回到 Control Plane,檢查 Node 是否已經加入 。
1 | kubectl get nodes -o wide |
如果有出現代表成功,不過你應該發現狀態是 NotReady
了,因為我們還沒有安裝 CNI Plugin。
遇到加入時卡住怎麼辦?
有可能是因為 token 過期了,可以先在 Control Plane 上執行以下指令確認:
1 | kubeadm token list |
1 | kubeadm token create |
1 | 5didvk.d09sbcov8ph2amjw |
1 | openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \ |
1 | 4c6eee8f79716a71d5f2b270b23748b4ed92d6362506048a0c74e5b0b324a781 |
安裝 CNI Plugin (僅 Control Plane 節點)
這邊我們使用 calico 作為 CNI Plugin。
在 Control Plane 上執行以下指令:
1 | kubectl apply -f calico.yaml |
然後透過以下指令監看 calico 的狀態:
1 | watch kubectl get pods -n kube-system |
等待 calico
開頭的 Pod 皆為 Running
狀態,代表安裝完成。
安裝完成後,再次檢查 Node 的狀態:
1 | kubectl get nodes -o wide |
此時 Node 的狀態應該已經是 Ready
了。
後記
部屬過程中,碰壁的地方大多都是 CRI 與 CNI。
CRI 一開始我是直接裝 Docker,後來看到文件說 Dockershim 支援已經移除,因此改裝 Containerd。
另外不少教學是用 cgroupfs 當作 cgroup driver,那時還需要修改 kubelet 的設定,但官方建議用 systemd(預設也是 systemd),並且 Containerd 內建 systemd 的 cgroup driver,因此也嘗試改為 systemd。
然後就碰到無法初始化的問題,又看了一次文件,才發現是少了「轉送 IPv4 並讓 iptables 查看橋接流量」這個步驟。
再來是 CNI 的部分,原本要用 weave-net,但沒有成功。後來又參考 calico 官方文件而改用 calico,但 pod 卻開不起來。
最後又查了另一篇教學才發現是 calico 的預設 CIDR 網段跟現有網卡衝突,另外網卡的名稱不同也不吃。因此修改 calico 的設定和網卡名稱之後才成功。
這次的架設過程碰到了不少問題,但也學到了不少東西,在這邊筆記下來,也希望這篇文章能幫助到有需要的人。
參考資料
- kubernetes/kubernetes: Production-Grade Container Scheduling and Management (github.com)
- Overview | Kubernetes
- Kubernetes Components | Kubernetes
- Day12 Kubeadm 安裝 建立屬於自己的 K8s - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)
- containerd/docs/getting-started.md at main · containerd/containerd (github.com)
- Install Docker Engine on Ubuntu | Docker Docs
- Container Runtimes | Kubernetes
- Installing kubeadm | Kubernetes
- Creating a cluster with kubeadm | Kubernetes
- Title: Kubernetes - 到處碰壁的 K8s 架設記錄
- Author: jimchen5209
- Created at : 2024-03-27 13:18:38
- Updated at : 2024-11-27 14:50:30
- Link: https://blog.lce-lab.dev/2024/03/27/Kubernetes-到處碰壁的-K8s-架設記錄/
- License: This work is licensed under CC BY-NC-SA 4.0.