新手搭K8s集群这件事,说难也难,说容易也容易。先说结论:如果你只是想在家里用几台虚拟机或者物理机跑起来一套能学习、能验证的Kubernetes集群,用kubeadm官方引导工具,一个周末完全够用。如果你一上来就非要搞二进制方式逐文件部署,那大概率会在证书、服务配置这些细节里迷失方向,多半两三天都折腾不完。
这篇文章就是把“新手搭建K8s集群”这件事彻底拆开讲,从环境规划、组件选型到一步步实操命令,再到踩坑排错,全程照着抄基本就能跑通。适合刚接触容器编排、准备搭建自己第一套集群的开发者,也适合那些之前“照着某篇文章敲了一半卡住”的朋友,看完应该能把原理和步骤一起打通。
1. 搭建前先想清楚:你要装哪种K8s
很多人上来就是“我要装一套K8s”,但K8s的安装方式其实分好几种,不同方式适合不同场景,选择不对,后面会非常痛苦。
1.1 常见搭建方式的横向对比
目前社区主流的有三条路:kubeadm方式、二进制方式、Rancher等图形化平台方式。这三者各有侧重,我分别说说他们的特点。
kubeadm是Kubernetes官方的集群引导工具,也是目前生产环境用的最多的一种方式。它把etcd、API Server、Controller-Manager、Scheduler这些核心组件全部容器化,通过镜像拉取、静态Pod配置文件来启动。对于新手来说最大的好处是步骤标准化,kubeadm init一把就把控制平面的骨架拉起来了,后续加节点只需要一条join命令。坏处是底层细节被藏起来了一部分,排错时如果不懂组件工作流程,容易抓瞎。
二进制方式就是去官方下载各个组件的二进制文件,手动配置证书、配置文件,再用systemd托管进程。这种方式对理解内部机制帮助最大,但部署工作量也最大。个人建议新手暂时不要碰,除非你已经用kubeadm成功搭过一两套集群,对组件交互有了帧底认知。
Rancher这类图形化平台是把K8s作为基础设施对外提供,你可以像操作一个软件一样去创建集群。好处是门槛低,Web界面点点点,但坏处是它帮你屏蔽了太多细节,如果哪天Rancher出了问题,你可能完全不知道底层到底是怎么回事。
综合来看,新手我强烈建议从kubeadm入手。原因很简单:它是官方工具,社区文档最多,出问题搜解决方案最容易搜到,而且学会之后对集群的理解也比用Rancher要深入得多。
注意:这里说的是用kubeadm搭建物理机/虚拟机集群,不是用minikube或kind。minikube和kind是单机模拟,适合本地快速验证,但和真正的多节点集群在架构上还是有差距。
1.2 数据面、控制面和etcd,先分清角色再动手
在动手敲命令之前,你必须搞清楚K8s集群里有哪些角色。这就好比你搭一个公司组织架构,先分清谁是管理岗、谁是执行岗,后面安排工作才不会乱。
控制平面(Control Plane)就是集群的大脑,由API Server、Scheduler、Controller-Manager和etcd组成。API Server是所有请求的入口,你执行kubectl命令实际上都是在和它通信;Scheduler负责决定Pod应该调度到哪个节点;Controller-Manager负责维持集群的期望状态,比如某个Deployment副本数是3,它会不停检查当前是不是3,不是就创建副本;etcd是集群的数据库,所有状态都存放在这里。
数据面(Worker Node)就是干活的节点,主要跑kubelet、kube-proxy和容器运行时。kubelet负责管理Pod的生命周期,kube-proxy负责实现服务的负载均衡和流量转发,容器运行时一般用containerd或Docker来真正创建容器。
新手容易犯的一个错误是认为控制平面和工作节点必须物理分开。其实小集群完全可以在同一台机器上装控制平面加工作节点,这样一台机器就能当主节点使用。我建议你至少准备三个节点:一个做主控,两个做工作节点,这样你可以体验到真实的调度过程。如果资源紧张,两个节点(一个主、一个工作)也能跑,但多节点调度的重要性就体现不出来了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手前的环境准备与核心组件选型
这一步决定了你后面是顺风顺水还是处处碰壁。很多新手集群建不起来,不是命令敲错了,而是前置条件没满足,环境不过关。
2.1 节点规格与系统版本推荐
K8s对节点的CPU和内存要求不算高,但也不能太寒碜。官方建议控制平面至少2核2G,实际经验是2核4G会更舒服,因为API Server和etcd在集群启动初期很吃内存。工作节点也是2核2G起步,这个配置跑一些简单的业务Pod绰绰有余。
操作系统这块,CentOS 7和Ubuntu 20.04/22.04是社区里被踩坑踩得最多的两个选择。个人更推荐Ubuntu 22.04,因为内核版本较新,对containerd和各种网络插件兼容性更好。如果你只能用CentOS 7,注意内核版本最好升级到3.10以上,默认的3.10在跑某些新版本K8s时会有兼容性问题。
主机名规划也要提前想好。建议统一格式,比如:
- master01(控制平面)
- work01(工作节点)
- work02(工作节点)
同时要把/etc/hosts写好,确保三个节点能通过主机名互相解析IP。这一步看似简单,实际中我见过无数人因为hosts没配好,导致kubelet启动时报错连不上API Server。
2.2 容器运行时选型:containerd还是Docker?
这是新手最容易懵的一个问题。Kubernetes从1.24版本开始移除了对Docker的直接支持,改用CRI(容器运行时接口)来对接容器运行时。现在主流的运行时是containerd,因为在kubeadm引导的集群里,containerd是默认最顺滑的选择。
如果你想沿用Docker的习惯,也不是不行,但是需要额外安装cri-dockerd这个适配层。说实话,既然官方都在推containerd,那你不如直接一步到位用containerd,很多新起的技术栈本来就是按containerd来做的,为自己的集群做一次减负也是好的。
containerd安装很简单,在Ubuntu上执行apt install containerd -y即可,CentOS上执行yum install containerd -y就可以了。装完之后要修改一个关键配置:默认的config.toml禁用了SystemdCgroup,但对于K8s集群来说,开启SystemdCgroup是让kubelet和容器runtime之间稳定协作的必要条件。改法如下:
bash复制rm -rf /etc/containerd/config.toml
containerd config default > /etc/containerd/config.toml
# 然后修改 /etc/containerd/config.toml,找到 SystemdCgroup = false 改成 SystemdCgroup = true
另外国内网络环境拉镜像可能很慢,建议把config.toml里sandbox_image的地址改成国内mirror,比如docker.io的pause镜像换成registry.aliyuncs.com/google_containers/pause:3.9。
实际经验:所有节点都需要装好containerd并保证它开机自启,这个装完不要漏。
3. 核心概念扫盲:Pod、Service、Deployment到底在干嘛
很多人搭建的时候只记命令,不理解原理,造成“搭起来了但不会用”的尴尬。这一节把几个最核心的概念用大白话讲明白,它们是后续运维的基础。
3.1 Pod:集群里最小的调度单元
Pod是Kubernetes调度的最小单位,一个Pod里可以有一个或多个容器,这些容器共享同一个网络命名空间和存储空间。你可以把Pod理解成一个“豆荚”,里面包着一颗或者几颗“豆子”(容器)。通常一个Pod里只放一个业务容器,但如果你有比如日志采集sidecar这种辅助容器,它们就会被放在同一个Pod里,共享网络栈。
Pod的生命周期是短暂的,比如你删除一个Deployment,里面的Pod就被销毁了,新创建出来的Pod可能落在另一台节点上。这个“位移”特性对新手来说刚开始会有点难适应——我的IP地址怎么老变?别慌,K8s里很少直接操作Pod,通常都通过Deployment来管理它。
3.2 Service:集群内部的固定入口
因为Pod的IP会变,所以K8s提供了一个稳定的访问入口叫Service。Service相当于给一组Pod做了一层负载均衡和DNS解析,你通过Service的IP或者名称就能稳定访问到后面的一组Pod,完全不用担心Pod漂移了怎么办。
Service的几种类型里,新手先理解ClusterIP和NodePort就够了。ClusterIP是集群内部访问用的,只能在集群内部通讯;NodePort则是把服务暴露到每个节点的某个端口上,比如30080这样,外部通过任意节点的IP加端口就能访问到服务。这两个类型覆盖了你学习和测试阶段的绝大多数需求。
3.3 Deployment:声明式管理应用副本
Deployment是管理Pod副本数和工作负载的控制器。你告诉它“我要运行3个nginx副本”,它会负责创建3个Pod,并且如果某个Pod挂掉了,它会自动创建一个新的Pod把数量拉回到3个。这种“声明式”的思路是K8s的核心哲学——你想达到什么状态就声明什么状态,K8s会想尽办法实现。
4. 完整实操:用kubeadm从零搭建一套三节点集群
理论铺垫够了,下面进入真正的实战环节。我以Ubuntu 22.04、Kubernetes 1.28、containerd运行时为例,演示完整搭建三个节点的流程。每一步都有对应的原因解释,照着做就不会迷茫。
4.1 所有节点统一环境初始化
集群节点之间一致性非常重要,所以下面这些操作要在每一台节点上都执行一遍。我以root用户身份操作,如果你用普通用户,命令前记得加sudo。
第一步,关闭swap。Kubernetes要求节点禁用swap,否则kubelet会启动失败或报错。打开/etc/fstab,找到swap那一行注释掉,然后重启或者直接执行swapoff -a让当前会话立即生效。建议两步都做:
bash复制swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab
第二步,加载内核模块并调整系统参数。Kubernetes依赖iptables和ipvs做流量转发,需要确保相关内核模块已经加载,同时开启流量转发。执行如下操作:
bash复制cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
cat <<EOF | 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
sysctl --system
这里我强调一下:overlay是容器镜像分层存储所依赖的文件系统,br_netfilter是让iptables规则能作用于网桥流量,如果不开启,流量转发会变得很诡异,集群内部网络会时不时出问题。
第三步,安装kubeadm、kubelet和kubectl。由于Google的源国内访问不稳定,建议使用阿里云镜像源:
bash复制apt-get update && apt-get install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/deb/ /" | tee /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubelet kubeadm kubectl
到这里三个版本的软件都会被安装上。安装完成后注意执行apt-mark hold kubelet kubeadm kubectl,防止以后执行apt upgrade的时候把它们升级到不兼容的版本,这个操作在真实生产里非常重要。
4.2 控制平面初始化:kubeadm init
在master01上执行初始化命令。这里有一个需要提前规划的细节:Pod网络网段和Service网段。kubeadm init里可以通过--pod-network-cidr和--service-cidr指定,这两个网段最好落在私有网段里,和你的物理机网段避开。
我常用的配置是Pod网段10.244.0.0/16,Service网段10.96.0.0/16,这是为了匹配后面要装的Flannel网络插件默认值。如果你选Calico做网络插件,Pod网段可能要改成192.168.0.0/16,因为Calico默认就这个。这个网段规划一定要提前定好,因为改网段意味着整个集群要推翻重新初始化,后面改成本很高。
初始化命令:
bash复制kubeadm init \
--apiserver-advertise-address=192.168.1.11 \
--control-plane-endpoint=192.168.1.11 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/16 \
--image-repository=registry.aliyuncs.com/google_containers
我这里用的是master01的实际IP作为APIServer地址。你如果没有高可用需求,直接填master01的IP即可。如果后面想加第二个控制平面做高可用,则应该在这里就设置一个LoadBalancer地址作为control-plane-endpoint。新手学习阶段先用一个控制平面就好,高可用等架构跑通后再考虑。
执行过程会拉取一堆镜像,耐心等待。如果你的网络不行,可能卡在镜像拉取这一步很久。解决方式是配置containerd的镜像加速,或者手动去能访问的机器上docker pull之后再导入到本地镜像库。等成功之后,最后几行会输出kubeadm join的命令,这个命令务必保存下来,后面工作节点加入集群要用。
然后执行配置kubectl:
bash复制mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
这些配置做好了之后打个简单验证:
bash复制kubectl get nodes
你会看到master01状态是NotReady,这是正常的,因为网络插件还没装。
4.3 安装网络插件:打通集群内部通信
Pod网络插件是集群能否正常工作的关键,不装它,所有节点都会停留在NotReady,因为这是CNI(容器网络接口)没有配置好,kubelet没法给Pod分配网络。
Flannel和Calico是两款最常见的方案。Flannel简单轻量,适合学习和内网环境;Calico功能更丰富,支持NetworkPolicy网络策略,适合生产环境。新手先装Flannel即可,等深入之后再观察Calico带来的额外能力。
安装Flannel只需要一条命令:
bash复制kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
不过国内网络访问GitHub可能不稳定,建议先下载这个YAML文件到本地,把里面的image地址替换成能访问的镜像仓库,再用kubectl apply -f kube-flannel.yml执行。
装完之后再查看节点状态:
bash复制kubectl get nodes
kubectl get pods -n kube-flannel
等Flannel的Pod全部运行,节点状态应该会从NotReady变到Ready。这一步如果一直卡在NotReady,优先查看kube-flannel这个命名空间下的Pod日志,问题多半出在镜像拉取不下来或者节点网段冲突。
我遇到过一次很隐蔽的问题:Flannel默认会选择一个网卡作为对外通信的网卡,如果机器有多块网卡,Flannel可能选错,导致跨节点Pod网络不通。解决方法是给Flannel的Deployment添加环境变量,指定正确的网卡名,比如:- name: IP_HOSTNET value: "eth0"。
4.4 工作节点加入集群
到work01和work02上,执行master01初始化时输出的kubeadm join命令,类似这样:
bash复制kubeadm join 192.168.1.11:6443 --token xxxxx.yyyyyy --discovery-token-ca-cert-hash sha256:xxxxxxxx
我提醒大家记住这个token是有过期时间的,默认24小时。如果过期了,可以在master上重新生成一个:
bash复制kubeadm token create --print-join-command
所有节点加入成功后,在master上执行kubectl get nodes,你会看到三个节点状态都变成Ready。这代表你的K8s集群已经基本搭建完成了。
4.5 部署一个测试应用验证集群
集群Ready之后,部署一个简单的nginx测试一下功能是否正常:
bash复制kubectl create deployment nginx-test --image=nginx:latest
kubectl expose deployment nginx-test --type=NodePort --port=80
kubectl get svc
看到nginx-test的Service映射到了一个类似80:31555/TCP的端口,然后在浏览器里访问任意节点的IP加这个端口:
code复制http://192.168.1.12:31555
如果你能看到Nginx的欢迎页,说明集群的数据通路是通的。这就是整个集群从零到一的完整验证闭环。
5. 集群自检:能起来不等于能用,这几个坑不踩后悔
很多教程到这里就收尾了,但根据我个人经验,新手做完上面的步骤之后,大概率还会遇到下面几个高频问题。这一节就是排雷。
5.1 1分钟学会K8s常用命令
日常运维怎么少得了命令行。kubectl是最常用的工具,这里把最高频的几条整理出来,建议收藏起来照着敲:
- kubectl get nodes:查看节点状态
- kubectl get pods -A:查看所有命名空间下的Pod
- kubectl logs -f pod名:跟踪Pod日志
- kubectl describe pod pod名:查看Pod详细事件,这个是排障神命令
- kubectl apply -f xxx.yaml:应用配置
- kubectl delete -f xxx.yaml:删除配置
- kubectl get svc -A:查看所有Service
新手最容易犯的错就是觉得Pod起不来就去看logs,只看logs不看describe。实际上很多调度失败、镜像拉取失败、卷挂载失败的原因,都会在kubectl describe pod输出末尾的Events里写得清清楚楚。先describe,再logs,这个顺序是排障的正确姿势。
5.2 常见坑Top 5:从验证到定位的完整链路
这里整理我见过的、也是社区里出现频率最高的几个坑:
第一,节点状态一直是NotReady。原因通常是网络插件没装好、kubelet没正常启动、containerd的问题。检查链路是:kubectl get nodes看状态,systemctl status kubelet看服务,journalctl -u kubelet -f看日志,最后再看网络插件Pod的状态。
第二,Pod一直Pending。大多数情况是节点资源不足,或者有污点(taint)导致调度不上。用kubectl describe pod看事件,如果显示0/3 nodes are available,那大概率是资源问题。
第三,镜像拉取失败ImagePullBackOff。在国内网络环境下太常见了。解决办法:一是配置镜像加速,二是去能访问的机器上手动docker pull再导入,三是修改YAML文件里的镜像地址为国内镜像源。
第四,Master节点不能调度Pod。这是默认行为,K8s为了安全起见会给控制平面打上污点,只有DaemonSet一类特殊负载才能调度上去。如果你想在单机环境跑测试Pod,可以去掉污点,但正规场景不建议这么做。
第五,Service无法访问。如果外部访问不通,先检查NodePort端口范围是否正确(默认是30000-32767),再检查kube-proxy是否正常运行,最后检查安全组/防火墙是否放行了对应端口。
6. 网络插件和Dashboard:让集群变得更好用
这一步不是必须的,但装上之后体验会好很多。尤其对于还没有K8s可视化面板的同学,Dashboard可以帮你直观看到资源的运行状态。
6.1 网络插件具体二选一:Flannel与Calico怎么取舍
很多新手在这上面犹豫很久,我直接给一个结论:学习阶段首选Flannel,原因如下:
- 架构简单,VXLAN隧道方案,不需要额外依赖,部署完就能用
- 性能对学习和小规模部署来说完全够
- 排错链路短,无论是网络还是日志,网上资料都很多
Calico适合什么时候用?等到你要上生产,或者需要做基于NetworkPolicy的细粒度网络隔离的时候,再迁移到Calico也不迟。Calico基于BGP路由协议,三层的效率更高,功能也更丰富,但复杂性也上了一个台阶。
如果集群对外要暴露非常多的服务,还可以考虑MetalLB这类负载均衡器插件,不过在虚拟机环境里先用NodePort就够了,后续再研究也不迟。
6.2 搭建K8s Dashboard可视化管理面板
Dashboard是K8s官方社区提供的Web UI。安装命令:
bash复制kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
默认情况下Dashboard是ClusterIP类型的Service,外部访问不到。改动它的Service为NodePort类型:
bash复制kubectl -n kubernetes-dashboard edit svc kubernetes-dashboard
把type改成NodePort,保存后执行kubectl get svc -n kubernetes-dashboard,就能看到映射出来的端口号。
Dashboard登录需要Token,创建一个管理员用户:
bash复制kubectl create serviceaccount admin-user -n kubernetes-dashboard
kubectl create clusterrolebinding admin-user --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:admin-user
kubectl -n kubernetes-dashboard create token admin-user
输出的那一长串Token就是登录凭据。整个面板把集群的节点状态、应用部署、日志查询都可视化出来了,对新手来说价值巨大。
7. 集群坏了怎么救:备份、恢复与重置
集群建好之后迟早会出问题。掌握备份、恢复和重置的技能,关键时刻能救命。
7.1 关键数据备份思路
集群里最重要的数据都在etcd里。备份etcd比备份一堆YAML文件实在得多,因为etcd里存着所有的配置、状态、资源定义。简单备份方法:
在控制平面节点上,用etcdctl命令:
bash复制ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /backup/etcd-snapshot.db
把生成的snapshot文件定期拷贝到远程存储,就是最简单有效的备份策略。
7.2 重置集群的正确姿势
如果集群完全搞坏了,别慌,重置往往比修要快得多。依次执行:
bash复制kubeadm reset -f
rm -rf /etc/cni/net.d
rm -rf ~/.kube
然后work节点也执行kubeadm reset -f,如果不执行,节点信息还残留在集群缓存里面,下次再搭集群可能冲突。这个清理路径我踩过好几次坑,发出来给大家参考。
注意:重置会清空etcd里的所有数据。如果集群已经上了一段时间、里面有不少业务数据,一定要先做快照备份再做重置。
8. 扩展思考:从搭建到运维,你的下一步是什么
当一个集群跑起来之后,新手往往会陷入迷茫:接下来干什么?这里我给几个思路,帮助你把“能跑”升级为“会用”。
首先,学会用Deployment的滚动更新和回滚。修改镜像版本,观察kubectl rollout status deployment/xxx的状态,再尝试用kubectl rollout undo回滚到上一个版本,这是日常发布的基础。
其次,学会用ConfigMap和Secret管理配置。不要再把环境变量和密码写在Deployment的YAML里,把这些配置从应用镜像中解耦出来是容器化的关键一步。比如用ConfigMap配置nginx的server块,挂载到Pod里,可以做到改了配置重启即生效。
再次,尝试搭建Ingress Controller。NodePort对外暴露服务在小规模场景够用,但当一个节点上有几十个服务时,NodePort会占用大量端口,而且不具备7层路由能力。Ingress相当于集群的L7网关,把不同域名的请求转发到对应的Service上,这一块很值得花时间研究。
最后,如果有条件,可以再做一次从Pod网络到Service网络再到Ingress的三层网络数据流分析。分别在Pod、节点和Service层做tcpdump,你会对K8s网络有质的理解。绝大多数网络排错高手,都是这么一步步练出来的。
搭建集群只是一个开始,把集群用起来、用好才是真正的学习过程。
整套流程走下来,如果你没有再被我上面列的那些坑绊倒,说明你的集群已经真正属于你了。个人经验是:搭建过程遇到问题非常正常,我自己第一次搭集群也花了整整两天才把所有节点变为Ready。最有效的排错姿势是养成看kubectl describe和journalctl日志的习惯,这两件东西会在之后漫长的运维生涯里一直陪伴你。最后再分享一个小技巧:每敲一条kubeadm或kubectl命令后,多等几秒再判断结果,K8s是异步系统,很多状态更新要等组件sync,太着急反而容易误判。祝你的第一套集群顺利跑起来。
