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 都記錄下來。

讀完本文,您可以:

  • 在自己的電腦建出 kind 叢集:下載並驗證執行檔、用設定檔建立固定版本的叢集,約 30 秒完成。
  • 避開預設值的資安盲點:讓連接埠只綁在本機、妥善保管 kubeconfig,並知道哪些元件會開出無驗證的介面。
  • 判斷 kind 適不適合您的用途:知道它能測什麼、不該拿來做什麼,以及碰到 NodePort 不通等問題時怎麼排查。

成本與風險摘要

先看這裡:

動手前先了解要花多少資源、風險在哪裡:

  • 適用對象與規模:想學 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 模式)。

第一部分:適不適合您

這一部分說明 kind 能做什麼、適合多大規模,以及哪些情況不該用;已經確定要用的讀者可以直接跳到第二部分。

應用場景

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 提供。

適用規模與不適合的情況

kind 是「用完即丟」的測試叢集,不是正式環境。適合的用途見上方的應用場景;以下說明它需要多少資源,以及哪些情況不該用。

規模與維運成本:

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

不適合的情況:

  • 正式環境、要給同事或客戶長期使用、要保存資料:沒有原地升級,重建就清空;節點是特權容器。請改用雲端託管的 Kubernetes 或自建叢集。
  • 需要從其他電腦連進來的服務:kind 的網路設計是給本機用,硬把連接埠開到 0.0.0.0 會把測試叢集暴露出去。
  • 共用或對外的伺服器:cloud-provider-kind 會開出無驗證的 envoy 管理介面,特權節點也會放大風險。
  • 想測 eBPF 網路或特定核心功能:節點共用主機核心,主機缺什麼模組,叢集就缺什麼(本文的 iptables 與 Cilium 就是例子)。
示意圖:一台筆電裡的三個 Docker 容器分別扮演 control-plane 與兩個 worker 節點,組成一個小型 Kubernetes 叢集
圖:kind 用 Docker 容器扮演節點,整個叢集都在您自己的電腦裡。(原創示意圖)

第二部分:動手實測

這一部分是實際安裝與操作的完整紀錄,每個安裝步驟都附上實測輸出,讓您對照自己的結果;標示「進階」的段落預設收合,需要時再展開。

測試環境

項目版本/規格
主機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(原因見「實測踩坑紀錄」)

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

安裝步驟

以下以 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(2026-10-29 全新環境重跑的紀錄):

kind v0.33.0 go1.26.7 linux/amd64
/usr/local/bin/kind: OK
終端機畫面: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 模式;為什麼要改,見「實測踩坑紀錄」與「kube-proxy 三種模式的差別」。

注意:連接埠預設開在 0.0.0.0

沒有寫 listenAddress 的 extraPortMappings 會綁在主機的所有網路介面(官方文件:「0.0.0.0 is the current default」),同一個網路裡的其他電腦都連得到您的測試服務。每一組都寫上 listenAddress: "127.0.0.1",下一步建好叢集後再用步驟 4 確認。

這一步只是寫設定檔,沒有指令輸出;設定有沒有生效,會在步驟 3、4 確認。

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'

成功時您會看到:各步驟打勾、Ready after 秒數,最後 kube-proxy 紀錄出現 Using nftables Proxier(2026-10-29 實測紀錄節錄):

Creating cluster "jslab" ...
 ✓ Ensuring node image (kindest/node:v1.37.0) 🖼️
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 • Ready after 18s 💚
Set kubectl context to "kind-jslab"
I1029 00:41:05.655756       1 server_linux.go:231] "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 單節點叢集(紅框為重點標註;強哥的實驗環境)

注意:節點是特權容器

實測 kind 的節點容器以 Privileged 模式執行,seccomp 與 AppArmor 為 unconfined,也沒有記憶體上限(kind 的設計如此)。叢集裡跑的東西等於能碰到您的主機:不要在 kind 裡執行來路不明的映像,並替自己的工作負載設定記憶體上限。

