外观
第二节 kind 多节点模拟集群规划与创建
约 3966 字大约 13 分钟
Kuberneteskind集群规划YAML
2026-07-28
项目目标
规划并创建一套包含 1 个控制平面节点与 2 个工作节点的 kind 多节点 Kubernetes 集群,完成宿主机与集群节点间的端口映射设计。掌握国内 Docker 镜像加速器配置与代理镜像源查找技巧,深入学习 kind-config.yaml 详细配置语法与底层网络连通机制,并通过进入节点内部观察底层容器与删除重建试验,验证集群配置的可复现性。
2.1 拓扑规划:为什么必须使用多节点集群
在上一课中,我们确认了 Docker、kind 和 kubectl 工具链正常可用。如果直接运行不带任何配置参数的 kind create cluster,kind 默认会创建一个单节点(Single-node)集群。
单节点集群虽然启动迅速,但在学习 Kubernetes 核心能力时存在严重局限:
- 无法观察真正的 Pod 调度过程:
kube-scheduler没有任何挑选余地,所有工作负载只能堆叠在唯一的节点上。 - 无法体验节点故障与驱逐机制:当某个工作节点发生故障或进入维护状态(
cordon/drain)时,无法观察 Pod 如何被自动重调度到其他健康节点。 - 角色模糊:控制平面(Control Plane)的核心组件与普通业务 Pod 混跑在同一个容器中,无法建立清晰的集群架构边界。
为了在单机环境下真实模拟生产集群的角色分工,本课将规划并构建一套 1 控制平面 + 2 工作节点 的多节点拓扑架构。
| 拓扑规格 | 节点组成 | 适用学习场景 | 核心价值 |
|---|---|---|---|
| 标准多节点(本课采用) | 1 × control-plane 2 × worker | 跨节点调度、Pod 负载均衡、节点故障驱逐、维持服务可用性 | 完整展示 Kubernetes 多节点协同机制 |
| 基础双节点 | 1 × control-plane 1 × worker | 角色分离、基础调度观察 | 资源紧张时的备选方案 |
| 默认单节点 | 1 × control-plane | 极简 API 操作测试 | 无法完成多节点调度与驱逐实验 |
2.2 架构原理:kind 的 Node-in-Container 运行机制
2.2.1 kind 节点内部包含了什么
kind(Kubernetes in Docker)的核心理念是 “用 Docker 容器伪装成物理/虚拟机节点”(Node-in-Container)。
当你通过 kind 创建集群时:
- Docker Engine 会根据配置启动数个容器,每个容器拥有独立的网络命名空间(Network Namespace)、cgroup 和存储卷。
- 每个节点容器内部都运行着 containerd(作为节点级容器运行时)和 kubelet(作为节点 Agent)。
- 对于 控制平面容器(
control-plane),containerd 会进一步拉取并运行kube-apiserver、etcd、kube-scheduler和kube-controller-manager等的核心静态 Pod。 - 对于 工作节点容器(
worker),kubelet 负责接收控制平面的指令,并通过节点内部的 containerd 拉取并运行你部署的业务 Pod。
观察下面的交互面板,理解请求提交后,控制平面中的 Scheduler 如何决定将 Pod 分发至不同的 Worker 容器节点:
kind 多节点角色分发与 Pod 动态调度演示
观察控制平面如何接收请求、调度决策,并将 Pod 分发至不同的 Worker 容器节点。
1 / 5
💻宿主机 Docker Engine 边界(Docker Bridge: 172.18.0.0/16)
Control Planeyunfan-control-plane
⚡ API Server
🎯 Scheduler
💾 etcd
⚙️ Controller Manager
Worker 节点 1yunfan-worker
kubelet + containerd
等待调度任务...
Worker 节点 2yunfan-worker2
kubelet + containerd
等待调度任务...
2.3 网络设计:三层网络与端口映射穿透路径
2.3.1 区分 Kubernetes 中的三层网络
kind 集群内部存在三层相互隔离的网络空间,必须清晰区分它们的范围与职责:
| 地址空间 | 作用域 | 地址范围示例 | 说明与注意事项 |
|---|---|---|---|
| Docker Bridge 网络 | 宿主机 ↔ kind 节点容器 | 172.18.0.0/16 | 由 Docker 自动分配,保证宿主机能与节点容器通信,节点容器间相互连通 |
| Pod CIDR (网段) | 集群内部 Pod 间通信 | 10.244.0.0/16 | 由 CNI 插件分配,Pod 在集群内拥有唯一 IP,但无法直接从宿主机访问 |
| Service CIDR (虚拟网段) | 集群内 Service 负载均衡 | 10.96.0.0/16 | Kubernetes 虚拟 IP 地址,仅在集群内部通过 iptables/IPVS 转发有效 |
2.3.2 宿主机到集群内部的端口穿透链
由于 Pod IP(10.244.x.x)处于容器内部网络,宿主机外部(如电脑上的浏览器)默认无法直接访问它。
在 kind 配置中,我们需要通过 extraPortMappings 声明端口转发规则,将宿主机的端口映射到控制平面节点容器中,为后续的 NodePort Service 暴露访问入口:
[宿主机浏览器] http://127.0.0.1:18080
│ (宿主机端口)
▼
[Docker 端口映射] extraPortMappings
│ (节点容器端口 30080/TCP)
▼
[kind 节点容器] yunfan-control-plane:30080
│ (NodePort Service 路由)
▼
[Pod 容器] 10.244.1.5:80 (业务响应)观察下面的端口穿透与数据包流向动画,理解数据包如何从宿主机一步步到达 Pod:
宿主机端口至集群内 Pod 网络穿透链路演示
观察数据包如何从本机的 18080 端口,一步步穿透 Docker 映射与 Kubernetes 网络层到达 Pod。
1 / 5
Hop 1包到达
1. 宿主机发包
127.0.0.1:18080Host OS Network
▶
Hop 2
2. Docker 端口映射
extraPortMappingsDocker Bridge
▶
Hop 3
3. 节点容器入口
yunfan-control-plane:30080Node Container (eth0)
▶
Hop 4
4. Service 路由
Service IP: 10.96.x.xVirtual IP Layer
▶
Hop 5
5. 送达目标 Pod
Pod IP: 10.244.1.5:80Pod Namespace (veth)
2.4 配置编写:声明式 kind-config.yaml 详细语法
在项目根目录下,直接创建集群配置文件 kind-config.yaml。我们将节点角色、网段规划与端口映射统一写入声明式 YAML 文件中。
2.4.1 配置文件的完整结构
在 Kubernetes 中,声明式配置能够保证环境的可复现性。以下是包含 1 控制平面和 2 工作节点的标准多节点配置:
kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: yunfan
networking:
ipFamily: ipv4
podSubnet: "10.244.0.0/16"
serviceSubnet: "10.96.0.0/16"
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30080
hostPort: 18080
listenAddress: "127.0.0.1"
protocol: TCP
- role: worker
- role: worker2.4.2 kind-config.yaml 各配置项语法与作用详解
| 配置层级 / 字段 | 数据类型 | 必需 | 示例 / 默认值 | 详细作用与底层原理解释 |
|---|---|---|---|---|
kind | 字符串 | 是 | Cluster | 标识配置文件的顶层资源类型,指示 kind CLI 解析该 YAML 为一个集群创建配置文件。 |
apiVersion | 字符串 | 是 | kind.x-k8s.io/v1alpha4 | 指定 kind 配置 API 的版本,决定后续字段的合法性校验规则。 |
name | 字符串 | 是 | yunfan | 指定新建集群的唯一标识名。创建后 Docker 容器名将带有 yunfan- 前缀,kubectl context 命名为 kind-yunfan。 |
networking | 对象 | 否 | - | 集群网络架构配置块。包含 Pod 和 Service 网段分配规则。 |
networking.podSubnet | CIDR 字符串 | 否 | 10.244.0.0/16 | 指定 CNI 插件为所有 Pod 分配 IP 时的地址池范围。需注意不能与宿主机本地 VPN 或物理网段冲突。 |
networking.serviceSubnet | CIDR 字符串 | 否 | 10.96.0.0/16 | 指定 Kubernetes 集群内部虚拟 Service IP (ClusterIP) 的分配池范围。 |
nodes | 数组列表 | 是 | - | 声明要创建的 kind 节点容器列表。每一个列表项对应 Docker Engine 中的一个容器实例。 |
nodes[].role | 枚举字符串 | 是 | control-plane / worker | 定义节点的集群角色。control-plane 会启动 API Server 和 etcd,worker 仅启动基础运行环境。 |
extraPortMappings | 数组列表 | 否 | - | 端口映射规则列表(类似于 docker run -p)。仅在控制平面或目标节点生效。 |
containerPort | 整数 (Port) | 是 | 30080 | 节点容器内部监听的端口号。后续第 8 课 NodePort Service 的 nodePort 需与此端口完全匹配。 |
hostPort | 整数 (Port) | 是 | 18080 | 宿主机本地物理机暴露的端口号。宿主机用户将通过 127.0.0.1:18080 进行网络访问。 |
listenAddress | IP 字符串 | 否 | 127.0.0.1 | 宿主机端口绑定的 IP 地址。显式指定为 127.0.0.1 可提高开发环境安全性,防止暴露给公网或局域网。 |
protocol | 枚举字符串 | 否 | TCP / UDP | 传输层网络协议,默认为 TCP。 |
2.5 集群创建与国内网络镜像加速实战
2.5.1 配置 Docker 镜像加速器与寻找国内源
在创建 kind 集群时,kind 需要拉取完整的 Kubernetes 节点镜像(如 kindest/node:v1.35.0,体积约 1.2GB)。因网络环境限制,直接拉取常导致超时。
方法一:配置 Docker Engine 镜像加速器
在 Docker 配置文件 daemon.json 中配置国内加速镜像站列表:
1. 修改配置文件:
- Docker Desktop (macOS / Windows): 打开 Docker 界面 ⚙️ Settings -> Docker Engine,在 JSON 配置中补充
"registry-mirrors"项。 - Linux 物理机/虚拟机: 修改
/etc/docker/daemon.json:
{
"registry-mirrors": [
"https://docker.anyhub.us.kg",
"https://dockerhub.icu",
"https://docker.m.daocloud.io"
]
}2. 重启 Docker 服务:
- Docker Desktop: 点击界面右下角的 Apply & restart。
- Linux: 执行
sudo systemctl daemon-reload && sudo systemctl restart docker。
3. 在宿主机上执行拉取: 配置生效后,直接运行标准拉取命令,加速器会自动拦截并加速下载:
docker pull kindest/node:v1.35.0方法二:查找并拉取代理镜像重命名 (推荐)
如果无法更改全局镜像加速器,可以通过国内镜像代理站手动拉取并转换 Tag。
如何查找镜像对应的国内源地址? kind 默认节点镜像官方全名为 docker.io/kindest/node:v1.35.0。国内代理站(如 DaoCloud 镜像代理 m.daocloud.io 或 华为云镜像代理 swr.cn-north-4.myhuaweicloud.com)的通用映射规则为:代理域名 / 官方全名。
为什么必须使用 docker tag 重新命名? 第三方代理拉取后,镜像在本地镜像库中的名称带有代理前缀(m.daocloud.io/docker.io/kindest/node:v1.35.0)。而 kind 在创建集群时,默认只寻找标准名字 kindest/node:v1.35.0。如果直接拉取而不重命名,kind 将无法识别本地已有镜像,依然会尝试连接国外源。通过 docker tag 建立标准别名,才能保证 kind 直接精准调用本地镜像。
在终端中依次执行以下命令:
# 1. 使用国内代理前缀拉取节点镜像
docker pull m.daocloud.io/docker.io/kindest/node:v1.35.0
# 2. 将镜像重新打标签 (tag) 还原为 kind 认可的标准名称
docker tag m.daocloud.io/docker.io/kindest/node:v1.35.0 kindest/node:v1.35.02.5.2 执行集群创建命令
在终端中执行以下命令,使用 kind-config.yaml 配置文件启动多节点集群:
kind create cluster --config kind-config.yaml --image kindest/node:v1.35.0 --wait 5m命令参数逐项解析:
kind create cluster: kind 创建集群的基础子命令。--config kind-config.yaml: 指定刚才编写的 YAML 配置文件路径。--image kindest/node:v1.35.0: 明确指定 Kubernetes 节点镜像版本。如果刚才已拉取并重命名镜像,kind 会直接使用本地镜像而无需再次联网。--wait 5m: 设定最高等待超时时间为 5 分钟。若控制平面组件在此时间内未就绪,命令会自动终止并报错。
2.6 操作与探秘:从双层视角验证集群
集群创建成功后,我们需要分别从 Docker 视角 和 Kubernetes 视角 验证节点运行状态,并深入控制平面内部查看运行组件。
核对 Docker Engine 内部运行的节点容器
运行以下命令,查看 Docker 正在运行的容器:
docker ps --filter name=yunfan --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"预期输出: 你应该能看到 3 个容器,其中
yunfan-control-plane容器的 Ports 列显式映射了127.0.0.1:18080->30080/tcp。验证 kubectl 集群节点状态
运行以下命令,查看 Kubernetes 认可的节点列表及其角色:
kubectl get nodes -o wide预期输出:
NAME STATUS ROLES AGE VERSION INTERNAL-IP OS-IMAGE yunfan-control-plane Ready control-plane 2m v1.35.0 172.18.0.2 Debian GNU/Linux 12 yunfan-worker Ready <none> 2m v1.35.0 172.18.0.3 Debian GNU/Linux 12 yunfan-worker2 Ready <none> 2m v1.35.0 172.18.0.4 Debian GNU/Linux 12探秘节点内部:使用
crictl观察控制平面原生 Pod进入
yunfan-control-plane节点容器内部,直接调用节点容器运行时的客户端crictl:docker exec -it yunfan-control-plane crictl ps原理说明与预期观察: 该命令直接打入了 Docker 容器内部。你会发现节点容器内部正在运行着
kube-apiserver、kube-scheduler、etcd和kindnet等系统级容器!这直接印证了 Node-in-Container 的机制。
2.7 演练与验证:删除集群并按配置一键重建
为了证明你的 kind-config.yaml 具备可复现的声明式基础设施能力,我们将执行一次删除与重建演练。
2.7.1 删除集群
执行以下命令彻底销毁当前集群:
# 删除名称为 yunfan 的 kind 集群
kind delete cluster --name yunfan删后检查:
# 确认集群名已被注销,节点容器已被销毁
kind get clusters
docker ps --filter name=yunfan2.7.2 一键重建集群
使用保存好的 kind-config.yaml 重新创建集群:
kind create cluster --config kind-config.yaml --image kindest/node:v1.35.0 --wait 5m创建完成后再次运行验证:
kubectl config current-context
kubectl get nodes成功标准:
- 节点快速重建完成,状态全部恢复为
Ready; - 无需手动重新配置网络或端口,声明式配置自动复原了 1 控制平面 + 2 工作节点的完整拓扑。
2.8 实验交付物与排错速查
2.8.1 本课提交成果清单
完成本课实训后,提交以下三项成果即可:
- 配置文件:项目根目录下的
kind-config.yaml。 - 第一张截图
02-create-nodes.png:同一终端画面中包含docker ps --filter name=yunfan与kubectl get nodes -o wide的执行结果。 - 第二张截图
02-crictl-explore.png:运行docker exec -it yunfan-control-plane crictl ps成功展示控制平面内部容器的终端画面。
2.8.2 常见错误与排错矩阵
| 故障现象 | 可能原因 | 修复排查路径 |
|---|---|---|
yaml: line ... error | YAML 缩进格式错误(使用了 Tab 或层级错乱) | 检查缩进,确保使用纯空格,核对 nodes 与 extraPortMappings 层级 |
address already in use | 本机 18080 端口已被其他程序占用 | 使用 lsof -i :18080 (macOS/Linux) 或 Get-NetTCPConnection (Win) 找出占用进程或更换 hostPort |
kind create 卡在等待节点响应 | 镜像拉取缓慢或 Docker 资源不足 | 使用 docker pull / docker tag 先行拉取镜像;检查 Docker 内存限制是否 ≥ 4GB |
kubectl 无法连接到 API Server | 当前 context 切换到了其他集群 | 运行 kubectl config use-context kind-yunfan 修正目标集群上下文 |
挑战任务:探索控制平面的静态 Pod 清单
运行 docker exec -it yunfan-control-plane bash 进入控制平面节点容器,查看 /etc/kubernetes/manifests/ 目录下的配置文件。这里的 YAML 文件是节点 kubelet 用来自动加载并启动 kube-apiserver、etcd 等核心组件的静态 Pod 清单(Static Pod)。你可以尝试打开其中一个文件,观察 Kubernetes 最核心的控制平面组件是如何通过声明式配置定义的。
本章小测
本章小结
完成本课后,你已经掌握了:
- 单节点与多节点拓扑的本质区别:理解了多节点是观察跨节点调度与故障驱逐的物理基础。
- kind 的 Node-in-Container 底层架构:掌握了 Docker 容器如何作为 Kubernetes 节点,以及节点内部 containerd 和 kubelet 的协作模式。
- 三层网络与端口映射:理清了宿主机端口 ↔ 节点容器端口 ↔ Service ↔ Pod IP 的数据包传递链路。
kind-config.yaml详细配置语法:掌握了声明式kind配置文件中networking、nodes以及extraPortMappings的各项参数含义与底层作用。- 镜像加速与国内源查找实战:掌握了 Docker daemon 镜像加速配置规则与代理源名称转换逻辑。
- 镜像预载与集群快速重建:掌握了本地预载节点镜像的方法,并通过进入节点内部探秘和删除重建,验证了基础设施的可复现性。
下一课中,我们将深入探究 Kubernetes 控制平面的调度决策机制、CNI 网络连通性测试以及工作节点的封锁(cordon)与驱逐(drain)实战!
