chundev
日期:2026-04-10 技術棧:Kubernetes 1.29 / kubeadm / Calico / Harbor / Ansible
拿到一套企業 ML 平台的離線安裝包(Ansible-based, ~17GB),目標是理解其架構後自行建置 single-node K8s 環境。透過解壓分析 playbook 和 role,完整還原了安裝流程、元件依賴、以及 K8s 1.29 下的架構差異(例如 seldon-core 在 1.29 不再安裝)。本文記錄分析方法和所有 K8s 元件的實務解釋。
某 ML 協作管理平台提供離線安裝包,使用 Ansible 自動化部署到多台 Ubuntu/RHEL 主機。安裝包包含 K8s 叢集建置、容器映像倉庫、GPU 虛擬化、監控棧等完整基礎設施。原廠提供的安裝指南是 PDF,目標是理解底層架構後,自行建立 single-node All-In-One 環境。
17GB 的 tgz 不適合直接解壓(磁碟空間有限),先用 tar -tzf 列出目錄:
# 列出所有條目
tar -tzf installer.tgz | wc -l
# → 398 個條目
# 只看目錄結構
tar -tzf installer.tgz | grep -E '/$' | sort
tar -xzf installer.tgz \
--include='*.yml' --include='*.yaml' \
--include='*.sh' --include='*.cfg' \
--include='*.org' --include='*.j2' \
--include='*.conf'
# → 181 個文字檔,足以分析完整架構
Ansible Playbook 的命名和執行順序就是安裝流程的藍圖:
cluster-01 環境檢查
cluster-02 跳板機 kernel 升級
cluster-03 所有主機 kernel 升級
cluster-04 檔案派送(infra 安裝包)
cluster-05 profile 設定
cluster-10 Harbor 安裝
cluster-11 K8s Master 安裝
cluster-12 AI-Stack Web 安裝
cluster-13 GPU Driver 安裝
cluster-14 Worker 安裝
cluster-15 Worker 加入叢集
cluster-20 K8s 附加元件(ingress、監控、儲存)
cluster-21 GPU Label + Skyport Key
cluster-22 ixgpu 安裝
cluster-90 CVE Patch
installer.tgz (17GB)
├── AI-Stack-Infra-*.tar.xz ← K8s 基礎設施(kubeadm, kubelet, containerd, Calico 等)
├── aistack-web-*.tar.gz ← ML 平台 Web 應用(專有)
├── ix-gpu-setup-*.tar.gz ← GPU 虛擬化(專有)
└── aistack-installer/ ← Ansible 自動化
├── hosts ← 角色配置
├── ansible.cfg
├── files/
│ ├── conf-jitignore.yml ← 核心變數(版本、網路、路徑)
│ └── config.yml ← 使用者可調設定
├── playbooks/ ← 22 個 Playbook
└── roles/ ← 48 個 Role
# conf-jitignore.yml — 整個安裝系統的設定中樞
aistack_ver: "4.27.2"
k8s: "1.29" # 支援 1.22 / 1.29 / 1.32
nv_driver: "570" # NVIDIA driver 版本
AISP: "~/ai-stack-install" # 安裝工作目錄
# 每台機器的網路資訊
netinfo:
- { dist: Ubuntu, ver: "24.04", name: hostname, ip: x.x.x.x, gw: x.x.x.x }
# seldon-core-install/tasks/main.yml
- ansible.builtin.import_role:
name: infinser-inpans
vars:
package_name: "seldon-core-install"
when: k8s == "1.22" # ← 只有 1.22 才裝!
K8s 1.29 改為只 push 一個 courier-executor image 到 Harbor,不再部署完整的 seldon-core。
幾乎所有安裝步驟都透過一個叫 infinser-inpans 的 role,它只是個 wrapper:
# infinser-inpans/tasks/main.yml
- become: true
ansible.builtin.script:
cmd: ../files/infinities-installer-exec-steps-v2.sh "input=" ""
args:
chdir: ""
creates: /tmp/.done # 冪等:做過就跳過
實際的安裝腳本 infinities-installer.sh 在 infra 安裝包內,而非 Ansible role 裡。
# sc-master-node-as-also-worker/tasks/main.yml
- set_fact: mastertaint="asworker"
when: groups['workers'] | length == 0 # workers 群組為空 → AIO 模式
- shell: |
kubectl taint node "$(hostname)" \
node-role.kubernetes.io/control-plane- --overwrite
when: mastertaint == "asworker"
| 類型 | 用途 | 複雜度 |
|---|---|---|
| NFS | 檔案共享、分佈式訓練 | 低 |
| MinIO | 物件儲存(S3 相容) | 中 |
| BigTera | 企業儲存 | 高 |
| NetApp Trident | 企業儲存 | 高 |
以下是這套 ML 平台用到的所有 K8s 元件,特別標注與 k3s 的差異。
kubeadm 是 Kubernetes 官方的叢集建置工具。與 k3s 的「一個 binary 搞定一切」不同,kubeadm 需要你分開安裝 kubelet、kubectl、containerd,然後用 kubeadm init 初始化 Control Plane。
# k3s 的做法(一行搞定)
curl -sfL https://get.k3s.io | sh -
# kubeadm 的做法(多步驟)
apt install kubelet kubeadm kubectl containerd
kubeadm init --pod-network-cidr=192.168.0.0/16
好處是完全可控、相容所有標準 K8s 工具鏈、企業支援。代價是複雜度高。
CNI(Container Network Interface)負責 Pod 之間的網路通訊。k3s 預設用 Flannel(簡單的 VXLAN overlay),這套平台用 Calico。
| Flannel (k3s 預設) | Calico | |
|---|---|---|
| 協定 | VXLAN overlay | BGP 路由 |
| 效能 | 一般 | 較佳(少一層封裝) |
| NetworkPolicy | 不支援 | 完整支援 |
| 適用場景 | 開發、小規模 | 生產、多租戶 |
ML 平台需要 Calico 是因為多租戶隔離:不同專案的 Pod 不應該互相存取。
# kubeadm init 時指定 Calico 的 Pod CIDR
kubeadm init --pod-network-cidr=192.168.0.0/16
# 然後部署 Calico
kubectl apply -f calico.yaml
Taint 是節點上的「禁止標籤」。Master 節點預設有 NoSchedule taint,意思是:「除非你的 Pod 明確聲明能容忍(Tolerate)我,否則不要排程到我這裡。」
# 查看 taint
kubectl describe node master | grep Taints
# → Taints: node-role.kubernetes.io/control-plane:NoSchedule
# All-In-One 模式:移除 taint,讓業務 Pod 也能跑在 master 上
kubectl taint node master node-role.kubernetes.io/control-plane:NoSchedule-
# ^ 注意這個減號
k3s 預設就是沒有 taint 的(server 節點可以跑 workload),所以你可能沒注意過這件事。
K8s 1.24 起棄用 Docker 作為容器執行時(Container Runtime),改用 containerd。但「棄用 Docker」不代表 Docker image 不能用——只是 kubelet 不再透過 dockershim 跟 Docker daemon 溝通。
K8s 1.22 (舊): kubelet → dockershim → Docker → containerd → runc
K8s 1.29 (新): kubelet → containerd → runc (少了兩層)
注意:這套平台仍然安裝 Docker CE,因為:
docker load / docker push 操作映像所以 K8s 用 containerd,但主機上同時有 Docker CLI 可用。
Harbor 是 VMware(現 Broadcom)開源的容器映像倉庫。它不只是存映像的地方,還提供:
這套平台的 Harbor 跑在 port 18080,所有 container image 都先 push 到 harbor:18080/infinitiessoft-tools/,K8s 再從 Harbor 拉取。
# 典型流程
docker load -i kepler-release-0.7.2.tar.gz
docker tag quay.io/sustainable_computing_io/kepler:release-0.7.2 \
harbor:18080/infinitiessoft-tools/kepler:release-0.7.2
docker push harbor:18080/infinitiessoft-tools/kepler:release-0.7.2
Helm 之於 Kubernetes,就像 apt 之於 Ubuntu。它用 Chart(模板包)定義一組 K8s 資源,支援參數化和版本控制。
# 安裝 kepler(Helm chart)
helm install kepler -n kepler --create-namespace kepler-0.5.5.tar.gz -f kepler-values.yaml
k3s 有內建的 Helm Controller(放 manifest 到特定目錄就自動部署),kubeadm 環境要手動裝 Helm CLI。
Ingress Controller 負責將外部 HTTP(S) 流量路由到叢集內的 Service。k3s 預設用 Traefik,這套平台用 ingress-nginx(NGINX 官方版本)。
| Traefik (k3s) | ingress-nginx | |
|---|---|---|
| 設定方式 | Annotation + CRD | Annotation |
| 自動 HTTPS | 內建 Let’s Encrypt | 需搭配 cert-manager |
| 效能 | 好 | 極好(NGINX 底層) |
| 社群生態 | 較小 | 最大 |
Prometheus 用 pull 模式定期抓取各元件的 metrics endpoint,儲存為時序資料。這套平台的 Prometheus 整合了:
Kepler(Kubernetes-based Efficient Power Level Exporter)透過 eBPF 監控每個容器的電力消耗。對 GPU 密集的 ML 工作負載,這代表你能知道「跑一次訓練花了多少電」。
cadvisor(Container Advisor)是 Google 開發的,蒐集每個容器的 CPU、記憶體、網路、磁碟 I/O。它是 Prometheus 的資料來源之一。
metrics-server 提供 kubectl top 和 HPA(Horizontal Pod Autoscaler)所需的即時 CPU/Memory 數據。k3s 預裝,kubeadm 要自己裝。
CSI 是 K8s 的標準儲存外掛介面。CSI-S3 讓 Pod 可以把 S3/MinIO 物件儲存當成本機目錄掛載(底層用 GeeseFS/s3fs)。
# 安裝後,Pod 可以這樣掛載 S3
volumes:
- name: training-data
persistentVolumeClaim:
claimName: s3-pvc
最簡單的共享儲存方案。ML 平台用 NFS 做分佈式訓練的共享工作目錄。注意需要 no_root_squash 參數(允許容器內的 root 操作 NFS 檔案)。
Kubernetes 原生的 GPU 分配是整卡分配(一個 Pod 拿一整張 GPU)。ixgpu 是這套平台的專有 GPU 虛擬化層,可以把一張 GPU 拆成多個 vGPU,讓多個容器共享。
原生 K8s: 1 Pod = 1 GPU(浪費)
ixgpu: 1 GPU = N 個 vGPU(共享,提高利用率)
安裝方式是 Helm chart(ixgpu-2.0.0),搭配 Prometheus config 變更。
seldon-core 將訓練好的模型包裝成 REST/gRPC API。但在 K8s 1.29 環境下,這套平台不再安裝完整的 seldon-core,改用自家的 courier-executor 取代。
| 面向 | k3s | kubeadm (本案) |
|---|---|---|
| 安裝 | 一行指令 | 多步驟手動配置 |
| Binary | 單一執行檔 (~60MB) | kubelet + kubeadm + kubectl + containerd |
| CNI | Flannel (內建) | Calico (需另裝) |
| Ingress | Traefik (內建) | ingress-nginx (需另裝) |
| metrics-server | 內建 | 需另裝 |
| 儲存 | local-path (內建) | NFS / CSI (需另裝) |
| etcd | 預設 SQLite | 預設 etcd |
| Master Taint | 無 (預設可排程) | 有 NoSchedule (需手動移除) |
| 適用場景 | 邊緣、IoT、開發 | 生產、企業、多租戶 |
creates: 是 Ansible 的冪等機制 — 用 /tmp/xxx.done flag file 確保每個步驟只跑一次docker load → docker tag → docker push 到 Harbor,K8s 從 Harbor 拉取