注意:妥善保管 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}'

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

ss -ltnH
docker port jslab-control-plane

成功時您會看到:docker port 列出的每一組對應都是 127.0.0.1,ss 的結果裡沒有 0.0.0.0:180xx(2026-10-29 實測紀錄節錄):

80/tcp -> 127.0.0.1:18018
443/tcp -> 127.0.0.1:18019
6443/tcp -> 127.0.0.1:33005
30002/tcp -> 127.0.0.1:18002
30003/tcp -> 127.0.0.1:18003

API server 的連接埠(上面的 6443)預設就只綁 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/

成功時您會看到:三個資源建立、rollout 完成(以下為 2026-10-29 全新環境重跑的 kubectl 輸出節錄),接著最後一行 curl 印出 200:

configmap/hello-html created
deployment.apps/hello created
service/hello created
Waiting for deployment "hello" rollout to finish: 0 of 1 updated replicas are available...
deployment "hello" successfully rolled out

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

示意圖:從主機 curl 127.0.0.1:18002,經 Docker 連接埠對應到節點容器的 NodePort 30002,再由 kube-proxy 轉送到 Service 與 Pod,回應 HTTP 200
圖:從主機連到 Pod 的路徑;只綁 127.0.0.1 時,同網路的其他電腦連不到。(原創示意圖)

多節點叢集

在設定檔的 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 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 <名稱>刪除叢集(資料一併刪除)

實測踩坑紀錄

點選每個症狀可以展開原因與解法:

Pod 正常,但從主機連 NodePort 被重設(connection reset)

原因:預設 iptables 模式需要核心的 statistic 擴充(CONFIG_NETFILTER_XT_MATCH_STATISTIC),測試主機的核心沒有,kube-proxy 整批規則寫入失敗

解法:改用 kubeProxyMode: "nftables"(核心需 5.13 以上)

終端機畫面:kube-proxy 紀錄顯示 Extension statistic revision 0 not supported 與 Sync failed(節錄)
實測截圖:iptables 模式下 kube-proxy 同步規則失敗,NodePort 全部不通(節錄;紅框為重點標註;強哥的實驗環境)
沒寫 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 自訂網路的對外連線

解法:先檢查自己環境的防火牆現況(見下方),確認規則來源後再處理

先確認自己環境的防火牆現況:如果您的主機曾經切換過 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 網路之後才能執行(刪除叢集後這個網路會保留)。發現殘留規則時,請先備份並確認是哪個工具建立的,不要直接清除整個防火牆;在共用主機或公司電腦上,請先和管理者確認。

多節點建好、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 三種模式的差別

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 與 Gateway API(ingress-nginx 退役後)

很多舊教學會在 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 容器。

這一段需要另外執行 cloud-provider-kind,並會在主機開出無驗證的管理介面,和主線無關的讀者可以先略過;需要時點開下方的完整步驟。

【進階】展開:cloud-provider-kind、Ingress 與 Gateway API 實測步驟
示意圖:kubectl apply Gateway 或 Ingress 後,主機上的 cloud-provider-kind 建立 envoy 容器(172.18.0.3),再依路徑、標頭與權重把請求分到 foo-app 或 bar-app
圖:cloud-provider-kind 處理 Gateway/Ingress 的流程與本文實測的分流結果。(原創示意圖)

步驟 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 &

成功時您會看到:tarball 驗證結果為 OK(2026-10-29 實測紀錄):

cloud-provider-kind_0.12.0_linux_amd64.tar.gz: OK

危險:envoy 管理介面外露

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 容器也沒有設定記憶體上限。

雜湊值是 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

成功時您會看到:Gateway 的 PROGRAMMED 為 True,並取得 kind 網路上的 IP(2026-10-29 全新環境重跑的紀錄節錄):

