Skip to content

上一篇用 Terraform 建好了 Master 和 Worker 兩個容器,這篇繼續進入 Master 節點,把 K3s 裝起來。這裡先手動跑一次,確認流程沒問題,後面會改用 Ansible 自動化執行。


連線進入 Master 容器

連線方式二擇一:

bash
# 方式一:SSH 連線
ssh root@192.168.<>.14

# 方式二:從 PVE 實體機直接穿透
pct enter 204

1. 更新套件庫並安裝 curl

bash
apt update && apt install curl -y

遇到 DNS 解析失敗?

如果 apt update 出現類似以下錯誤:

Temporary failure resolving 'deb.debian.org'
Temporary failure resolving 'security.debian.org'

代表容器無法連上網路,依序排查:

Step 1:確認網路是否通

bash
ping -c 3 8.8.8.8

若 ping 不通,回到 Terraform 確認 ip_config 的 gateway 是否設正確:

hcl
ip_config {
  ipv4 {
    address = "192.168.10.14/24"
    gateway = "192.168.10.1"   # 確認這是你的路由器 IP
  }
}

Step 2:確認 DNS 是否設定

若 ping 得到但 DNS 解析失敗,確認 dns 區塊有加上去:

hcl
dns {
  servers = ["8.8.8.8", "1.1.1.1"]
}

修改後重新 terraform apply,再回容器內重試即可。


2. 安裝自動安全性更新套件

這個套件預設只會自動安裝「安全性更新」,既能補上漏洞,又不會因為升級核心軟體而把 K3s 叢集弄壞。

bash
apt install unattended-upgrades -y
dpkg-reconfigure -plow unattended-upgrades

3. 安裝 K3s Master

執行官方安裝指令:

bash
curl -sfL https://get.k3s.io | sh -s - server --cluster-init

--cluster-init 讓這個節點以叢集模式啟動,後續可以加入更多 Master 或 Worker。

跑完後稍等 10~20 秒讓服務完全啟動,再確認狀態:

bash
systemctl status k3s
kubectl get nodes

看到節點狀態為 Ready 就代表成功了。


疑難排解

LXC 容器和一般 VM 不同,它是「共用宿主機核心」的輕量虛擬化,預設會拔掉一些 K8s 啟動所需的系統權限,所以安裝後很容易踩到以下幾個坑。

kubectl: command not found

bash: kubectl: command not found

這是環境變數(PATH)沒有包含 K3s 的安裝路徑,先用絕對路徑測試:

bash
/usr/local/bin/kubectl get nodes

如果有輸出,把路徑永久加入環境變數:

bash
echo 'export PATH=$PATH:/usr/local/bin' >> ~/.bashrc
source ~/.bashrc

API Server 無法啟動(ServiceUnavailable)

Error from server (ServiceUnavailable): the server is currently unable to handle the request

通常代表 K3s 的 API Server 啟動後一直 crash 重啟。先看 log:

bash
journalctl -u k3s -n 50 --no-pager

常見原因是 LXC 隱藏了 /dev/kmsg(系統核心日誌裝置),而 K8s 的 Kubelet 啟動時一定要讀它來監控 OOM 狀況,找不到就直接罷工。

解法是建一個捷徑,把 /dev/console 假裝成 /dev/kmsg 騙過 Kubelet:

bash
echo 'L /dev/kmsg - - - - /dev/console' > /etc/tmpfiles.d/kmsg.conf
systemd-tmpfiles --create /etc/tmpfiles.d/kmsg.conf
systemctl restart k3s

modprobe br_netfilter / overlay 失敗

Process: ExecStartPre=/sbin/modprobe br_netfilter (code=exited, status=1/FAILURE)
Process: ExecStartPre=/sbin/modprobe overlay (code=exited, status=1/FAILURE)

K3s 需要兩個核心模組:

  • br_netfilter:K8s 內部網路路由
  • overlay:容器檔案系統掛載

LXC 容器沒有權限自己載入核心模組,要回到 Proxmox 實體主機手動載入:

bash
modprobe overlay
modprobe br_netfilter

順手把設定寫進去,避免重開機後又卡住:

bash
echo -e "overlay\nbr_netfilter" | tee -a /etc/modules-load.d/k3s.conf

載入完成後回到容器重啟 K3s:

bash
systemctl restart k3s

/proc/sys 無寫入權限(kubelet crash)

open /proc/sys/vm/overcommit_memory: permission denied
open /proc/sys/kernel/panic: permission denied
open /proc/sys/kernel/panic_on_oops: permission denied
Error: failed to run Kubelet: failed to start ContainerManager

unprivileged LXC 容器沒有權限寫入 kernel 參數,kubelet 啟動時嘗試調整這些值並 crash。

方案一:啟用 KubeletInUserNamespace(推薦)

建立 k3s 設定檔,讓 kubelet 跳過這些操作:

bash
mkdir -p /etc/rancher/k3s
cat > /etc/rancher/k3s/config.yaml << 'EOF'
kubelet-arg:
  - "feature-gates=KubeletInUserNamespace=true"
EOF
systemctl restart k3s

方案二:放寬 LXC 容器權限

Proxmox 實體主機上編輯該容器的設定檔(假設容器 ID 為 204):

bash
nano /etc/pve/lxc/204.conf

在檔案最底部加入:

lxc.apparmor.profile: unconfined
lxc.cgroup2.devices.allow: a
lxc.cap.drop:
lxc.mount.auto: proc:rw sys:rw

Proxmox 8.x 請用 lxc.cgroup2,舊版用 lxc.cgroup

存檔後完全關機再重開容器(Shutdown → Start),權限設定才會生效。重啟後確認 kmsg 捷徑也生效:

bash
systemd-tmpfiles --create /etc/tmpfiles.d/kmsg.conf
systemctl restart k3s

今日小結

今天完成了容器建立與 K3s 安裝的基本流程:Terraform 成功在 PVE 上建出 Master 和 Worker 兩個容器,K3s 服務也順利啟動。

NAME         STATUS   ROLES                  AGE   VERSION
k3s-master   Ready    control-plane,etcd     70s   v1.35.4+k3s1