kind 封面圖:在本機免費建 Kubernetes 測試叢集

kind:在本機免費建 Kubernetes 測試叢集,實測踩坑與資安設定

內容概述

kind(Kubernetes IN Docker)是一個開源(Apache-2.0 授權)的工具,用 Docker 容器當作 Kubernetes 的「節點」,在一台電腦上就能建立完整的 Kubernetes 叢集。官方說明 kind 原本是為了測試 Kubernetes 本身而設計,也可以用在本機開發與 CI。

對個人開發者和中小企業的平台團隊來說,它解決的是「想練習或驗證 Kubernetes,卻不想先付雲端叢集費用」的問題:軟體免費,叢集約 30 秒建好,用完一個指令刪掉。本文以 kind v0.33.0、Kubernetes v1.37.0 實際操作,除了基本安裝,也把預設設定在資安上的盲點、網路模式踩到的坑,以及 ingress-nginx 退役後怎麼測 Ingress 與 Gateway API 都記錄下來。

測試方式說明:本文的安裝、部署、多節點、版本切換、Ingress、Gateway API、Headlamp 等步驟皆為實測(2026-10-29),並在全新環境用同一份腳本把整套流程重跑一次,14 個檢查項目全部通過;標示「查核」的內容來自官方文件或原始碼;標示「未實測」的項目(例如 Cilium/eBPF、TLS)只依官方文件說明。文中的時間與記憶體數字都來自實測紀錄,兩次測試數字不同時會列出範圍。

什麼規模才需要 kind

kind 是「用完即丟」的測試叢集,不是正式環境。可依下列情況判斷:

  • 想學 Kubernetes、跑教學範例:很適合,一台 16 GB 記憶體的電腦就能跑三節點叢集。
  • 開發要部署到 Kubernetes 的程式,想在本機先驗證 YAML、Helm chart:很適合,搭配本機映像載入(kind load)不用推到映像檔倉庫。
  • 想在升級前先試新版 Kubernetes 或新版 manifest:適合,指定節點映像就能切換版本。
  • 要給同事或客戶長期使用的服務:不適合。kind 沒有原地升級、重建就清空資料,節點容器以特權模式執行,也沒有對外服務的設計。正式環境請改用雲端託管的 Kubernetes 或自建叢集。
示意圖:一台筆電裡的三個 Docker 容器分別扮演 control-plane 與兩個 worker 節點,組成一個小型 Kubernetes 叢集
圖:kind 用 Docker 容器扮演節點,整個叢集都在您自己的電腦裡。(原創示意圖)

應用場景

kind 適合「需要一個真的 Kubernetes,但不需要它一直存在」的情境,例如:

  • 學習與教學:照著官方文件或書本練習 Deployment、Service、Ingress,做錯就刪掉重建。
  • 本機開發驗證:在本機建置映像,載入叢集測試,不必經過網路或映像檔倉庫。
  • 版本相容性測試:同一份 YAML 在 v1.36 和 v1.37 各建一次叢集試跑。
  • 網路與流量規則實驗:測試 Ingress、Gateway API 的路徑、標頭與權重分流規則。
  • CI 測試:官方說明 kind 也可以用在 CI;本文沒有實測 CI 流程。