gateway.gateway.networking.k8s.io/jslab-gw condition met
NAME       CLASS                 ADDRESS      PROGRAMMED   AGE
jslab-gw   cloud-provider-kind   172.18.0.3   True         1s

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

終端機畫面:Gateway API 路徑、X-Canary 標頭分流正確,200 次權重分流結果 155 比 45
實測截圖: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

  • 用完就停:用 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、無需驗證(節錄;紅框為重點標註;強哥的實驗環境)

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

開發時常用的四個操作:把本機建置的映像載入叢集、換 Kubernetes 版本(等於重建)、匯出除錯紀錄,以及重啟節點容器(資料會保留)。只想先把叢集跑起來的讀者可以跳過。

【進階】展開:載入映像、換版本、匯出紀錄、重啟節點

操作 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/

成功時您會看到:映像載入節點、rollout 完成,curl 回應映像的內容(2026-10-29 全新環境重跑的紀錄節錄;叢集名稱為驗證腳本自動產生):

Image: "jslab/hello:0.1" with ID "sha256:c055315a1273180fbbfb7239cdfd1a217274369b38d0f61599999e56a5b70cab" not yet present on node "jslab-verify-20261029-132930-control-plane", loading...
docker.io/jslab/hello                           0.1                  b9c27d8cf5504       26.1MB
deployment "hello-local" successfully rolled out
hello from jslab/hello:0.1 (kind load) via 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

成功時您會看到:匯出目錄的路徑(2026-10-29 實測紀錄;實測時匯出到 /tmp 底下的目錄):

Exporting logs for cluster "jslab" to:
/tmp/jslab-kc/kind-logs

實測 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
實測截圖:重啟節點容器後叢集自動恢復,資料保留(第一次實測;紅框為重點標註;強哥的實驗環境)
示意圖:左邊是換 Kubernetes 版本的流程(刪除、重建、重新套用,舊資料清空),右邊是重啟節點容器的流程(API 與服務自動恢復,資料保留)
圖:換版本=重建(資料清空),重啟節點=保留資料。(原創示意圖)

【進階】用 Headlamp 看叢集(取代已封存的 Kubernetes Dashboard)

Kubernetes Dashboard 已在 2026-01-21 封存,官方文件建議新安裝改用 Headlamp。以下用 Helm 安裝在叢集內,只透過 127.0.0.1 的 port-forward 存取。只想先把叢集跑起來的讀者可以跳過。

【進階】展開:Headlamp 安裝、短效 token 登入與清除
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

注意:cluster-admin 權限很大

範例替 Headlamp 建立 cluster-admin 權限的 ServiceAccount,只適合本機實驗叢集;token 用短效(30 分鐘),只走 127.0.0.1 的 port-forward,token 檔不要截圖或分享。

開啟 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。
  • 用完清除:依序執行 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 紀錄(紅框為重點標註;強哥的實驗環境)

安全檢查清單與清理

預設值偏方便

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 移除。

第三部分:評價與延伸

這一部分是實測後的評價、使用小技巧與延伸資源。

優缺點

優點:

  • 免費又快:不需要雲端帳號,約 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 管理介面外露的問題。

綜合評價

長條圖:kind 綜合評價,社群活躍度 4 分、安裝難易度 4 分、更新頻率 3 分、升級方式 3 分、計費模式 5 分(滿分 5 分)
圖:kind 五個面向的評分(滿分 5 分;原創圖表)

文字版評分與理由:

  • 社群活躍度:★★★★☆(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 讓您不用付雲端費用,約 30 秒就在自己的電腦上有一個真的 Kubernetes 叢集;只要先把連接埠綁在本機、改用 nftables 模式並保管好 kubeconfig,就能放心拿來學習與驗證設定。它的定位是用完即丟的測試環境,正式服務請改用正式的 Kubernetes 叢集。

下一步,您可以:

NotebookLM 互動問答

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

參考連結

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

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

返回頂端