恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
VMware中kubeadm部署Kubernetes集群及Dashboard实战指南
首页
资讯中心
/
VMware中kubeadm部署Kubernetes集群及Dashboard实战指南
VMware中kubeadm部署Kubernetes集群及Dashboard实战指南
发布时间:2026/10/21 13:53:54
最近在整理内部测试环境需要在虚拟化平台上搭一套能日常练手和跑demo的Kubernetes集群。原本以为K8s集群部署已经是很成熟的流程闭着眼都能装完结果真正从VMware里创建虚拟机开始走了一遍才发现坑全藏在细节里网络模式选错导致节点之间互不通、镜像拉不下来卡在初始化、cgroup驱动不一致导致kubelet起不来、CNI插件没装对节点一直NotReady。这篇文章就是我把整套流程从头到尾亲手验证之后整理出来的用VMware Workstation创建了三台Ubuntu 22.04虚拟机一台master两台node采用kubeadm方式部署Kubernetes 1.28版本最后还装上了K8s Dashboard并跑通了一个测试应用。每一步都给出具体命令和操作理由按这个顺序做下来可以少走很多弯路适合正在准备本地集群环境、想快速跑通一套可用K8s的开发者参考。1. 虚拟机创建前的规划网络模式、资源分配和IP设计1.1 网络模式决定集群搭建的成败在VMware里搭建K8s集群第一个要决定的不是装什么系统而是虚拟机使用哪种网络模式。VMware Workstation提供桥接模式、NAT模式和仅主机模式不同模式直接影响三台节点之间能否互通、外网能否访问镜像仓库。我在第一次尝试时直接用了桥接模式想着让三台机器跟宿主机处于同一局域网IP由家里的路由器DHCP分配结果第二天重新开机后发现节点IP全变了集群直接分崩离析。桥接模式下IP取决于所连接网络的DHCP租约在办公环境或频繁切换Wi-Fi的场所非常不稳定。如果只是本机自己练习、不要求集群被局域网内其他机器访问最稳妥的方案是用NAT模式配合VMware自带的虚拟网络编辑器固定网段然后在虚拟机内配置静态IP。NAT模式的宿主机网络结构比较稳定所有虚拟机共享一个虚拟NAT网关三台机器天然处于同一个二层网络这正好满足K8s集群对节点网络的基本要求。1.2 节点资源规划最低配置和推荐配置K8s集群对硬件资源不算太苛刻但如果虚拟机配置得太低初始化阶段镜像拉取、组件启动都会变得非常慢甚至直接超时失败。我这次给每个节点分配了2核CPU、4GB内存和40GB磁盘三台虚拟机一共占用宿主机6核、12GB以上的内存。资源规划上有一条经验之谈master节点建议内存不要低于4GB否则etcd和kube-apiserver在系统负载上来之后容易出现内存压力node节点2GB是下限但如果还要在上面跑业务容器4GB会更从容。磁盘方面20GB装完系统外加容器镜像会比较紧张建议40GB起步避免后续拉几个镜像就把根分区写满。节点角色CPU内存磁盘数量master2核4GB40GB1node工作节点2核4GB40GB2创建虚拟机时有个容易被忽略的细节内存分配需要在创建向导里一次性设置好虚拟机创建完成后再改内存需要关机操作。系统镜像选择Ubuntu 22.04 Server版安装过程比较直观选择默认的LVM分区方案即可不需要额外定制。1.3 IP规划与主机名设计我采用NAT模式在VMware的虚拟网络编辑器中确认了当前NAT网络的网段。这里要说明一下不同电脑上VMware生成的NAT网段可能不一样实际操作时以自己机器上显示为准。我的三台虚拟机IP规划如下主机名IP地址角色master192.168.137.10控制平面节点node1192.168.137.11工作节点node2192.168.137.12工作节点安装系统时可以在安装向导里预设主机名也可以在系统安装完成后通过命令设置。比较推荐在安装阶段就分别命名为master、node1、node2避免后面混淆。系统装好第一件事是把三台机器的IP地址从DHCP改为静态。Ubuntu 22.04使用netplan管理网络配置编辑/etc/netplan/00-installer-config.yaml文件network: ethernets: ens33: dhcp4: false addresses: - 192.168.137.10/24 routes: - to: default via: 192.168.137.2 nameservers: addresses: - 192.168.137.2 version: 2网卡名称以实际环境为准可能是ens33、ens160或eth0用ip addr命令查看确认即可。配置完成后执行sudo netplan apply使配置生效然后用ip addr验证IP是否变成预期值。关于/etc/hosts解析三台节点都要配置相同的条目保证节点之间通过主机名可以互相访问192.168.137.10 master 192.168.137.11 node1 192.168.137.12 node2这一步经常被忽略但kubeadm初始化之后kubelet会通过主机名或API服务器地址来访问Master节点解析不通会造成各种莫名奇妙的连接问题。2. 系统基础配置关闭swap、防火墙和调整内核参数2.1 更新软件源并安装基础工具三台虚拟机系统装好后先别急着部署K8s先把操作系统本身做一遍基础配置。先用root身份登录或者用创建用户加sudo提权。首先更新软件包索引并升级系统sudo apt-get update sudo apt-get upgrade -y升级时间取决于网络状况可能需要几分钟到十几分钟不等。然后安装一些后面会用到的工具sudo apt-get install -y apt-transport-https ca-certificates curl gpg这里安装apt-transport-https是为了让apt支持从HTTPS源下载软件包ca-certificates则用于信任HTTPS证书。如果跳过这一步后面在添加K8s软件源时很可能会报证书或传输协议相关的错误。2.2 关闭swap和防火墙为什么K8s明确要求Kubernetes对节点有个硬性要求必须关闭swap分区。kubelet默认情况下不允许在swap内存上工作因为K8s的资源模型是基于CPU和内存配额管理的swap的存在会让资源使用量统计出现偏差影响调度判断。不关闭swap的情况下启动kubelet服务会直接报错退出。关闭swapsudo swapoff -a sudo sed -i / swap / s/^/#/ /etc/fstab第一条命令立刻卸载当前系统里已经启用的swap第二条命令注释掉fstab里的swap挂载项防止重启之后swap卷土重来。很多人只执行第一条重启后swap又回来了然后一脸疑惑地开始排查各种奇怪问题。Ubuntu默认的防火墙是ufwK8s集群内部组件需要互相访问大量端口。为了本地测试环境的便利直接关闭ufw并把iptables的转发策略调整为允许sudo systemctl stop ufw sudo systemctl disable ufw在生产环境中防火墙策略通常比这个复杂但本地VMware环境里开防火墙带来的麻烦远大于收益尤其当你对K8s各组件的端口要求还不熟悉时。2.3 内核模块和sysctl参数的设置K8s网络插件CNI需要Linux内核支持overlay网络和bridge过滤功能。overlay是一种容器网络层叠技术简单理解就是让容器可以拥有跨主机的扁平虚拟网络br_netfilter模块则确保桥接的流量也能通过iptables规则进行过滤。创建内核模块加载配置sudo tee /etc/modules-load.d/k8s.conf EOF overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter然后配置sysctl参数确保包转发和桥接流量处理正常工作sudo tee /etc/sysctl.d/k8s.conf EOF net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF sudo sysctl --system这里面的net.ipv4.ip_forward尤其关键。Kubernetes的Pod网络和Service代理依赖IP转发来实现数据包在节点之间的路由如果不开启容器之间、不同节点上的Pod之间无法正常通信即使集群初始化成功后续也会出现Pod访问不通的问题。2.4 设置主机名并检查时区前面提到安装时最好把主机名设置好如果当时没有设置现在需要手动补上sudo hostnamectl set-hostname master sudo hostnamectl set-hostname node1 sudo hostnamectl set-hostname node2注意三台机器分别执行对应的主机名命令设置完成后最好重启一次系统让所有内核参数、主机名配置彻底生效。时区方面保持系统默认即可不需要额外配置统一时间K8s组件自己会协调时间偏差只要系统时间没有大的差异一般不会出问题。3. 安装容器运行时与Kubernetes核心组件3.1 安装Docker并调整cgroup驱动Kubernetes需要容器运行时来启动Pod里的容器目前最主流的选择还是Docker通过containerd作为底层运行时来工作。Ubuntu 22.04的软件源里直接有Docker包使用docker.io这个包名安装sudo apt-get install -y docker.io sudo systemctl enable --now docker安装好之后先用docker version检查Docker守护进程是否正常。这里有个非常重要的步骤修改Docker的cgroup驱动为systemd。sudo tee /etc/docker/daemon.json EOF { exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m } } EOF sudo systemctl daemon-reload sudo systemctl restart dockercgroup是Linux用来限制进程资源使用的机制Docker和Kubelet各自管理cgroup如果两者的驱动不一致在节点运行一段时间后就会被kubelet判定为资源管理方式不匹配而触发崩溃。把Docker的cgroup驱动改成systemd与kubelet保持一致是官方推荐的标准配置。关于镜像加速的问题如果你的网络环境访问Docker Hub比较慢可以在这个daemon.json里额外配置registry-mirrors字段填入一个网络可达的镜像加速地址。不同地域、不同网络环境下可用的加速地址并不相同建议根据自己实际网络情况配置填错反而拖慢拉取速度。3.2 添加Kubernetes软件源并安装三件套Kubernetes的核心组件是kubeadm、kubelet、kubectl。kubeadm负责初始化集群和管理节点加入流程kubelet是运行在每个节点上的核心代理服务kubectl是操作集群的命令行工具三者缺一不可。添加Kubernetes官方APT源sudo curl -fsSL K8s官方APT源的Release.key地址 | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo deb [signed-by/etc/apt/keyrings/kubernetes-apt-keyring.gpg] K8s官方APT源地址 / | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update这里我没有直接写出具体URL因为不同引导文档可能推荐不同地址而且软件源地址也可能随版本调整。实际操作时以Kubernetes官方文档的说明为准。重点在于源配置完成后执行apt-get update能看到Kubernetes相关软件包列表。然后安装指定版本的kubeadm、kubelet和kubectlsudo apt-get install -y kubelet kubeadm kubectl安装完成后执行apt-mark hold kubelet kubeadm kubectl锁定这三个包的版本防止意外升级导致集群组件版本不一致。Kubernetes版本升级有时会引入不兼容的API变化在正式升级之前锁版本是惯例操作。安装完成后可以查看版本号kubeadm version kubectl version --client如果kubelet服务没有自动启动手动执行sudo systemctl enable --now kubelet这时候kubelet可能处于异常状态这是正常的因为集群还没有初始化等kubeadm init之后它才能正常工作。3.3 预先拉取需要的系统镜像kubeadm init过程中会从容器镜像仓库拉取Kube API Server、etcd、CoreDNS等镜像如果网络不稳定初始化会卡在镜像拉取阶段很久。可以在初始化之前先手动查看需要哪些镜像kubeadm config images list这条命令会列出该版本K8s组件所需的全部镜像及版本号。如果默认镜像仓库访问困难可以使用kubeadm config images pull --image-repository 可访问的镜像仓库地址预先拉取也可以直接在这里换成可访问的镜像仓库地址。手动先拉一遍镜像既能验证网络是否通畅也能让后续初始化流程更加顺畅。4. 集群初始化与工作节点加入4.1 master节点初始化命令详解在master节点上执行初始化命令sudo kubeadm init \ --apiserver-advertise-address192.168.137.10 \ --pod-network-cidr10.244.0.0/16两个参数详解一下--apiserver-advertise-address指定API Server对外广播的IP地址这里填master节点的静态IP。如果不指定kubeadm会尝试自动探测本机IP在多网卡环境下有可能探测到错误的网卡导致工作节点无法连接API Server。--pod-network-cidr是Pod网络的CIDR网段这个网段必须和接下来安装的CNI插件配置保持一致。这里用10.244.0.0/16是flannel网络插件的默认网段。初始化过程会执行一段时间成功后会看到类似这样的输出Your Kubernetes control-plane has initialized successfully!注意重点在最后两段输出第一段是在master节点上配置kubectl的命令不执行的话无法在本机使用kubectl命令管理集群第二段是给工作节点加入集群用的kubeadm join命令里面包含token和证书哈希值。配置kubectlmkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config这里一定要用root或者有sudo权限的用户去复制admin.conf文件到当前用户目录下否则后面执行kubectl get nodes会因为缺少集群连接信息而报错。4.2 镜像拉取失败和初始化中断的处理方式初始化过程中最常见的失败点是镜像拉取超时。如果碰到这种情况错误信息会比较明确地指出是哪个镜像拉不下来。处理思路是检查网络弄清楚默认镜像仓库是否可达如果不可达就手动执行镜像预拉取换一个可达的镜像仓库地址。还有一种情况是初始化到一半因为参数错误失败比如Pod网段与后面要装的CNI冲突。这时候不需要销毁虚拟机重来先执行重置命令sudo kubeadm reset -f sudo rm -rf /etc/cni/net.d sudo rm -rf $HOME/.kube然后检查系统状态再重新执行kubeadm init。重置操作不会删除已经拉取的镜像所以第二次初始化时会快很多。4.3 工作节点加入集群与token过期处理master节点初始化成功后在node1和node2上分别执行初始化完成时输出的kubeadm join命令命令格式类似这样sudo kubeadm join 192.168.137.10:6443 \ --token token \ --discovery-token-ca-cert-hash sha256:hash其中token和hash是初始化时生成的真实值。执行后等待几秒钟如果输出显示节点已加入集群那就成功了。如果初始化时没有来得及保存join命令或者token过期了不用重新初始化集群。在master节点上重新生成一条join命令kubeadm token create --print-join-command这条命令会生成新的token并直接打印出完整的join命令复制到工作节点执行即可。节点加入后在master节点上查看集群状态kubectl get nodes此时大概率会看到master和两个node都处于NotReady状态原因是没有安装CNI网络插件。这是正常的下一步就是装网络插件。5. 部署CNI网络插件让节点从NotReady变成Ready5.1 flannel和calico怎么选CNIContainer Network Interface是Kubernetes容器网络的接口规范负责给每个Pod分配IP并打通跨节点通信。没有CNI插件的集群节点之间的Pod网络是断裂的kubelet会一直报告节点条件不满足所以节点状态停留在NotReady。社区里最常见的两种CNI方案是flannel和calico。flannel实现简单、资源占用低、配置方便适合本地开发和小规模集群calico功能更强支持网络策略适合对网络安全隔离要求较高的场景。我这次本地环境选择的是flannel原因很直接部署只需要一条命令对硬件要求低默认监听端口也少不容易踩坑。如果你的生产环境需要精细控制Pod之间的访问策略再去考虑calico。5.2 安装flannel并验证Pod网络获取flannel的部署清单文件然后应用到集群kubectl apply -f flannel部署清单文件地址部署清单文件地址以Kubernetes文档推荐或flannel项目官方发布的为准。应用前可以先查看清单内容确认其中的Network网段是否为10.244.0.0/16如果不是就需要下载后修改为与初始化参数一致否则flannel会给Pod分配与预期不一致的网段导致网络混乱。应用完成后flannel会以DaemonSet方式在集群每个节点上启动一个Pod检查flannel Pod是否正常运行kubectl get pods -n kube-flannel -o wide等所有flannel Pod进入Running状态后再次查看节点状态kubectl get nodes正常情况下master、node1、node2都会从NotReady变为Ready。节点状态变为Ready意味着kubelet已经正常上报参数网络插件也已就绪Pod的调度和启动条件都满足了。如果节点长时间停留在NotReady查看kubelet日志是排查的第一步journalctl -u kubelet -f5.3 跨节点Pod通信验证集群Ready之后可以先简单验证一下跨节点通信能力。部署一个测试Pod并进入其中ping另一个节点的Pod IP比如在master上执行kubectl run test-pod --imagenginx kubectl get pods -o wide拿到Pod的IP后进入Pod内部访问集群的另一个节点地址。更简单的验证方式是在某个节点上部署一个Pod然后通过Service将流量转发到另一个节点上的Pod这个放在仪表盘部署之后再验证也不迟。6. 安装Dashboard并跑通一个测试应用6.1 部署Dashboard控制台Kubernetes Dashboard是官方提供的Web管理界面可以直观地查看节点状态、工作负载和日志。部署Dashboard用官方推荐清单文件kubectl apply -f dashboard推荐部署清单文件地址部署完成后Dashboard相关的Pod会运行在kubernetes-dashboard命名空间下。等待Pod全部运行正常kubectl get pods -n kubernetes-dashboardKubernetes Dashboard从较新版本开始默认不开放匿名访问需要使用token或者kubeconfig文件登录。为了拿到管理员的登录权限需要单独创建一个具有管理员权限的ServiceAccount。创建管理员账号的YAML文件apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard保存为dashboard-admin.yaml后执行kubectl apply -f dashboard-admin.yaml然后获取登录tokenkubectl -n kubernetes-dashboard create token admin-user输出的长字符串就是登录Dashboard的访问令牌。Dashboard默认监听的是443端口想从宿主机浏览器直接访问最简单的办法用kubectl proxy转发kubectl proxy然后在浏览器访问http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/打开页面后选择token登录方式粘贴刚才获取的token即可进入控制台。6.2 部署一个带Service的测试应用为了确认集群确实可以承载业务流量部署一个简单的nginx应用并暴露Service。创建Deployment和Servicekubectl create deployment nginx-test --imagenginx kubectl expose deployment nginx-test --typeNodePort --port80 --target-port80查看Service详情kubectl get svc nginx-testNodePort类型会为Service分配一个30000-32767范围内的端口例如31567。此时在宿主机浏览器访问http://192.168.137.10:31567如果能看到nginx的欢迎页面说明整个集群工作正常请求经过Service转发到了Pod里的nginx容器跨节点网络也处于通联状态。如果想验证跨节点调度可以扩容副本数kubectl scale deployment nginx-test --replicas3然后查看Pod分布在哪些节点上kubectl get pods -o wide正常情况下Pod会分布在不止一个节点上说明调度器正常工作两个工作节点也能正常运行业务容器。6.3 集群日常排查的常用命令集群搭建完成后后续维护中也经常会遇到各种状态问题。把我实际使用中比较高频的命令整理一下查看节点整体状态kubectl get nodes查看所有命名空间下的Pod状态kubectl get pods -A查看某个Pod的详细信息和事件kubectl describe pod pod名 -n 命名空间查看容器实时日志kubectl logs -f pod名 -n 命名空间查看集群所有组件状态kubectl get componentstatus部分版本可能不再支持查看Control Plane相关Pod状态kubectl get pods -n kube-system检查网络插件Pod状态kubectl get pods -n kube-flannel如果某个节点状态变为NotReady先把网络插件Pod和kubelet日志翻一遍基本能定位80%以上的问题。这次搭建过程中我最常踩的坑集中在两处一是镜像拉取问题二是cgroup驱动不一致。镜像问题在本地环境里通过预拉取和配置可用镜像源解决掉cgroup驱动则在配置Docker daemon.json这一步就提前规避了。整个流程走完从空的虚拟机到可用的K8s集群总共用了一下午时间。如果你也是准备在VMware里搭一套集群练手建议每完成一步就做一个VMware虚拟机快照后续想快速重建环境或者回退到正常状态不用从头再装一遍系统和软件。