技術特點

  • 容器即節點:每個節點是一個 Docker 容器,裡面跑 kubelet、containerd 和 Kubernetes 元件。
  • 多節點:用設定檔宣告 control-plane 與 worker 的數量,實測 1 個 control-plane 加 2 個 worker 約 26~28 秒建好。
  • 指定 Kubernetes 版本:每個 kind 版本會公布一組預先建好的節點映像(v0.33.0 提供 v1.37.0、v1.36.4、v1.35.8、v1.34.11 等),建議用 @sha256: 固定版本(官方 Quick Start 原文:「Please use the sha256 shasum」)。
  • 本機映像載入:kind load docker-image 把本機建置好的映像直接放進節點,不用推到網路上。
  • kube-proxy 模式可選:可設定 iptables(預設)、nftables(Kubernetes v1.31 以上)或 ipvs,也可以設成 none 改用其他方案(見後面的「kube-proxy 三種模式的差別」)。
  • 沒有外掛系統:kind 不像 kubectl 有外掛機制(官方 RFC #1986 已關閉)。LoadBalancer、Ingress 這類功能由同一個 SIG 維護的獨立程式 cloud-provider-kind 提供。

測試環境

項目版本/規格
主機Debian 13,Linux kernel 6.12.x,8 vCPU/16 GB 記憶體
容器執行環境Docker 29.9.2
kindv0.33.0(2026-08-27 發佈,台北時間;SHA256 已驗證)
節點映像kindest/node v1.37.0、v1.36.4(皆以 sha256 digest 固定)
kubectlv1.37.2
cloud-provider-kindv0.12.0(tarball SHA256 已驗證)
HeadlampHelm chart 0.46.0(helm v4.3.1)
kube-proxy 模式nftables(原因見「實測踩坑紀錄」)

安裝步驟

以下以 kind v0.33.0 為例(請以 GitHub Releases 頁面的最新版本為準)。kind 需要先安裝 Docker(官方也支援 Podman、nerdctl,本文未實測),以及 kubectl。

1. 下載並驗證 kind 執行檔

從 v0.33.0 Releases 頁面下載符合您平台的執行檔(本文為 kind-linux-amd64)和同名的 .sha256sum 檔,放到 PATH 中並命名為 kind。一定要比對 SHA256,確認下載的檔案沒有被竄改:

echo "aee6151561422756b764a4ae28e7f44cda5af5a9eead3cc9985112b1de8d8e0d  $(command -v kind)" | sha256sum -c
kind version

上面的雜湊值是 kind-linux-amd64 v0.33.0 的值,其他平台或版本請改用 Releases 頁面對應的 .sha256sum 檔。看到 OK 和 kind v0.33.0 就代表安裝正確。

終端機畫面:sha256sum 驗證 kind 執行檔顯示 OK,kind version 顯示 v0.33.0
實測截圖:驗證 kind 執行檔的 SHA256 並確認版本(強哥的實驗環境)

2. 準備叢集設定檔

官方 Quick Start 的一行 kind create cluster 就能建出叢集,但預設值有兩個地方建議先改:連接埠預設綁在所有網路介面(0.0.0.0),以及 kube-proxy 預設用 iptables 模式(在部分核心上會整個不通,見踩坑紀錄)。本文實測用的設定檔 kind-config.yaml 如下(節錄,完整設定共 10 組連接埠):

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: jslab
networking:
  kubeProxyMode: "nftables"
nodes:
  - role: control-plane
    image: kindest/node:v1.37.0@sha256:a1ed56cfb0e7b93589bdf97c8cd566405a265939e3620fc4f5de89adff580ae5
    labels:
      ingress-ready: "true"
    extraPortMappings:
      - { containerPort: 30002, hostPort: 18002, listenAddress: "127.0.0.1", protocol: TCP }
      - { containerPort: 30003, hostPort: 18003, listenAddress: "127.0.0.1", protocol: TCP }
  • image 加上 @sha256::固定節點映像,避免同一個標籤日後指向不同內容。digest 請從 kind 的 Releases 頁面複製。
  • listenAddress: "127.0.0.1":讓 NodePort 只在本機可以連。官方文件註明「0.0.0.0 is the current default」,不寫就會開在所有介面上。
  • kubeProxyMode: "nftables":改用 nftables 模式;為什麼要改,見後面兩個章節。

3. 建立叢集並確認狀態

kind create cluster --name jslab --config kind-config.yaml --wait 120s
kubectl get nodes -o wide
kubectl wait --for=condition=Ready node --all --timeout=120s
kubectl -n kube-system logs ds/kube-proxy | grep -m1 'Using nftables Proxier'

實測建立時間:節點映像已在本機時約 26~28 秒;第一次建立(含下載約 1.34 GB 的節點映像)為 35.7 秒(2026-10-28 實測)。單節點叢集的節點容器約使用 517~632 MiB 記憶體,刪除叢集不到 1 秒。最後一行看到 Using nftables Proxier,代表 kube-proxy 確實用 nftables 模式。

終端機畫面:kind create cluster 建立 v1.37.0 叢集的過程,各步驟顯示勾選完成
實測截圖:用設定檔建立 Kubernetes v1.37.0 單節點叢集(強哥的實驗環境)

4. 確認連接埠只綁在本機

ss -ltnH
docker port jslab-control-plane 6443/tcp

API server 預設就只綁 127.0.0.1 的隨機連接埠;extraPortMappings 有寫 listenAddress: "127.0.0.1" 的連接埠也只會出現在 127.0.0.1。同樣的設定拿掉 listenAddress 再建一次,實測 18003 會變成 0.0.0.0:18003,同一個網路裡的其他電腦都連得到。

終端機畫面:沒有指定 listenAddress 時,ss 顯示 18003 綁在 0.0.0.0(節錄)
實測截圖:沒寫 listenAddress 的對照組,連接埠開在所有介面(節錄;強哥的實驗環境)
終端機畫面:ss 顯示 18002 到 18019 與 API server 都只綁在 127.0.0.1
實測截圖:指定 127.0.0.1 之後,所有連接埠都只在本機(強哥的實驗環境)

5. 部署範例並從主機連線

範例 k8s-hello.yaml 是一個 nginx Deployment(設定記憶體上限 64Mi)加上 NodePort 30002 的 Service,對應到主機的 127.0.0.1:18002:

kubectl apply -f k8s-hello.yaml
kubectl rollout status deploy/hello --timeout=120s
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:18002/

實測從 kubectl apply 到回應 HTTP 200 約 2.7 秒。

kind 常用指令速查

以下指令都在本次實測中執行過:

指令用途
kind version顯示 kind 版本
kind create cluster --name <名稱> --config <設定檔> --wait 120s建立叢集,等待節點就緒
kind get clusters列出所有 kind 叢集
kind get nodes --name <名稱>列出叢集的節點容器
kind load docker-image <映像> --name <名稱>把本機映像載入叢集節點
kind export logs <目錄> --name <名稱>匯出除錯紀錄
kind delete cluster --name <名稱>刪除叢集(資料一併刪除)

妥善保管 kubeconfig:官方說明沒有設定 KUBECONFIG 環境變數時,kind 會把連線設定寫進 ${HOME}/.kube/config。這個檔案等同叢集的管理員鑰匙,不要貼到聊天室、Issue 或 AI 工具裡。本文實測把它放在權限 600 的獨立檔案,可以這樣檢查:

stat -c '%a %U:%G %n' "$KUBECONFIG"
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'

實測踩坑紀錄

症狀原因解法
Pod 正常,但從主機連 NodePort 被重設(connection reset)預設 iptables 模式需要核心的 statistic 擴充(CONFIG_NETFILTER_XT_MATCH_STATISTIC),測試主機的核心沒有,kube-proxy 整批規則寫入失敗改用 kubeProxyMode: "nftables"(核心需 5.13 以上)
沒寫 listenAddress,連接埠開在 0.0.0.0官方預設值就是 0.0.0.0每組 extraPortMappings 都寫 listenAddress: "127.0.0.1"
Pod 一直卡在 ContainerCreating、rollout 逾時,預設 bridge 網路卻正常主機殘留舊的 iptables-legacy DOCKER 規則(FORWARD 預設 DROP),擋掉 kind 自訂網路的對外連線先檢查自己環境的防火牆現況(見下方),確認規則來源後再處理
多節點建好、rollout 完成,第一次 curl 卻回 000新 Pod 的轉送規則還沒同步完成等 1~5 秒再試,或在腳本中加重試
重啟節點容器後,local-path-provisioner 顯示 Error它比 API server 先啟動、連不上而退出會自動重啟恢復,不需處理
kubectl top 無法使用kind 預設沒有安裝 metrics-server改用 docker stats 看節點容器的資源用量
升級 Kubernetes 版本後,之前建的資源都不見了kind 沒有原地升級,換版本=刪掉重建把 YAML、Helm 指令保存在 Git,重建後重新套用
執行 kind 或 docker 指令出現權限錯誤使用者不在 docker 群組加入 docker 群組;注意 Docker 官方提醒 docker 群組等同 root 權限
終端機畫面:kube-proxy 紀錄顯示 Extension statistic revision 0 not supported 與 Sync failed(節錄)
實測截圖:iptables 模式下 kube-proxy 同步規則失敗,NodePort 全部不通(節錄;強哥的實驗環境)

先確認自己環境的防火牆現況:如果您的主機曾經切換過 iptables 與 nftables,或裝過其他防火牆工具,建立 kind 叢集前可以先做兩個檢查。第一行檢查有沒有殘留的 iptables-legacy DOCKER 規則(ip6tables-legacy 也照樣檢查),第二行從 kind 網路連 Docker Hub,回應 401 代表網路是通的(只是沒有登入):

sudo -n iptables-legacy -S | grep -q -- '-N DOCKER' && echo "有殘留的 iptables-legacy DOCKER 規則"
docker run --rm -m 64m --network kind nginx:1.30.6-alpine wget -q -O /dev/null -T 8 https://registry-1.docker.io/v2/

第二行要在 kind 建立過 kind 網路之後才能執行(刪除叢集後這個網路會保留)。發現殘留規則時,請先備份並確認是哪個工具建立的,不要直接清除整個防火牆;在共用主機或公司電腦上,請先和管理者確認。

kube-proxy 三種模式的差別

kube-proxy 負責把 Service 的流量轉送到 Pod,它有幾種實作方式。這是 kube-proxy 的模式,不是容器網路介面(CNI);kind 預設的 CNI 是 kindnet,本文沒有更換。

模式官方狀態核心需求本次實測
iptablesKubernetes v1.37 與 kind 的預設需要 iptables 擴充模組(含 statistic)失敗:測試核心缺少 statistic,NodePort 不通
nftablesKubernetes v1.33 起為穩定版(GA),官方表示未來會改成預設Linux 核心 5.13 以上成功,本文全程使用
ipvsv1.35 起棄用,v1.40 起預設停用,v1.43 移除需要 IPVS 模組未實測(已棄用)
不用 kube-proxy(eBPF,例如 Cilium)kind 可設 kubeProxyMode: "none" 並停用預設 CNICilium 需核心 5.10 以上與多項模組未實測(原因見下方)
  • nftables 與 iptables 的行為差異:官方說明 iptables 模式的 NodePort 預設在節點所有 IP 上都能連,nftables 模式則預設只在節點的主要 IP 上(--nodeport-addresses primary)。從主機透過 extraPortMappings 連 127.0.0.1:18002 不受影響(實測正常)。
  • 從 iptables 改成 nftables:kind 叢集直接在設定檔改 kubeProxyMode 後重建即可;正式叢集要切換,請先讀官方的遷移說明,因為部分防火牆互動行為不同。
  • 為什麼沒有實測 Cilium:查核時 Cilium 穩定版 v1.20.4 的支援清單只到 Kubernetes v1.36,還沒有列 v1.37;測試主機的精簡核心也缺少 Cilium 預設設定需要的 VXLAN/GENEVE、ipset 等模組,要為這台主機改多個設定值,結果不具代表性,所以只依官方文件說明。

ingress-nginx 退役後,在 kind 測 Ingress 與 Gateway API

很多舊教學會在 kind 上裝 ingress-nginx,但 Kubernetes 官方部落格已宣布 ingress-nginx 在 2026 年 3 月退役、停止維護;官方的 Ingress 文件也寫明 Ingress API 已凍結,建議改用 Gateway API。kind 官方的 Ingress 文件目前改用 cloud-provider-kind(從 v0.9.0 起原生支援 Ingress,不必另外安裝 Ingress 控制器),它會在主機上執行,替 LoadBalancer、Ingress 和 Gateway 建立 envoy 容器。

1. 下載、驗證並啟動 cloud-provider-kind

curl -fsSL -o cloud-provider-kind_0.12.0_linux_amd64.tar.gz https://github.com/kubernetes-sigs/cloud-provider-kind/releases/download/v0.12.0/cloud-provider-kind_0.12.0_linux_amd64.tar.gz
echo "5716aca8f01a85172c12f3b6329c70f151bec02c91b6f600c9f230845ee138e6  cloud-provider-kind_0.12.0_linux_amd64.tar.gz" | sha256sum -c
tar xzf cloud-provider-kind_0.12.0_linux_amd64.tar.gz cloud-provider-kind
./cloud-provider-kind --gateway-channel standard > cpk.log 2>&1 &

雜湊值是 v0.12.0 Linux amd64 tarball 的值(來自 Releases 頁面的 checksums)。cloud-provider-kind 需要存取 Docker,官方說明它需要開連接埠與連線容器執行環境的權限。啟動後會自動安裝 Gateway API 的 CRD、預設的 IngressClass 和名為 cloud-provider-kind 的 GatewayClass;第一次使用時還會下載 envoy 映像(約 261 MB)。

2. 用 Ingress 依路徑分流

這裡直接套用 kind 官方文件的 Ingress 範例(ingress-usage.yaml:/foo 和 /bar 分到兩個 Pod)。官方範例沒有設定資源上限,所以先套用一份 LimitRange,替 default 命名空間的容器加上預設記憶體上限 64Mi:

kubectl apply -f limitrange-default.yaml -f ingress-usage.yaml
kubectl wait --for=condition=Ready pod/foo-app pod/bar-app --timeout=180s
IP=$(kubectl get ingress example-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://$IP/foo
kubectl get ingressclass,gatewayclass

實測從套用到 Ingress 取得 IP 約 2~4.9 秒,/foo、/bar 都分流正確。這個 IP(實測為 172.18.0.3)位在 Docker 的 kind 網路上,只有本機連得到。cloud-provider-kind 內部會把 Ingress 轉成 Gateway 與 HTTPRoute 來處理。

終端機畫面:Ingress 取得 172.18.0.3,curl /foo 與 /bar 分別回應 foo-app 與 bar-app
實測截圖:cloud-provider-kind 讓官方 Ingress 範例在 kind 上運作(強哥的實驗環境)

3. 用 Gateway API 做路徑、標頭與權重分流

Gateway API 把「入口」(Gateway)和「路由規則」(HTTPRoute)分開。下面節錄自本文的 gateway-usage.yaml,後端同樣是 foo、bar 兩個 Pod:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata: { name: jslab-gw }
spec:
  gatewayClassName: cloud-provider-kind
  listeners:
  - { name: http, protocol: HTTP, port: 80, allowedRoutes: { namespaces: { from: Same } } }
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: { name: canary-header }
spec:
  parentRefs: [ { name: jslab-gw } ]
  rules:
  - matches: [ { path: { type: PathPrefix, value: /app }, headers: [ { name: X-Canary, value: "true" } ] } ]
    backendRefs: [ { name: bar-service, port: 8080 } ]
  - matches: [ { path: { type: PathPrefix, value: /app } } ]
    backendRefs: [ { name: foo-service, port: 8080 } ]
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: { name: weighted }
spec:
  parentRefs: [ { name: jslab-gw } ]
  rules:
  - matches: [ { path: { type: PathPrefix, value: /split } } ]
    backendRefs:
    - { name: foo-service, port: 8080, weight: 80 }
    - { name: bar-service, port: 8080, weight: 20 }
kubectl apply -f limitrange-default.yaml -f gateway-usage.yaml
kubectl wait --for=condition=Programmed gateway/jslab-gw --timeout=120s
GW=$(kubectl get gateway jslab-gw -o jsonpath='{.status.addresses[0].value}')
curl -H 'X-Canary: true' http://$GW/app

實測結果:帶 X-Canary: true 標頭的請求分到 bar,沒帶的分到 foo;對 /split 送 200 次請求,兩次測試分別為 155/45 與 157/43,接近設定的 80/20。從套用到 /foo 有回應約 2.3~3.0 秒。

終端機畫面:Gateway API 路徑、X-Canary 標頭分流正確,200 次權重分流結果 157 比 43
實測截圖:Gateway API 的路徑、標頭與權重分流(強哥的實驗環境)

4. Ingress 與 Gateway API 怎麼選

比較項目IngressGateway API
官方狀態API 已凍結,不再加新功能官方建議的新方式
本次範例官方範例 5 個物件、77 行8 個物件、73 行(多了標頭與權重兩條規則)
標頭、權重分流標準欄位沒有,要靠各控制器的註解標準欄位就支援(實測可用)
實測反應時間套用到可連線約 3.5~4.9 秒約 2.3~3.0 秒
資源用量(實測)envoy 約 17~19 MiB,cloud-provider-kind 約 68~75 MiB相同

簡單來說:維護既有的 Ingress YAML,kind 上用 cloud-provider-kind 一樣能測;新寫的設定建議直接用 Gateway API。TLS 本次未實測。

5. 用完記得停止 cloud-provider-kind

cloud-provider-kind 的 envoy 管理介面(admin)會被 Docker 的 --publish-all 發佈到主機的 0.0.0.0 隨機連接埠,而且沒有驗證。實測連到 /server_info 直接回 HTTP 200;這個行為寫在 cloud-provider-kind 的程式碼裡,沒有選項可以關掉。另外,它和 envoy 溝通的 XDS 服務會在 Docker 預設網橋 172.17.0.1 上開一個隨機連接埠;envoy 容器也沒有設定記憶體上限。

  • 用完就停:用 kill -TERM <PID> 停止 cloud-provider-kind,它會自動移除 envoy 容器,實測停止後管理介面和 XDS 連接埠都不再監聽。
  • 不要在有公開 IP 或不受信任網路的主機上執行:如果一定要用,請先用主機防火牆擋掉這些隨機連接埠。
終端機畫面:ss 顯示 envoy admin 綁在 0.0.0.0:32768,GET /server_info 回應 200
實測截圖:cloud-provider-kind 的 envoy 管理介面開在 0.0.0.0、無需驗證(節錄;強哥的實驗環境)

本機開發流程:載入映像、換版本、匯出紀錄、重啟節點

1. 載入本機建置的映像

在本機建置映像後用 kind load 放進節點,Deployment 要設定 imagePullPolicy: IfNotPresent,否則 Kubernetes 會試著從網路拉這個不存在的映像:

docker build -q -t jslab/hello:0.1 hello-image
kind load docker-image jslab/hello:0.1 --name jslab
docker exec jslab-control-plane crictl images | grep jslab/hello
kubectl apply -f hello-local.yaml
curl -s http://127.0.0.1:18003/

實測建置加載入約 3.3 秒,Pod 事件顯示「already present on machine」,代表映像沒有從網路下載。

終端機畫面:kind load docker-image 載入 jslab/hello:0.1,crictl images 列出映像,curl 18003 回應映像內容
實測截圖:本機映像直接載入叢集節點使用(強哥的實驗環境)

2. 指定舊版 Kubernetes,以及「升級=重建」

把設定檔中的節點映像換成 kindest/node:v1.36.4@sha256:099e049362a1526b2db71494e1947aae99bd16290d7c895f2b7ea312e3cbfaed 就能建立 v1.36.4 叢集(實測 26.1~26.6 秒)。kind 沒有原地升級,要換版本就是刪掉重建:

kind delete cluster --name jslab
kind create cluster --name jslab --config kind-config.yaml --wait 120s
kubectl version -o json

實測從 v1.36.4 重建成 v1.37.0 約 27.3~31.4 秒,舊叢集裡建立的 ConfigMap 不在了。kubectl v1.37.2 連 v1.36.4 叢集沒有出現警告,符合官方「kubectl 與 API server 相差一個次版本以內」的版本差異政策;更舊的叢集請換對應版本的 kubectl。

終端機畫面:kind delete 後重建為 v1.37.0,舊叢集的 configmap 查不到
實測截圖:kind 換版本就是重建,舊資料不會保留(強哥的實驗環境)

3. 匯出除錯紀錄

kind export logs ./kind-logs --name jslab

實測 0.2 秒匯出 32 個檔案(約 712 KB~784 KB)。分享前請先檢查內容:實測匯出的紀錄包含主機名稱與多個內部 IP,貼到 Issue 或論壇前要先遮蔽。

4. 重啟節點容器,資料會保留

和「重建」不同,重新啟動節點容器不會清空叢集:

kubectl create configmap restart-marker --from-literal=before=restart
docker restart jslab-control-plane
kubectl get --raw /readyz

實測 docker restart 約 11.4~11.5 秒,API server 約 17 秒後恢復,範例服務 18002 在 17.0~35.4 秒間恢復,ConfigMap 與節點 IP 都沒變。期間 local-path-provisioner 會短暫顯示 Error,之後自動恢復。

終端機畫面:docker restart 節點後 API readyz 在 17 秒恢復,configmap 仍在,hello Pod Running,local-path-provisioner 顯示 Error
實測截圖:重啟節點容器後叢集自動恢復,資料保留(第一次實測;強哥的實驗環境)

5. 用 Headlamp 看叢集(取代已封存的 Kubernetes Dashboard)

Kubernetes Dashboard 已在 2026-01-21 封存,官方文件建議新安裝改用 Headlamp。以下用 Helm 安裝在叢集內,只透過 127.0.0.1 的 port-forward 存取:

helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/
helm repo update headlamp
helm install headlamp headlamp/headlamp --version 0.46.0 -n kube-system --set resources.limits.memory=256Mi --set resources.requests.memory=64Mi --wait --timeout 180s
kubectl -n kube-system create serviceaccount jslab-headlamp-admin
kubectl create clusterrolebinding jslab-headlamp-admin --clusterrole=cluster-admin --serviceaccount=kube-system:jslab-headlamp-admin
( umask 077; kubectl -n kube-system create token jslab-headlamp-admin --duration=30m > hl.token )
kubectl -n kube-system port-forward --address 127.0.0.1 service/headlamp 18010:80

開啟 http://127.0.0.1:18010/,貼上 hl.token 的內容登入。實測安裝(含等待 Pod 就緒)約 22 秒,Headlamp Pod 約 16~22 MB 記憶體;用 token 呼叫 API 回 200,沒有 token 回 403。

  • token 用短效:create token --duration=30m 產生 30 分鐘後失效的 token,不要建立長效的 Secret token。
  • cluster-admin 權限很大:只在本機實驗叢集這樣做;token 檔不要截圖、不要分享。
  • 用完清除:依序執行 shred -u hl.token、helm uninstall headlamp -n kube-system --wait、刪除 clusterrolebinding 與 serviceaccount、helm repo remove headlamp。
Headlamp 總覽頁面,顯示 1 個節點 Ready、11 個 Pod 與最近的警告事件
實測截圖:Headlamp 總覽頁面(強哥的實驗環境)
Headlamp Pods 清單,列出 kube-system 與 default 命名空間的 Pod 狀態
實測截圖:在 Headlamp 檢視所有 Pod(強哥的實驗環境)
Headlamp 顯示 Pod 即時紀錄的畫面
實測截圖:在 Headlamp 查看 Pod 紀錄(強哥的實驗環境)

多節點叢集

在設定檔的 nodes 加上兩個 worker(映像同樣以 digest 固定)就是 1 個 control-plane 加 2 個 worker:

  - role: worker
    image: kindest/node:v1.37.0@sha256:a1ed56cfb0e7b93589bdf97c8cd566405a265939e3620fc4f5de89adff580ae5
  - role: worker
    image: kindest/node:v1.37.0@sha256:a1ed56cfb0e7b93589bdf97c8cd566405a265939e3620fc4f5de89adff580ae5
kind create cluster --name jslab --config kind-config-3node.yaml --wait 120s
kubectl get nodes
kubectl scale deploy/hello --replicas=3
kubectl get pods -o wide

實測建立約 26.1~27.5 秒,記憶體用量 control-plane 約 545~600 MiB、每個 worker 約 119~182 MiB。

  • inotify 上限:測試主機維持預設上限(instances 128),三節點時 root 已用 91 個 instance(control-plane 約 45 個、每個 worker 約 18 個),還沒出現「too many open files」。依這個幅度推估,再多約兩個 worker 就可能碰到上限;官方 Known Issues 建議調成 fs.inotify.max_user_watches=524288、fs.inotify.max_user_instances=512。
  • 實際用量:可用 cat /proc/sys/fs/inotify/max_user_instances 查看目前上限。
終端機畫面:kubectl get nodes 顯示 1 個 control-plane 與 2 個 worker 皆為 Ready
實測截圖:三節點叢集建立完成(強哥的實驗環境)

安全檢查清單與清理

kind 是開發工具,很多預設值是為了方便,不是為了安全。使用前後可以照這份清單檢查:

  • 驗證下載的檔案:kind 執行檔、cloud-provider-kind tarball 都比對 SHA256;節點映像用 @sha256: 固定。
  • 連接埠只綁本機:extraPortMappings 一律寫 listenAddress: "127.0.0.1",用 ss -ltnH 確認沒有 0.0.0.0。
  • 保管 kubeconfig:權限 600,不要分享 kind get kubeconfig 的輸出。
  • 知道節點是特權容器:實測節點容器以 Privileged 模式執行、seccomp 與 AppArmor 為 unconfined、沒有記憶體上限。不要在 kind 裡跑來路不明的映像,並自行替工作負載設定記憶體上限。
  • cloud-provider-kind 用完就停:envoy 管理介面開在 0.0.0.0 且無驗證。
  • 分享紀錄前先遮蔽:kind export logs 會包含主機名稱與內部 IP。
  • Headlamp 用短效 token,只走 127.0.0.1 的 port-forward。

用完後清理:

kind delete cluster --name jslab
kind get clusters
docker image rm jslab/hello:0.1

刪除叢集後,Docker 的 kind 網路會保留(下次建立會沿用);節點映像每個約 1.3 GB,不再需要時可用 docker image rm 移除。

什麼情況不該用 kind

  • 正式環境或要長期保存資料:沒有原地升級,重建就清空;節點是特權容器。
  • 需要從其他電腦連進來的服務:kind 的網路設計是給本機用,硬把連接埠開到 0.0.0.0 會把測試叢集暴露出去。
  • 共用或對外的伺服器:cloud-provider-kind 會開出無驗證的 envoy 管理介面,特權節點也會放大風險。
  • 想測 eBPF 網路或特定核心功能:節點共用主機核心,主機缺什麼模組,叢集就缺什麼(本文的 iptables 與 Cilium 就是例子)。

適用規模與維運成本

  • 授權:Apache-2.0,免費,沒有付費版本。
  • 硬體:單節點叢集約 0.5~0.6 GB 記憶體,三節點約 0.9 GB;每個節點映像約 1.3 GB 磁碟。8 vCPU/16 GB 的電腦跑三節點仍有餘裕(實測)。
  • 時間:建立約 30 秒、刪除不到 1 秒;換 Kubernetes 版本等於重建。
  • 維護工作:定期更新 kind 執行檔並驗證 SHA256;用完刪叢集、停 cloud-provider-kind;偶爾清掉不用的節點映像。

優缺點分析

優點:

  • 免費又快:不需要雲端帳號,約 30 秒就有一個真的 Kubernetes 叢集。
  • 重現性高:設定檔加上固定 digest,換一台電腦也能建出一樣的叢集。
  • 貼近正式 Kubernetes:用上游的 kubeadm 與元件,可以測多節點、版本差異、Gateway API。
  • 官方維護:Kubernetes SIG 專案,更新跟著 Kubernetes 版本走。

缺點:

  • 預設值偏方便、不偏安全:連接埠預設 0.0.0.0、Quick Start 的安裝指令沒有 SHA256 驗證步驟、節點是特權容器。
  • 和主機核心綁在一起:本文就碰到預設 iptables 模式在精簡核心上整個不通。
  • 沒有升級:換版本就清空資料。
  • 周邊功能要另外裝:LoadBalancer、Ingress、metrics-server、Dashboard 都不是內建,cloud-provider-kind 還有 envoy 管理介面外露的問題。

綜合評價

面向評分理由與來源
社群活躍度★★★★☆(4)GitHub 15,580 星、1,825 個 fork,近 90 天 39 個 commit、10 位非機器人作者,屬 Kubernetes SIG 專案。(GitHub API,2026-10-29)
安裝難易度★★★★☆(4)一個執行檔加 Docker,叢集約 26~28 秒建好(實測);扣一顆星是因為預設 0.0.0.0、iptables 模式在部分核心不通,要自己改設定檔。
更新頻率★★★☆☆(3)近 12 個月 3 個版本(v0.31.0、v0.32.0、v0.33.0),每版附新 Kubernetes 版本的節點映像;最近一次 commit 為 2026-10-22。(GitHub Releases/API,2026-10-29)
升級方式★★★☆☆(3)換執行檔很簡單,但叢集沒有原地升級,重建約 27~31 秒且資料清空(實測)。
計費模式★★★★★(5)Apache-2.0 授權,完全免費、沒有付費版本;成本只有本機的記憶體與磁碟。(GitHub LICENSE)

小技巧

  • 設定檔放進 Git:kind 設定、YAML、Helm 指令都保存在儲存庫,重建時幾分鐘就能回到原狀。
  • NodePort 固定對應:在設定檔預留一段 NodePort(例如 30002~30009 對應 18002~18009),測試服務時就不用每次改設定重建。
  • 本機映像載入失敗時:本文沒有重現官方 Issue #3795 描述的載入失敗;如果您遇到,可依 Known Issues 改用 docker image save --platform linux/amd64 存成檔案,再用 kind load image-archive 載入(實測可用)。
  • 定期更新:更新 kind 前先看 Releases 頁面的 Breaking Changes,換新執行檔後再驗證一次 SHA256;叢集要換版本就照「升級=重建」流程。
  • 想把 kind 上驗證過的服務搬到正式叢集,可參考 MetalLB:裸機 Kubernetes 叢集的負載平衡解決方案 與 Harbor:自架容器映像檔倉庫;導入時有問題,歡迎透過聯絡我們詢問。

NotebookLM 互動問答

想針對本文或官方文件提問,可以使用我們整理的 NotebookLM 筆記:kind 互動問答(NotebookLM)。筆記的來源只收錄 kind、Kubernetes、cloud-provider-kind、Gateway API 與 Headlamp 的官方網站、官方文件與 GitHub 儲存庫,回答內容仍請以官方文件為準。

參考連結

本文僅供學習參考,請在您自己的環境自行評估風險,詳見免責與揭露聲明。

本文寫作方式:本文的測試計劃與審稿由強哥負責,實測操作、紀錄整理與初稿由 AI 助理協作完成,所有數字皆來自實測紀錄或官方來源;封面與示意圖為原創繪製(未使用 AI 生成圖片),截圖為實測畫面。

成本與風險摘要

  • 適用對象與規模:想學 Kubernetes 的個人、需要在本機驗證 YAML/Helm chart 的開發者與平台工程師;只適合用完即丟的測試叢集,正式環境請改用雲端託管或自建 Kubernetes。
  • 成本(硬體、訂閱、授權):Apache-2.0,免費、沒有付費版本;單節點約 0.5~0.6 GB 記憶體、三節點約 0.9 GB,每個節點映像約 1.3 GB 磁碟;不需要訂閱。
  • 維護時間:建立約 30 秒、刪除不到 1 秒;定期更新 kind 並驗證 SHA256,換 Kubernetes 版本要重建叢集並重新套用設定。
  • 資安注意事項:extraPortMappings 寫 listenAddress: "127.0.0.1"(預設 0.0.0.0);kubeconfig 權限 600 不外流;節點是特權容器且沒有記憶體上限;cloud-provider-kind 的 envoy 管理介面開在 0.0.0.0 且無驗證,用完就停;kind export logs 含主機名稱與內部 IP。
  • 常見誤區:以為預設 iptables 模式到處都能用(精簡核心可能整個不通);以為改節點映像就能升級(其實是重建、資料清空);主機殘留的舊防火牆規則讓 Pod 拉不到映像,卻誤以為是 kind 的問題。
  • 不建議使用的情況:正式服務、需要保存資料、需要讓其他電腦連入、有公開 IP 的共用伺服器;這些情況請改用正式的 Kubernetes 叢集。
  • 測試日期與版本號:測試日期:2026-10-29;kind v0.33.0(測試環境:Debian 13、Linux kernel 6.12.x、8 vCPU/16 GB、Docker 29.9.2、kindest/node v1.37.0 與 v1.36.4、kubectl v1.37.2、cloud-provider-kind v0.12.0、Headlamp chart 0.46.0、helm v4.3.1;kube-proxy nftables 模式)。
返回頂端