前言
官方文档地址:https://kind.sigs.k8s.io/
github仓库地址:https://github.com/kubernetes-sigs/kind
国内镜像仓库地址:https://gitcode.com/gh_mirrors/ki/kind/overview
kind 是一种使用 Docker 容器 nodes 运行本地 Kubernetes 集群的工具。 kind 主要是为了测试 Kubernetes 自身而设计的,但它也可用于本地开发或 CI。
Kind是Kubernetes In Docker的缩写,顾名思义,看起来是把k8s放到docker的意思。没错,kind创建k8s集群的基本原理就是:提前准备好k8s节点的镜像,通过docker启动容器,来模拟k8s的节点,从而组成完整的k8s集群。需要注意,kind创建的集群仅可用于开发、学习、测试等,不能用于生产环境。
使用Kind搭建Kubernetes环境
可以在Github上查看到Kind的发布记录:https://github.com/kubernetes-sigs/kind/releases
在其中可以找到不同版本对应的Node镜像。
前置准备工作
代理加速:
- 镜像加速:https://github.com/DaoCloud/public-image-mirror
- 二进制文件加速:https://github.com/DaoCloud/public-binary-files-mirror
- Helm 加速:https://github.com/DaoCloud/public-helm-charts-mirror
先docker 拉取该源,并修改tag:
sudo docker pull m.daocloud.io/docker.io/kindest/node:v1.34.0sudo docker tag m.daocloud.io/docker.io/kindest/node:v1.34.0 docker.io/kindest/node:v1.34.0sudo docker rmi m.daocloud.io/docker.io/kindest/node:v1.34.0查看结果:
$ sudo docker image lsREPOSITORY TAG IMAGE ID CREATED SIZEkindest/node v1.34.0 4357c93ef232 2 weeks ago 985MB单节点kind集群
sudo kind create cluster --name huari-test --image kindest/node:v1.34.0 --retain; sudo kind export logs --name huari-test参数解释:
- –image可以执行指定不同版本的镜像
- –name可以指定集群名
查看通过kind创建的集群:
sudo kind get clustershuari-test根据提示切换kubectl上下文集群:这在涉及到多集群时很实用
sudo kubectl cluster-info --context kind-huari-test查看信息:
# 查看集群节点sudo kubectl get nodes
# 查看集群全部的podsudo kubectl get pods -A -owide删除集群:
sudo kind delete cluster --name huari-test搭建一主二从Kind集群
创建一个 huari.yaml 的文件,内容如下:
kind: Cluster# 一共三个节点,一个主节点,两个从节点apiVersion: kind.x-k8s.io/v1alpha4nodes:- role: control-plane # 主节点- role: worker # 从节点- role: worker # 从节点创建集群命令:
sudo kind create cluster --config=huari.yaml --name huari-test --image kindest/node:v1.34.0 --retain; sudo kind export logs --name huari-test切换kubectl上下文:
sudo kubectl cluster-info --context kind-huari-test查看信息:
# 查看集群节点sudo kubectl get nodes
# 查看集群全部的podsudo kubectl get pods -A -owide删除集群:
sudo kind delete cluster --name huari-test搭建三主三从高可用kind集群
创建一个 huari.yaml 的文件,一共六个节点,三个 control-plane 节点,三个 workers 节点,内容如下:
kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes:- role: control-plane- role: control-plane- role: control-plane- role: worker- role: worker- role: worker创建高可用集群命令:
sudo kind create cluster --config=huari.yaml --name huari-test --image kindest/node:v1.34.0 --retain; sudo kind export logs --name huari-test高可用集群时需要手动处理下镜像:
sudo docker pull m.daocloud.io/docker.io/kindest/haproxy:v20230606-42a2262bsudo docker tag m.daocloud.io/docker.io/kindest/haproxy:v20230606-42a2262b docker.io/kindest/haproxy:v20230606-42a2262bsudo docker rmi m.daocloud.io/docker.io/kindest/haproxy:v20230606-42a2262b切换kubectl上下文:
sudo kubectl cluster-info --context kind-huari-test查看信息:
# 查看集群节点sudo kubectl get nodes
# 查看集群全部的podsudo kubectl get pods -A -owide删除集群:
sudo kind delete cluster --name huari-test问题解决
问题描述
在搭建三主三从高可用kind集群时遇见异常问题。
配置:
kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes:- role: control-plane- role: control-plane- role: control-plane- role: worker- role: worker- role: worker异常:
I0916 14:07:31.164509 282 etcd.go:593] [etcd] Promoting the learner a4010febcb7ad87f failed: etcdserver: can only promote a learner member which is in sync with leader{"level":"warn","ts":"2025-09-16T14:07:31.664361Z","logger":"etcd-client","caller":"v3@v3.6.4/retry_interceptor.go:65","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc0007a43c0/172.18.0.7:2379","method":"/etcdserverpb.Cluster/MemberPromote","attempt":0,"error":"rpc error: code = FailedPrecondition desc = etcdserver: can only promote a learner member which is in sync with leader"}I0916 14:07:31.664483 282 etcd.go:593] [etcd] Promoting the learner a4010febcb7ad87f failed: etcdserver: can only promote a learner member which is in sync with leadererror: error execution phase etcd-join: error creating local etcd static pod manifest file: etcdserver: can only promote a learner member which is in sync with leader在ubuntu平台上之前就遇见过这个问题,而且改成两个master节点就可以,但是mac上就可以。
修改成两个master节点时,虽然集群可以启动,但是节点状态有问题:
$ sudo kubectl get nodesNAME STATUS ROLES AGE VERSIONhuari-test-control-plane Ready control-plane 5m54s v1.34.0huari-test-control-plane2 Ready control-plane 5m22s v1.34.0huari-test-worker2 Ready <none> 5m21s v1.34.0worker节点huari-test-worker和huari-test-worker3没有展示出来,但实际容器存在:
$ sudo docker ps | grep huari-test1fcd57452e8c kindest/node:v1.34.0 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes huari-test-worker2f8e8f598552c kindest/node:v1.34.0 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes huari-test-worker3a6e6a569f86c kindest/haproxy:v20230606-42a2262b "haproxy -W -db -f /…" 4 minutes ago Up 4 minutes 127.0.0.1:33377->6443/tcp huari-test-external-load-balancer80b12fa4d035 kindest/node:v1.34.0 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes 127.0.0.1:43807->6443/tcp huari-test-control-planec71b91c9a29b kindest/node:v1.34.0 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes huari-test-worker8bcd6dfd6c8a kindest/node:v1.34.0 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes 127.0.0.1:33187->6443/tcp huari-test-control-plane2容器内错误日志:
$ sudo docker exec -it huari-test-worker bashroot@huari-test-worker:/# systemctl status kubeletSep 16 14:15:56 huari-test-worker kubelet[8366]: E0916 14:15:56.561227 8366 manager.go:294] Registration of the raw container factory failed: inotify_init: too many open filesSep 16 14:15:56 huari-test-worker kubelet[8366]: E0916 14:15:56.561242 8366 kubelet.go:1686] "Failed to start cAdvisor" err="inotify_init: too many open files"Sep 16 14:15:56 huari-test-worker systemd[1]: kubelet.service: Main process exited, code=exited, status=1/FAILURESep 16 14:15:56 huari-test-worker systemd[1]: kubelet.service: Failed with result 'exit-code'.临时解决:
sudo sysctl fs.inotify.max_user_instances=8192sudo sysctl fs.inotify.max_user_watches=524288sudo docker restart huari-test-worker huari-test-worker3永久解决:
echo fs.inotify.max_user_instances=8192 | sudo tee -a /etc/sysctl.confecho fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.confsudo sysctl -p验证
一切恢复正常:
$ sudo kubectl get nodesNAME STATUS ROLES AGE VERSIONhuari-test-control-plane Ready control-plane 14m v1.34.0huari-test-control-plane2 Ready control-plane 13m v1.34.0huari-test-worker Ready <none> 6m55s v1.34.0huari-test-worker2 Ready <none> 13m v1.34.0huari-test-worker3 Ready <none> 6m55s v1.34.0并且重新尝试创建三主三从kind节点也可以正常启动:
$ sudo kubectl get nodesNAME STATUS ROLES AGE VERSIONhuari-test-control-plane Ready control-plane 81s v1.34.0huari-test-control-plane2 Ready control-plane 56s v1.34.0huari-test-control-plane3 Ready control-plane 33s v1.34.0huari-test-worker Ready <none> 32s v1.34.0huari-test-worker2 Ready <none> 32s v1.34.0huari-test-worker3 Ready <none> 32s v1.34.0参数解释:
- fs.inotify.max_user_instances:每个用户最多可以创建多少个 inotify 实例(比如 kubelet、Docker、VSCode 各算一个)
- fs.inotify.max_user_watches:每个用户最多可以“盯”多少个文件/目录的变化(每个实例可以盯很多文件)
上面问题的最终本质,kubelet 要监听下面的文件:
/var/lib/kubelet/pods//etc/kubernetes/manifests//var/lib/containerd/
如果盯的文件数超过上限,就会:inotify_init: too many open files,然后崩溃重启,节点就无法注册到集群。
导出kind集群kubeconfig
导出命令:
sudo kind export kubeconfig --name=huari-test --kubeconfig=$HOME/.kube/config用法进阶
我们已经搭建了各种类型的集群,但是我们该怎么访问集群呢?
以前在使用docker时,如果需要访问docker内部署的服务,通常需要以端口映射的方式,将宿主机指定端口的流量,转发进docker的指定端口,既然kind集群是利用docker部署的node,那是不是通过端口映射就可以实现访问集群了呢?
如果我们需要部署服务时,怎么去拉取image呢,这里是要在container里部署container,所以镜像是存储在第一层container(node节点)里的,那么怎么将image导入呢?
端口映射
设想一种场景:在Kind集群中运行一个Nginx容器服务,监听80端口对外暴露,这时在另一台机器上能不能访问Kind集群所在机器的80端口,进而访问这个Nginx服务呢?
其实不行,因为Kind集群是Docker内运行的,所以Kine集群内Nginx容器的80端口和Kine集群所在的宿主机的80端口并不在同一个网络命名空间。
我们可以通过如下方式来配置端口映射,从而解决这类问题。
在配置文件中增加extraPortMappings配置项:
kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4nodes:- role: control-plane extraPortMappings: - containerPort: 80 hostPort: 80 listenAddress: "0.0.0.0" protocol: tcp- role: control-plane- role: control-plane- role: control-plane- role: worker- role: worker- role: worker这样,搭建出来的Kubernetes集群中使用NodePort暴露80端口或者使用hostNetwork方式暴露80端口的Pod就可以通过主机的80端口来访问了。
注意,这里仅配置了一个control-plane,其他的进行配置时,要注意端口不能冲突,即每一个node进行端口映射时,hostPort不能冲突。
创建高可用集群命令:
sudo kind create cluster --config=huari.yaml --name huari-test --image kindest/node:v1.34.0 --retain; sudo kind export logs --name huari-test切换kubectl上下文:
sudo kubectl cluster-info --context kind-huari-test查看信息:
# 查看集群节点sudo kubectl get nodes
# 查看集群全部的podsudo kubectl get pods -A -owide删除集群:
sudo kind delete cluster --name huari-test暴露kube-apiserver
有时我们会在一台计算机上使用Kind搭建一套Kubernetes环境,在另一台机器上编写代码,这时会发现我们无法连接到Kind集群中的kube-apiserver来调试Operator程序。
其实这是因为默认配置下kube-apiserver监听127.0.0.1和随机端口,要从外部访问就需要把kube-apiserver监听的网卡改成非lo(代表127.0.0.1,即localhost)的对外网卡,比如eth0。
同样,我们通过配置文件自定义来实现这一需求,添加networking.apiServerAddress配置项,值是本地网卡IP(可根据实际情况修改):
kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4networking: apiServerAddress: "10.10.151.201"nodes:- role: control-plane extraPortMappings: - containerPort: 6443 hostPort: 6443 listenAddress: "10.10.151.201" protocol: tcp- role: control-plane- role: control-plane- role: worker- role: worker- role: worker创建高可用集群命令:
sudo kind create cluster --config=huari.yaml --name huari-test --image kindest/node:v1.34.0 --retain; sudo kind export logs --name huari-test切换kubectl上下文:
sudo kubectl cluster-info --context kind-huari-test查看信息:
# 查看集群节点sudo kubectl get nodes
# 查看集群全部的podsudo kubectl get pods -A -owide删除集群:
sudo kind delete cluster --name huari-test安装ingress
kind 官方推荐用 ingress-nginx 的“裸机”版(DaemonSet + hostNetwork),直接让 Controller 占用宿主机 80/443,无需云 LB,最适合本地/物理机场景。
安装ingress:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml等待 Controller 就绪:
kubectl -n ingress-nginx wait --for=condition=ready pod -l app.kubernetes.io/component=controller --timeout=90s确认宿主机 80/443 已被监听
$ sudo netstat -tulnp | grep -E ':80|:443'tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 275756/docker-proxy导入镜像
通过Kind搭建的环境本质是运行在一个容器内,宿主机上的镜像默认不能被Kind环境所识别,这时可以通过如下方式导入镜像:
# 例如一个镜像名是my-testimage:v1kind load docker-image my-testimage:v1 --name huari-test
# 例如需要的镜像是一个tar包,my-testimage.tarkind load image-archive my-testimage.tar --name huari-test实战
集群搭建
kind: ClusterapiVersion: kind.x-k8s.io/v1alpha4networking: apiServerAddress: "10.10.151.201"nodes:- role: control-plane extraPortMappings: - containerPort: 6443 hostPort: 6443 listenAddress: "10.10.151.201" protocol: tcp- role: control-plane- role: control-plane- role: worker extraPortMappings: - containerPort: 80 hostPort: 7080 listenAddress: "0.0.0.0" protocol: tcp - containerPort: 443 hostPort: 7443 listenAddress: "0.0.0.0" protocol: tcp- role: worker extraPortMappings: - containerPort: 80 hostPort: 8080 listenAddress: "0.0.0.0" protocol: tcp - containerPort: 443 hostPort: 8443 listenAddress: "0.0.0.0" protocol: tcp- role: worker extraPortMappings: - containerPort: 80 hostPort: 9080 listenAddress: "0.0.0.0" protocol: tcp - containerPort: 443 hostPort: 9443 listenAddress: "0.0.0.0" protocol: tcp创建高可用集群命令:
sudo kind create cluster --config=huari.yaml --name huari-test --image kindest/node:v1.34.0 --retain; sudo kind export logs --name huari-test切换kubectl上下文:
sudo kubectl cluster-info --context kind-huari-test查看信息:
# 查看集群节点sudo kubectl get nodes
# 查看集群全部的podsudo kubectl get pods -A -owide删除集群:
sudo kind delete cluster --name huari-testIngress 安装
需要安装官方定制版本的ingress。
安装ingress:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml等待 Controller 就绪:
kubectl -n ingress-nginx wait --for=condition=ready pod -l app.kubernetes.io/component=controller --timeout=90s确认宿主机 80/443 已被监听
$ sudo netstat -tulnp | grep -E ':80|:443'tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 275756/docker-proxy测试目标
主要有两个测试点:
- API Server:验证外部能否访问 Kubernetes API(https://10.10.151.201:6443)
- 80 端口:验证容器 80 端口是否穿透到宿主机(http://10.10.151.201:80)
确认监听地址
# 看宿主机是否在 10.10.151.201:6443 和 80 监听$ sudo netstat -tulnp | grep -E ':6443|:80'tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 244210/docker-proxytcp 0 0 10.10.151.201:6443 0.0.0.0:* LISTEN 244220/docker-proxy测试 API Server 外部访问
$ curl -k https://10.10.151.201:6443/livezok测试 80 端口(部署一个简单服务)
查看 Controller 落在哪个节点:
$ sudo kubectl -n ingress-nginx get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESingress-nginx-controller-6869595b64-f8tj7 1/1 Running 0 7m6s 10.244.5.3 huari-test-worker <none> <none>现在controller落在huari-test-worker这个节点上,那么宿主机 7080/7443 就会被 nginx-ingress-controller 监听。
创建nginx-80.yaml文件,并将下面的配置写入:强制调度到该映射了80端口的节点
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: nginx annotations: nginx.ingress.kubernetes.io/rewrite-target: /spec: ingressClassName: nginx rules: - host: nginx.local # 可改任意域名 http: paths: - path: / pathType: Prefix backend: service: name: nginx port: number: 80---apiVersion: v1kind: Servicemetadata: name: nginxspec: selector: app: nginx ports: - port: 80 targetPort: 80---apiVersion: apps/v1kind: Deploymentmetadata: name: nginxspec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: m.daocloud.io/docker.io/nginx:alpine ports: - containerPort: 80部署:
$ sudo kubectl apply -f nginx-80.yamldeployment.apps/nginx createdservice/nginx created从外部访问测试:
curl -H "Host: nginx.local" http://10.10.151.201:7080应该返回:
<!DOCTYPE html><html><head><title>Welcome to nginx!</title><style>html { color-scheme: light dark; }body { width: 35em; margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif; }</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.</p>
<p>For online documentation and support please refer to<a href="http://nginx.org/">nginx.org</a>.<br/>Commercial support is available at<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p></body></html>部分信息可能已经过时









