news 2026/10/21 13:53:51

VMware中kubeadm部署Kubernetes集群及Dashboard实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
VMware中kubeadm部署Kubernetes集群及Dashboard实战指南

最近在整理内部测试环境,需要在虚拟化平台上搭一套能日常练手和跑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核4GB40GB1
node工作节点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,服务会直接报错退出。

关闭swap:

sudo swapoff -a sudo sed -i '/ swap / s/^/#/' /etc/fstab

第一条命令立刻卸载当前系统里已经启用的swap,第二条命令注释掉fstab里的swap挂载项,防止重启之后swap卷土重来。很多人只执行第一条,重启后swap又回来了,然后一脸疑惑地开始排查各种奇怪问题。

Ubuntu默认的防火墙是ufw,K8s集群内部组件需要互相访问大量端口。为了本地测试环境的便利,直接关闭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.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" } } EOF sudo systemctl daemon-reload sudo systemctl restart docker

cgroup是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和kubectl:

sudo 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-address=192.168.137.10 \ --pod-network-cidr=10.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和证书哈希值。

配置kubectl:

mkdir -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变成Ready

5.1 flannel和calico怎么选

CNI(Container 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 -f

5.3 跨节点Pod通信验证

集群Ready之后,可以先简单验证一下跨节点通信能力。部署一个测试Pod并进入其中ping另一个节点的Pod IP,比如在master上执行:

kubectl run test-pod --image=nginx 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-dashboard

Kubernetes 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

然后获取登录token:

kubectl -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和Service:

kubectl create deployment nginx-test --image=nginx kubectl expose deployment nginx-test --type=NodePort --port=80 --target-port=80

查看Service详情:

kubectl get svc nginx-test

NodePort类型会为Service分配一个30000-32767范围内的端口,例如31567。此时在宿主机浏览器访问http://192.168.137.10:31567,如果能看到nginx的欢迎页面,说明整个集群工作正常:请求经过Service转发到了Pod里的nginx容器,跨节点网络也处于通联状态。

如果想验证跨节点调度,可以扩容副本数:

kubectl scale deployment nginx-test --replicas=3

然后查看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虚拟机快照,后续想快速重建环境或者回退到正常状态,不用从头再装一遍系统和软件。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 13:53:50

Grid R-CNN实战:基于R101+FPN的垃圾车高精度检测

1. 项目概述说到垃圾车目标检测&#xff0c;很多做CV的人第一反应是“这不就是普通的车辆检测嘛&#xff0c;拿YOLO或者Faster R-CNN跑一下不就完事了&#xff1f;”但真正接过这类落地项目的人心里都清楚&#xff0c;垃圾车检测和通用车辆检测之间差的不是一星半点。为什么这么…

作者头像 李华
网站建设 2026/10/21 13:52:11

技能习得的底层逻辑:从刻意练习到反馈循环的完整训练框架

1. 从“skills”这个标题说起&#xff1a;一个被低估的硬核话题 “skills”这个词&#xff0c;乍一看平平无奇&#xff0c;甚至有点太宽泛了。但恰恰是这种宽泛&#xff0c;让它成了一个极难写好、也极难做透的题目。我见过太多人一上来就列清单——编程、设计、写作、沟通&…

作者头像 李华
网站建设 2026/10/21 13:50:46

知识工作插件化:从捕获到复用,搭建自动化知识流水线

不知道你有没有这种经历&#xff1a;收藏夹里躺着上百篇“稍后读”&#xff0c;真到用的时候一篇都翻不到&#xff1b;笔记软件里记了几百条&#xff0c;搬运一次工具就跟失忆一样&#xff1b;写报告想引个出处&#xff0c;翻了两小时浏览器历史还是没找到。我做了好几年知识密…

作者头像 李华
网站建设 2026/10/21 13:50:18

大模型应用开发需简单至上:稳定高效的工程化实践

1. 项目概述&#xff1a;什么才算“简单至上”的大模型应用1.1 这个指南是什么&#xff0c;写给谁看最近半年我帮几个团队做过大模型应用的技术评审&#xff0c;发现一个共性&#xff1a;很多人不是被技术难点卡住的&#xff0c;是被过度设计拖垮的。一拿到大模型的能力&#x…

作者头像 李华
网站建设 2026/10/21 13:50:15

YOLO26 OBB旋转目标检测实战:从标注到训练避坑指南

旋转目标识别这两年真的是越来越刚需了。以前做目标检测&#xff0c;一个水平框框住目标就很满意了&#xff0c;可一旦场景里出现大量任意朝向的物体——比如遥感影像里的飞机、船只&#xff0c;工业场景中码放角度不一的工件&#xff0c;甚至医疗切片里的细胞簇——普通的水平…

作者头像 李华
网站建设 2026/10/21 13:50:13

Formula One 控件公式引擎集成与避坑指南

简介&#xff1a;Formula One 9.0 是一款基于 Java 开发的 VTS 内容编辑工具&#xff0c;面向需要定期制作与定制 VTS 模板内容的个人用户及小型团队。它提供基于模板的编辑方式&#xff0c;配合图形化界面&#xff0c;可较便捷地完成内容创建与调整&#xff0c;并借助 Xalan、…

作者头像 李华