文档看了三个星期,真正动手是在一台装了 VMware Workstation 的普通电脑上。以前用单机工具把 Kubernetes 的 Pod、Service、Deployment 都玩了一遍,以为掌握了,直到需要观察一次滚动更新如何把 Pod 调度到不同节点、一个节点宕了业务会不会自动迁移时,单机工具全都回答不了。
后来搭了一套基于 VMware 虚拟机的三节点 Kubernetes 1.29.14 集群,一台主机做控制面,两个工作节点,才第一次感受到“集群”和“单机模拟”之间的真实差距。这篇文章不打算复述安装文档,而是想把这套环境从资源规划、母版准备、初始化控制面、节点加入、再到验证排查的完整过程讲清楚,包括那些文档不会告诉你的坑。这套方案真正的价值,不是在一台电脑上多跑一个 K8s,而是用一个离生产环境更近的形态,逼你去面对单机实验永远碰不到的工程问题。
1. 先搞清楚:为什么是 VMware 虚拟机里的三节点,而不是单机玩一玩
很多人学 Kubernetes 的第一站是桌面端工具,比如用单二进制方式启动一个本地集群,或者用 minikube 起一个虚拟机。它们确实把上手门槛压得很低,十几分钟就能跑起第一个 Pod。但用到一定阶段,你会明显发现这些工具回答不了几个关键问题。
1.1 单节点工具和真正的集群差在哪里
单节点实验环境的问题不在于小,而在于它把集群最核心的复杂性隐藏了。集群不是多个数字空间的简单叠加,而是调度、网络、存储、故障域之间的协同。
第一个差异是调度。单节点上 Pod 永远只会调度到那一个节点,你根本看不到 NodeAffinity、资源请求与节点压力、污点容忍这些机制如何在工作。第二个差异是网络。跨节点通信才是集群的默认假设,Pod 在不同节点上怎么拿到同一个虚拟网络地址,Service 又是怎么把流量转发到多台机器上的 Pod,这只有在多节点环境里才会真正暴露出来。第三个差异是故障。节点宕机后工作负载如何被控制面重新拉起,这个过程需要 kubelet、控制器管理器、etcd 等多个组件协同工作,单节点上没机会触发,自然也没机会理解。
还有一个容易被忽略的区别:单机工具大多把组件弱化成了黑盒,而三节点虚拟机里,每台机器上的 kubelet、容器运行时、网络插件都是标准 Linux 进程,你可以通过日志、系统服务、端口监听去排查它们。这种“能拆开看”的透明性,对学习价值非常大。
1.2 三节点是最小可信集群
为什么是三台,不是两台,更不是一台?在资源有限的前提下,三节点能覆盖最常见的集群工作场景:一个控制面负责调度和状态管理,两个工作节点可以承载多副本应用,也才能体现滚动更新、跨节点调度、故障驱逐等行为。
如果只有两个节点,控制面和工作节点混在一起,或者只有一个 worker,很多调度行为都难以观察。三个节点,尤其是 1 个 master 加 2 个 worker 的组合,是低成本和真实感之间的平衡点。它不是一个生产级高可用集群,因为控制面只有一台,存在单点,但作为学习和开发环境,它就是最接近生产形态的最小单元。
我经常听到一个说法:等我把三节点玩熟练了,再换到实体服务器上完全没问题。这个想法大体成立,但要注意边界。虚拟机里能练到的运维操作,和裸金属上的网络配置、内核调优、硬件异常处理,仍然有本质差距。三节点环境的价值在于把 Kubernetes 本身的通用机制练熟,而不是把硬件层问题也一起覆盖。
1.3 这个方案适合谁,不适合谁
适合这套环境的典型场景包括:没有自己物理服务器的人;想系统性学习 K8s 调度、网络、存储机制的人;需要复现某个生产问题的开发或运维同学;想在公司内部快速搭建一套不依赖云厂商的联调环境。
不太适合的场景也比较明确:对性能极其敏感的应用压测;大规模并发验证;需要测试 GPU、SR-IOV 等特殊硬件能力的场景;以及刚上手一小时就想得到零维护体验的人。虚拟机方案天然带有虚拟化层开销,并且在嵌套虚拟化场景下性能还会进一步下降,这一点需要有心理准备。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 资源规划比安装命令更值得花时间
多数人搭集群,上手就是复制安装命令,结果后面遇到节点反复 NotReady,才开始回头查资源、查网络。我更建议先把资源规划和网络模型想清楚,这一步会决定后面所有操作是否顺畅。
2.1 宿主机与虚拟机的资源估算
在这个方案里,资源紧张导致的失败通常不是立刻报错,而是 K8s 集群能装完,但 Pod 一直在 Pending 状态,节点状态反反复复,kubelet 频繁被杀或者 OOM。所以一开始就要给每个节点留够空间。
常见的三节点分配方案如下:
| 角色 | CPU | 内存 | 磁盘 | 主要职责 |
|---|---|---|---|---|
| 控制面节点 | 2 核 | 2 GB | 20 GB 以上 | kube-apiserver、etcd、kube-controller-manager、kube-scheduler |
| 工作节点 1 | 2 核 | 2 GB | 20 GB 以上 | 运行业务 Pod |
| 工作节点 2 | 2 核 | 2 GB | 20 GB 以上 | 运行业务 Pod |
如果宿主机内存只有 8 GB,三台 2 GB 的虚拟机加上 VMware 自身开销,会比较紧张,建议至少 16 GB 内存。CPU 方面,只要不是老旧的低功耗处理器,三台双核虚拟机问题不大。磁盘建议用 SSD,因为三台虚拟机会同时读写系统日志、镜像层和工作负载数据,机械盘会在拉取镜像和启动容器时成为明显瓶颈。
还要考虑一个容易被忽略的资源:镜像存储。Kubernetes 集群跑起来后,每个节点都要缓存 pause、coredns、网络插件、业务镜像,长期使用后磁盘会逐渐增长,所以磁盘预分配宁可大一点,也不要卡着 20 GB 的最小值。
2.2 网络模式选择:NAT、桥接还是仅主机
VMware 虚拟机的网络模式直接决定三台节点如何互通,也决定你宿主机怎么访问集群。三种模式各有取舍。
| 网络模式 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| NAT | 虚拟机之间互通,宿主机可访问,IP 固定 | 外部局域网设备默认不能直接访问虚拟机 | 个人电脑本地学习,最稳妥 |
| 桥接 | 虚拟机像局域网内独立主机,能被其他设备访问 | 依赖宿主机所处网络,IP 可能被 DHCP 变化影响 | 需要把集群服务暴露给同局域网其他机器 |
| 仅主机 | 完全隔离,只有宿主机和虚拟机互相访问 | 外部无法访问,需要额外配置路由才能上网 | 离线实验、完全隔离调试 |
我在本地学习时优先用 NAT。原因是宿主机网络一变化,比如从家里换到公司,桥接模式下虚拟机 IP 可能重新分配,而 NAT 模式通常保持稳定。三节点的内部通信,只需要虚拟交换机,不需要真的成为局域网里可以被外部发现的主机。
具体网段不固定,不同 VMware 版本和不同电脑会不一样。关键是:三台虚拟机要选择同一个 NAT 网络,保证它们在同一个网段;控制面节点的 IP 要固定下来,因为后续 kubeadm join 的命令里、kubeconfig 里、甚至证书的 SAN 里都依赖它。你可以在 VMware 的虚拟网络编辑器中查看 NAT 网段的 IP 分配范围,再选择一个不会被 DHCP 抢占的固定地址。
2.3 集群内的命名与软性约定
除了硬件和网络,还要先约定好命名。主机名、IP、角色、时区、DNS 这些不统一,后期排查问题会非常痛苦。
习惯上我会这样分配:控制面节点叫 k8s-master,两个工作节点叫 k8s-worker1、k8s-worker2。每台机器编辑 /etc/hosts,把三台机器的 IP 和主机名对应关系写进去,这样 kubeadm 初始化时组件之间可以通过主机名互相访问,避免日志里到处是 IP 混淆。时区全部统一为同一时区,否则查看日志时间会对不上。DNS 不一致会导致拉取镜像、解析内部 Service 域名时出现奇怪的间歇性失败。
这一步看起来像“软配置”,但它在后续问题排查里经常是根因。比如有一个节点的时间比控制面偏差 30 秒,集群状态不会立刻报错,但证书校验、租约续期可能间歇性失败,这类问题极难定位。
3. 搭建一套可复现的集群:先做好“母版”,再克隆
搭建多节点环境,最忌讳的是逐台机器手工操作,因为三台机器只要有一点点系统配置不一致,后面就会东边报错西边排查。正确做法是先把一台虚拟机做成标准的“母版”,配置好所有基础依赖,然后克隆出三台节点。
3.1 为什么先做母版再克隆
母版思路在服务器集群里很常见,核心目的是消除环境漂移。三台节点需要高度一致的配置项包括:操作系统版本、内核模块和参数、容器运行时、kubeadm/kubelet/kubectl 版本、cgroup 驱动、hosts 文件基础结构、镜像源设置等。
如果一台一台手工装,某台机器少了一个内核参数、某个包的版本有差异、某台 containerd 配置里漏改了一行,问题会在初始化阶段爆发,而且在三台机器之间对比排查非常耗时。从母版克隆出来的三台机器,配置天然一致,后续只需要处理克隆带来的主机名、IP 和节点角色差异。
另外,母版还有一个隐藏价值:快照。完成母版配置后拍一个快照,之后无论在三台克隆机上怎么折腾,都能回到这个干净基础形态重新开始。这比每次手动卸载重装高效得多。
3.2 母版机器需要准备什么
母版系统建议选择 Ubuntu Server 或 Debian desktop 版本之外的轻量选择。个人推荐 Ubuntu Server,安装过程最小化,减少无关软件对集群环境的影响。
基础准备主要包括四个层次。
第一,系统层。关闭 swap,因为 Kubernetes 集群通常要求禁用交换分区,否则 kubelet 无法保持健康和资源模型的一致性。同时加载 overlay 和 br_netfilter 两个内核模块,并配置 net.bridge.bridge-nf-call-iptables 等转发参数。这些操作要在三台节点上都生效,所以做成母版配置最合适。
第二,运行时层。安装 containerd 并重新生成默认配置。Kubernetes 从 1.24 之后已经不再内置 dockershim,合理的选择是直接用 containerd 作为容器运行时。安装后要确认 containerd 的 cgroup 驱动和 kubelet 保持一致,通常都是 systemd。
第三,Kubernetes 组件层。安装 kubeadm、kubelet、kubectl,并且固定版本为 1.29.14。这一步要注意:不要顺手升级到最新版,而是锁住版本,否则 kubeadm 初始化的版本和控制面组件版本不一致会导致很多兼容问题。常见写法是安装时用类似 kubelet=1.29.14-* 这样的精确版本表达式。
第四,镜像源和网络配置。如果所在网络环境访问官方镜像仓库不稳定,需要提前把 kubeadm 的镜像仓库参数指到可达的镜像仓库,并且提前拉取初始化所需的镜像。这一步直接决定了后续 kubeadm init 会不会因为拉不到镜而中断。
下面是母版上常见的基础配置示例,适合 Ubuntu 系系统:
bash复制# 加载内核模块
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
# 设置内核转发参数
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
# 关闭 swap
sudo swapoff -a
注意:swapoff 只是临时生效,需要注释掉 /etc/fstab 里的 swap 相关行,否则重启后 swap 会重新打开,kubelet 报错会非常隐蔽。
3.3 克隆出三台节点后的“三查”
从母版克隆三台虚拟机之后,不是直接就能初始化集群,因为克隆行为会带来几个必然变化。
第一查网络。VMware 克隆后,新虚拟机的 MAC 地址和 IP 可能变化。需要手工把三个节点的 IP 固定下来,并更新 /etc/hosts。如果系统是 netplan 或 NetworkManager 管理网络,要检查网卡配置里有没有绑定旧 IP 或旧 MAC。
第二查主机名。克隆出来的机器可能都保留母版的主机名,如果不改,三台机器在集群里会相互冲突。需要分别执行 hostnamectl set-hostname k8s-master、k8s-worker1、k8s-worker2,并确认 /etc/hosts 的主机名映射与机器实际身份一致。
第三查系统唯一标识。部分组件会依赖机器 ID,克隆机如果出现重复的 machine-id,会影响某些服务校验。建议每台克隆机重新生成 machine-id,这是一个容易被忽略但真实存在的坑。
bash复制# 查看当前主机名和网络状态
hostnamectl
ip addr
# 修改主机名
sudo hostnamectl set-hostname k8s-worker1
# 重新生成 machine-id
sudo rm -f /etc/machine-id
sudo systemd-machine-id-setup
完成这一步后,可以分别对三台机器拍一个快照,这个快照就是“预初始化快照”。后面不管初始化成什么样,都能回到这个一致起点。
4. 初始化控制面与加入工作节点
三台虚拟机准备好后,接下来的操作顺序基本是固定的:先在控制面节点执行 kubeadm init,等控制面组件就绪,再在两个 worker 节点上执行 kubeadm join,最后部署 CNI 网络插件。顺序不能乱,尤其是 CNI 必须在节点加入后尽早部署,否则节点会一直保持 NotReady。
4.1 kubeadm init 前必须确认的几件事
初始化之前最好做一个快速检查,把这些状态确认好再执行大命令。
第一是版本兼容性。kubeadm、kubelet、kubectl 三个客户端工具的版本应该一致,容器运行时 containerd 的版本要在 Kubernetes 支持的范围内。如果某台机器上的 kubelet 版本比其他节点高一个补丁版本,不一定立刻出问题,但没必要冒这个险。可以统一用下面几条命令确认:
bash复制kubelet --version
kubeadm version
kubectl version --client
containerd --version
第二是 cgroup 驱动一致。containerd 配置里的 SystemdCgroup 要设置为 true,并且 kubelet 的配置也要指向 systemd。两者不一致,容器运行时创建 Pod 沙箱时会报 cgroup 错误,节点状态会卡在 NotReady。
第三是镜像源与镜像预拉取。如果你的网络环境访问默认镜像地址有问题,可以在 init 前先基于自定义镜像仓库拉取镜像。例如很多国内环境会把镜像仓库参数指向一个可访问的公共仓库,比如兼容 google_containers 路径的镜像源。这个操作要在控制面节点提前执行,否则 init 会卡在 “Pull image” 阶段。
bash复制sudo kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers
第四是 hostname 与 IP。控制面节点的 IP 要和 /etc/hosts 里配置的一致,而且必须是集群内其他节点可达的地址。如果存在多个网卡,kubeadm 默认会选择默认路由对应的 IP,如果这个 IP 不是你想用的集群内网地址,就需要在 init 参数里显式指定。
4.2 控制面初始化命令与参数含义
控制面节点执行 kubeadm init,参数至少要覆盖三件事:Kubernetes 版本、apiserver 广播地址、Pod 网段。常见示例写法如下:
bash复制sudo kubeadm init \
--kubernetes-version=1.29.14 \
--apiserver-advertise-address=192.168.236.10 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/16
解释一下关键参数。--apiserver-advertise-address 必须写成控制面节点在网络里的固定 IP,因为 worker 节点 join 的时候要连这个地址来访问 API Server。--pod-network-cidr 是分配给 Pod 的虚拟网段,这个网段不能和宿主机网段冲突,也不能和 Service 网段重叠,具体选择会和你后面用哪个 CNI 插件强相关。--service-cidr 是 Service 的虚拟 IP 网段,一般使用默认的 10.96.0.0/16 即可,不需要随意修改。
init 执行成功后,终端会输出两段关键信息:一段是 kubeconfig 文件的配置方法,另一段是 worker 节点加入集群的 kubeadm join 命令。join 命令里包含 token 和证书哈希,需要保存好,因为它们有有效期,默认是 24 小时。
初始化完成后,控制面节点要配置好 kubeconfig,才能使用 kubectl 访问集群。常见做法是把 root 用户生成的 admin.conf 复制到当前用户的 ~/.kube/config,或者直接使用初始化输出里的 export KUBECONFIG 方式。
这是一个新手容易踩坑的点:kubeadm init 即使显示成功,如果忘记配置 kubeconfig,你在控制面节点执行 kubectl get nodes 会报 connection refused 或 “no configuration has been provided”,然后误以为集群初始化失败。
4.3 给控制面节点加回工作负载能力
用 kubeadm 初始化的控制面节点默认带有 Taint,不允许调度业务 Pod,这是合理的生产默认。但在三节点本地学习环境里,如果你想最大限度地利用资源,可以移除这个 Taint,让控制面节点也参与业务负载调度。
bash复制kubectl taint nodes --all node-role.kubernetes.io/control-plane-
这个操作只适合学习和小规模验证。在生产环境,控制面节点应该保持专用,不承担业务负载。三节点方案里是否解除 Taint,取决于你希望模拟什么样的集群。想体会生产形态,就保留 Taint;想让有限资源都能跑业务,就解掉。
4.4 worker 节点 join 的完整流程
worker 节点加入集群,本质是执行控制面初始化完成后输出的 kubeadm join 命令。命令里包含 API Server 地址、token 和证书哈希。示例结构如下:
bash复制sudo kubeadm join 192.168.236.10:6443 \
--token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
如果 token 过期了,可以在控制面节点重新生成:
bash复制sudo kubeadm token create --print-join-command
join 之后并不是立刻完成。你需要在控制面节点观察节点状态,通常会先看到 worker 节点注册,但状态是 NotReady。这个状态的原因大概率是还没有安装 CNI 网络插件。此时不要急着怀疑 join 失败,先把网络插件解决。
4.5 部署 CNI 网络插件
CNI 插件负责为每一个 Pod 分配虚拟网络地址,并打通跨节点通信。没有它,即使节点状态是 Ready,Pod 之间的网络也是不通的。
常见选择有两种:Flannel 和 Calico。Flannel 配置简单、资源占用低,适合学习和轻量使用,典型实现是 VXLAN 后端;Calico 功能更强大,支持网络策略,更接近生产环境,但配置和资源开销都更高。这个方案里,如果目的主要是学 K8s 基础机制,Flannel 就够了;如果想顺便学网络安全策略,可以选 Calico。
安装方式通常是获得对应插件的 manifest 文件后执行:
bash复制kubectl apply -f kube-flannel.yml
要特别注意 Pod 网段参数。Flannel 默认使用 10.244.0.0/16,这也是之前 kubeadm init 时 --pod-network-cidr 使用 10.244.0.0/16 的原因。如果反过来,Pod 网段和 CNI 默认网段不一致,Flannel 会报 subnet 冲突,Pod 一直 CrashLoopBackOff。
安装完成后,等待数十秒到数分钟,再次执行 kubectl get nodes,看到三台节点的状态都变成 Ready,集群的搭建阶段才算完成。这个等待时间取决于机器性能和网络状况。
注意:不要同时装多个 CNI 插件。Flannel 和 Calico 同时部署会导致网络策略冲突,Pod 的网络可能反复重建,这种问题很难一眼看出来。
5. 验证一个“学得会”的集群,而不是“装出来”的集群
节点 Ready 之后,很多人会以为集群已经大功告成。实际上,Ready 只代表节点层面的健康检查通过,不代表集群真的能正确处理应用生命周期。你需要跑一条完整的验证链路,证明调度、服务暴露、跨节点通信都正常工作。
5.1 节点状态不是唯一指标
kubectl get nodes 显示 All Ready,反映的是 kubelet 心跳、系统资源、容器运行时状态都正常。但这个状态不会告诉你:Pod 能不能被调度到不同节点;Service 能不能正确转发流量;跨节点访问是否被网络策略拦截。所以验证要分层次推进。
最低层是运行时验证,确认容器镜像能正常拉取、容器能启动、日志能正常采集。再上一层是调度验证,确认多副本 Pod 会分布到不同节点。再上一层是网络验证,确认 Pod 之间、Service 与 Pod 之间、NodePort 对外访问都能通。最后一层是故障验证,确认节点不可用后,集群是否按预期重新调度。
这一套验证做下来,才算真正使用了集群,而不是只在控制面节点上敲了几个 kubectl 命令。
5.2 用一条 demo 串起完整链路
一个常用的做法是部署一个 nginx Deployment,副本数设为 3,然后创建 Service 暴露访问入口。
bash复制kubectl create deployment nginx-demo --image=nginx:1.27 --replicas=3
kubectl expose deployment nginx-demo --port=80 --target-port=80 --type=NodePort
创建后,先后观察两个东西。第一个是 Pod 的分布:
bash复制kubectl get pods -o wide
正常情况会看到三个 Pod 分布在不同的节点上,如果有 Pod 一直 Pending,多半是节点资源不足,或者 Taint 阻止调度。第二个是 Service 的 NodePort 端口:
bash复制kubectl get svc nginx-demo
拿到 NodePort 端口后,从任意一台 worker 节点或宿主机访问这个端口,例如:
bash复制curl http://192.168.236.11:3xxxx
只要返回 nginx 的默认页面,说明从 Service 到 Pod 的转发链路是通的。接下来还可以做一次滚动更新,观察新 Pod 如何先创建、再替换、最后达到所有副本可用的状态:
bash复制kubectl set image deployment/nginx-demo nginx=nginx:1.28
kubectl rollout status deployment/nginx-demo
这时你会看到,滚动更新不是把所有 Pod 杀掉再建,而是逐个替换,并且新 Pod 可能被调度到和旧 Pod 不同的节点。这一步能直观理解 ReplicaSet 的协调机制。
5.3 排查链路:从现象到根因
三节点集群使用过程中,问题会比单机环境多,而且更容易让你摸不着头脑。这里给一个常用排查顺序,按层次推进,不要跳步。
| 现象 | 优先排查 | 常用命令 |
|---|---|---|
| 节点 NotReady | kubelet 状态、容器运行时、CNI | journalctl -u kubelet -n 100、crictl ps -a |
| Pod 一直 Pending | 资源不足、污点、调度器状态 | kubectl describe pod |
| Pod 一直是 ContainerCreating | 镜像拉取失败、sandbox 启动失败、存储问题 | crictl ps -a、crictl logs |
| Pod 反复重启 | 启动命令、探针失败、容器内崩溃 | kubectl logs |
| 跨节点网络不通 | CNI 插件、路由、iptables、Firewalld | ip addr、ip route、kubectl logs -n kube-system |
| DNS 解析异常 | CoreDNS 是否运行、Service 是否正常 | kubectl logs -n kube-system -l k8s-app=kube-dns |
排查时有一个稳定思路:先看整体状态,再定位到具体对象,最后看日志。比如 kubectl get nodes 全部 Ready,但某个 Pod 是 Pending,那就用 kubectl describe pod 看事件;如果显示节点资源不足,就看节点上的 kubelet 日志;如果显示容器启动失败,就用 crictl logs 看运行时日志。
要特别留心几个“模仿成其他问题”的现象。节点 NotReady 但 kubelet 看起来还在跑,很可能是容器运行时卡住;Pod 一直 ContainerCreating,很可能是 sandbox 镜像 pause 没有被正确拉取;应用日志正常但访问不通,很可能是 Service 的 selector 与 Pod 标签不匹配。
6. 这套虚拟机集群的长期价值与边界
搭建三节点环境不只是为了解决“把 K8s 装起来”的一次性问题。如果把它当成一次性安装任务,装完就会吃灰。更值得做的,是把这套环境经营成一个可反复使用的“集群练习场”。
6.1 快照和文档,是虚拟机集群最值得依赖的两件事
虚拟机的最大优势之一就是快照。在几个关键节点分别留一个快照,能大幅降低试错成本。
建议至少保留三个快照:第一个在母版完成系统基础配置后,称为“模板快照”;第二个在三台克隆机完成主机名、IP、系统唯一标识调整后,称为“预初始化快照”;第三个在集群全部节点 Ready、CNI 正常部署后,称为“集群可用快照”。有了这三个快照,你可以放心地实验各种异常操作,比如破坏 kubelet、删 CNI 资源、模拟节点宕机,实验结束后几分钟就能恢复。
另一件事是文档化。把三台机器的 IP 分配、主机名角色、K8s 组件版本、容器运行时配置、镜像仓库参数、初始化命令、验证步骤记录成一份文档或者脚本。这不是给别人的,是给你自己的。三个月后重新回来看这份文档,你能用它把集群重建出来,说明你真的理解了这套环境。
最简单的方式是写一个 shell 脚本,把母版上的重复配置固化下来,再在文档里标注“手动调整的部分”。这样后续如果 VMware 版本变化、镜像地址失效、K8s 小版本升级,你只需要改脚本参数,不用重新踩一遍所有坑。
6.2 从“能用”到“接近生产”,还缺哪几块拼图
这套三节点环境解决了集群运行的基础问题,但离生产可用还有明显距离。如果你未来要往生产方向扩展,至少还有几块拼图要补。
第一是监控。当前集群没有部署 Metrics Server,kubectl top 无法查看 Pod 和节点的资源占用。生产环境至少要有节点监控、Pod 监控、控制面组件监控。第二是日志。节点日志、容器日志和 Kubernetes 事件需要统一收集,Pod 重建后日志不能直接丢失。第三是备份。etcd 是集群状态的核心,需要定期做快照,否则误删对象或损坏 after upgrade,没有备份会很被动。第四是镜像仓库。生产环境很少直接使用 Docker Hub 公共镜像,需要一个私有仓库管理镜像。第五是入口。NodePort 不适合生产流量入口,一般会补 Ingress Controller 做七层路由。
这些能力不是一上来就要全上,但你要知道这套虚拟机环境搭建只是起点,不是终点。每次在本地验证新组件,都应该顺手把它接入现有的三节点环境。
6.3 什么场景不建议用这套方案,以及它的适用边界
虚拟机里的三节点集群,适用边界比很多人想象的要窄。性能方面,虚拟化层会带来系统调用和网络转发开销,在嵌套虚拟化场景下更明显,所以不适合做基准压测和性能对比实验。功能方面,如果你的实验需要真实物理网卡、特殊内核模块、GPU 或 RDMA 设备,虚拟机方案很难模拟。规模方面,三节点里只有一个控制面节点,不是高可用集群,不能用来验证多控制面故障切换。
但它的边界也正是它的价值。学习 Kubernetes 核心机制,验证 Deployment、Service、ConfigMap、PV/PVC、RBAC 这些通用对象,排查 kubelet 和容器运行时问题,这些场景在三节点虚拟机上体验和物理集群几乎一致,而且成本低、可恢复、可重复。
所以我的最终建议很明确:不要把这套环境只当成“安装 K8s 的一次性任务”,而是结合模板快照、预初始化快照、可用快照和一份清楚的文档,把它固化成一个可复用的实验工具。先跑通一条最简验证链路,再把监控、日志、备份逐步接入。这样你用三个月积累下来的,不只是一台能吃灰的虚拟机,而是一套属于自己的 Kubernetes 实践方法论。虚拟机可以随时删除重建,但你对这套机制的理解,会一直留下来。
