news 2026/9/26 16:52:18

K8s集群环境配置全指南:从主机规划到kubeadm初始化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
K8s集群环境配置全指南:从主机规划到kubeadm初始化

搞K8s集群,第一步就是配置环境,但很多人恰恰是在这一步被劝退的。网上教程一抓一大把,版本新旧混杂,照着敲命令动不动就报错,折腾一天可能连kubelet都起不来。我自己前前后后搭过好几套集群,从单机测试到多节点生产环境都踩过不少坑,这篇内容是把环境配置阶段的完整思路和操作细节梳理出来,按照一套可复现的标准流程走一遍,把为什么要这么配、哪些参数是关键的、哪些坑是必踩的都讲清楚。这个系列会按阶段拆开写,这是第一篇,专注把底层环境全部准备好,适合刚接触K8s、准备自己动手搭集群,或者搭到一半卡在初始化之前的朋友参考。

1. 主机规划与版本选型思路

1.1 节点角色怎么分

K8s集群不是随便拿几台机器跑起来就行,节点角色和资源规划直接决定了后面高可用和调度能力的上限。常见的分法是Master节点和Worker节点,Master负责API Server、调度器、控制器这些大脑组件,Worker负责真正跑业务容器。我按三台Master加若干Worker的规模来规划,这套配置在学习阶段够用,后续要扩Worker也方便。

节点角色主机名建议配置建议数量
Masterk8s-master01/02/034C8G,系统盘50G以上3
Workerk8s-worker01/028C16G,系统盘100G以上2

生产环境里Master节点不建议跑业务负载,学习环境压力不大,Master资源压力也不明显。硬盘这块我特别注意过,K8s的镜像、容器日志、etcd数据都很吃空间,系统盘低于50G,跑一段时间就会报警。还有一点,所有节点要求有两块网卡的话配置会灵活一点,主机名规划阶段就把名字定好,后面很多配置直接依赖主机名。

1.2 版本组合别乱配

版本选型是整个环境配置里最需要动脑子的部分。很多人图省事直接装最新版,结果组件之间版本不兼容,报错信息看不懂,排查半天。我用的组合是Kubernetes 1.28.2、containerd 1.7.13、Calico 3.26,操作系统选择Rocky Linux 9.2,这套组合在社区生态和稳定性上很成熟,网上踩坑案例也齐全。

版本选择的逻辑有三点。第一,K8s的版本支持周期是12个月左右,1.28这个版本在功能、稳定性、文档完整度上都处于成熟期。第二,容器运行时用containerd而不是Docker,K8s从1.24版本开始就彻底移除了dockershim,直接使用containerd作为默认运行时,这是主流趋势,现在新装集群再配Docker反而是绕远路。第三,Calico网络插件对版本的要求不苛刻,但保持和K8s主版本接近,减少兼容性问题。

1.3 网段规划提前定

网段规划是环境配置环节最容易被忽视、后期出问题最头疼的点。K8s内部涉及两个虚拟网段,一个是Pod网段,一个是Service网段,另外还要预留出物理网络不冲突的地址段。我习惯用Pod网段10.244.0.0/16,Service网段10.96.0.0/12,这两个网段是社区里的默认值,Calico和Flannel都能直接兼容。

规划前先确认物理网络的CIDR,比如公司内网是192.168.1.0/24,那就避开这个段,用10.x段就不会冲突。后面如果要用MetalLB这类方案暴露外部访问IP,还要规划好可用IP池,别在环境配置阶段就把地址段占死。这个细节我在实际部署Master节点初始化时踩过,Pod网段和物理网段冲突会直接导致容器网络起不来,每个Pod都拿不到IP,排查起来非常痛苦。

2. 操作系统基础配置是一切的根基

2.1 主机名、hosts、防火墙清理

操作系统装好之后,第一件事是设置主机名。K8s节点之间的通信依赖主机名解析,主机名乱写会导致节点的标识混乱,日志里看起来全是莫名其妙的主机名。我习惯在主节点上把所有节点的hosts条目都写进去。

hostnamectl set-hostname k8s-master01

然后在每台机器上编辑/etc/hosts,加入所有节点的主机名和IP对照,三台Master的域名解析记录我提前写好,后面做高可用时直接用域名通信,不用记IP:

cat >> /etc/hosts <<EOF 192.168.1.101 k8s-master01 192.168.1.102 k8s-master02 192.168.1.103 k8s-master03 192.168.1.201 k8s-worker01 192.168.1.202 k8s-worker02 EOF

防火墙这块,K8s集群内部要开很多端口,学习环境我直接关闭firewalld,减少干扰。别急着杠生产环境不能关防火墙,生产环境应该用云平台的安全组规则或者独立防火墙策略精确放行,而不是靠系统自带的firewalld做粗放管理。学习阶段最重要的是先把集群跑起来,网络问题排查的范围越小越好。

systemctl stop firewalld systemctl disable firewalld

2.2 关闭swap和SELinux的原因

swap和SELinux这两个东西,是K8s初始化时最常见的两个拦路虎。先看swap为什么必须关。Kubernetes的kubelet在运行时会根据节点上的内存资源做调度决策,如果开启了swap,kubelet无法准确判断节点可用内存,导致调度器把Pod调度到一个实际上内存压力很大的节点上,系统性能就会很诡异。官方要求的做法是禁用swap,这个没得商量。

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

sed命令把/etc/fstab里的swap行注释掉,保证重启后swap不会自动挂载回来。不注释存在一个隐患:重启后swap重新启用,kubelet直接报错起不来。这个坑我遇到太多次了,每次复制系统镜像到新机器都会忘记检查fstab。

SELinux的作用是强制访问控制,K8s组件对文件系统的访问模式很特殊,SELinux的默认策略会拦截很多K8s组件的文件操作,导致各种Permission denied。学习阶段直接设置成permissive模式,别改成disabled,因为disabled之后如果要恢复SELinux,需要重启并且重新打标签,permissive模式只是记录违规但不拦截,后面排查问题时还能从SELinux日志里看到线索。

sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

改完配置后先setenforce 0让当前会话立即生效,重启后再检查配置确认状态。

2.3 内核模块与关键参数

K8s的容器网络依赖Linux内核的overlay和br_netfilter模块。overlay文件系统是容器镜像分层存储的基础,br_netfilter让Linux网桥上的流量也能经过iptables过滤,K8s的Service转发依赖iptables规则来处理流量。先加载模块,再配置参数让重启后自动加载:

modprobe overlay modprobe br_netfilter cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF

接下来是内核参数,这几个参数直接关系到K8s网络转发和iptables规则是否正确生效。我见过不少集群初始化成功但跨节点Pod网络不通,最后查到就是net.ipv4.ip_forward没有开。把配置写入/etc/sysctl.d/k8s.conf并执行sysctl --system:

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 net.ipv4.conf.all.forwarding = 1 EOF sysctl --system

sysctl --system是读取所有配置目录并应用,执行完成后可以用sysctl net.ipv4.ip_forward确认当前值已经是1。注意bridge-nf-call-iptables这个参数依赖br_netfilter模块,如果模块没加载成功,设置参数时系统会提示文件不存在,这就是排查思路的起点。

2.4 时间同步与基础依赖

K8s整套体系非常依赖证书和时间的准确性。etcd、kubelet、apiserver之间的通信都用TLS证书,证书的有效期校验要靠系统时间,如果节点间时间漂移超过几秒,集群直接报x509证书校验失败,这种错误最容易让人误判成证书过期,实际只是时间不对。我建议所有节点统一配置chrony时间同步,指向同一台NTP服务器。

dnf install -y chrony systemctl enable --now chronyd

另外把基础工具装齐,包括net-tools、vim、wget、curl、ipvsadm这些。ipvsadm是给kube-proxy的IPVS模式准备的,虽然不装也能跑iptables模式,但在节点数量多了之后IPVS的性能优势会很明显。配置内核参数开启IPVS的负载均衡支持,这个在环境配置阶段准备好,后续kubeadm init时直接加--proxy-mode=ipvs参数:

dnf install -y ipvsadm ipset cat <<EOF | sudo tee /etc/sysctl.d/k8s-ipvs.conf net.ipv4.conf.all.arp_ignore = 1 net.ipv4.conf.all.arp_announce = 2 EOF sysctl --system

每个节点都要做全这些操作,Master和Worker没有区别。我建议写好一个shell脚本,在每台机器上执行,这一步减少大量重复劳动,也避免某台机器漏配参数。

3. 容器运行时换成containerd

3.1 为什么不用docker做运行时

K8s早期版本默认用Docker作为运行时,那时候kubelet通过dockershim与Docker通信,接口层复杂还有额外性能损耗。K8s在1.24版本之后正式移除了dockershim,容器运行时直接通过CRI接口对接,containerd就是目前最主流的CRI运行时实现。它比Docker少一层守护进程,资源占用更小,部署Pod的链路更短,排查问题也少一环。

很多初学者习惯先装Docker再装K8s,这个思路在现在的新版本里其实没必要。K8s集群的运行时只需要containerd,业务容器如果需要Docker构建镜像,可以在开发环境单独装,集群节点上没必要。我甚至见过有人装了Docker又把containerd也装上,两个运行时抢占cgroup资源,kubelet起不来的情况。

3.2 containerd二进制安装流程

安装containerd我习惯直接用官方release包,它自带了runc和CNI插件,省去自己拼装的麻烦。使用cri-containerd-cni包,解压后会自动把containerd、runc、CNI插件放到对应目录。

wget https://github.com/containerd/containerd/releases/download/v1.7.13/cri-containerd-cni-1.7.13-linux-amd64.tar.gz tar Cxzvf / cri-containerd-cni-1.7.13-linux-amd64.tar.gz

解压完成后,把containerd的服务管理文件放到/etc/systemd/system/目录。我通常直接复制release包里的containerd.service到系统目录,然后执行systemctl daemon-reload。这里如果跳过这一步,containerd服务根本找不到启动脚本,systemctl start会提示unit not found。

systemctl enable --now containerd

启动之后用ctr version验证版本,用systemctl status containerd看运行状态。接下来是生成配置文件,containerd首次启动不会自己生成配置,直接启动会使用内置默认值,但内部CRI配置、sandbox镜像地址都不能改,所以必须手动生成:

mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml

3.3 SystemdCgroup与sandbox_image两个关键配置

生成的config.toml里有几个关键点必须改。第一是把SystemdCgroup改成true。为什么必须改?因为K8s推荐使用systemd作为cgroup驱动,而containerd的默认配置是cgroupfs。如果运行时用cgroupfs而kubelet用systemd,两边对cgroup的接管方式不统一,Pod启动后资源限制失效,甚至kubelet直接报错说cgroup驱动不匹配。

第二个关键点是sandbox_image,这个是Pod的pause容器镜像地址。默认配置写的是registry.k8s.io/pause:3.8,国内网络环境拉不下来,初始化时会在拉镜像阶段卡住。改成国内镜像源:

sed -i 's#registry.k8s.io/pause:3.8#registry.aliyuncs.com/google_containers/pause:3.9#' /etc/containerd/config.toml

网上的仓库地址各有不同,我用的是阿里云镜像仓库的pause镜像。改完配置之后重启containerd,再验证一下配置是否生效:

systemctl restart containerd ctr images list

还要检查一下CRI插件的日志,用crictl ps看能不能和containerd通信。crictl命令如果提示找不到,需要在/etc/crictl.yaml配置里指定runtime-endpoint,containerd的CRI默认监听unix:///run/containerd/containerd.sock。

cat <<EOF > /etc/crictl.yaml runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 3 EOF

到这一步,每台机器的容器运行时都准备好了。注意,Worker节点不需要额外安装其他运行时,containerd一套搞定所有节点的Pod生命周期管理。

4. kubeadm、kubelet、kubectl三件套

4.1 yum源的选择与版本锁定

三个核心组件中,kubelet是节点上的代理服务,kubeadm是集群初始化的工具,kubectl是命令行管理工具。这三个必须装在同一组版本上,版本不一致会导致API接口不兼容,最典型的错误是kubelet和apiserver的版本差距过大,节点加入集群时报错。我建议直接用官方Kubernetes rpm源,这个源支持Rocky Linux 9系统,配置起来也很直接。

创建/etc/yum.repos.d/kubernetes.repo:

cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/ enabled=1 gpgcheck=1 gpgkey=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/repodata/repomd.xml.key exclude=kubelet kubeadm kubectl EOF

这个源里的repodata key会随着版本变动,直接用官网文档里的当前地址就行。安装命令加上版本号,不允许装这个源里最新版,防止多个节点装到不同小版本:

dnf install -y kubelet-1.28.2-0 kubeadm-1.28.2-0 kubectl-1.28.2-0

装完后立刻锁定版本。我用dnf versionlock来锁:

dnf install -y python3-dnf-plugin-versionlock dnf versionlock add kubelet kubeadm kubectl

锁定版本这个操作太重要了。你想象一下,某天执行dnf update系统更新,kubelet跟着升级到1.30版本,而集群apiserver还是1.28,节点加入时直接报版本不匹配,整个集群的加入逻辑全部卡住。我在一个测试环境里吃过这个亏,kubelet版本比apiserver新,节点调度过来后容器反复重启。

安装完成后让kubelet开机自启,但不要现在启动它,因为还没有集群配置,现在启动只会报错。这个细节后面再说:

systemctl enable kubelet

4.2 初始化参数逐项说明

所有前置步骤都完成后,在第一台Master节点上执行kubeadm init。这个命令的参数基本上决定了集群的网络模型、证书体系和控制面地址。把参数拆开看:

kubeadm init \ --kubernetes-version=v1.28.2 \ --image-repository=registry.aliyuncs.com/google_containers \ --control-plane-endpoint=k8s-master01 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12

每项参数的含义:

  • --kubernetes-version必须和前面装的kubeadm版本一致,不一致时kubeadm会尝试从yum仓库里拉对应版本,但可能因为版本锁定导致失败。
  • --image-repository指定镜像仓库地址,默认从registry.k8s.io拉取控制面镜像,国内网络根本拉不动,换成阿里云镜像仓库保平安。
  • --control-plane-endpoint这里我直接写了master01的主机名和IP,它表示控制面的统一入口。学习环境先用单机入口,后续做高可用时再换成负载均衡器的虚拟IP加域名。
  • --pod-network-cidr是Pod网段,要和后面装的Calico配置保持一致,用10.244.0.0/16就没有冲突。
  • --service-cidr是Service网段,10.96.0.0/12也是社区默认值。

你也可以加上--apiserver-advertise-address参数指定apiserver对外通告的IP,默认会自动选择节点上的默认路由IP。多网卡的环境必须显式指定这个参数,否则apiserver暴露的IP是错的,其他节点根本连不上6443端口。

初始化过程会自动拉取镜像并启动控制面组件,整个过程大约三到五分钟。执行完成后,输出结尾会有两段指令,一段是kubeconfig配置命令,一段是Worker节点加入集群的命令,这两段都先保存下来。

4.3 初始化后验证与kubectl配置

初始化输出成功后,先把kubectl的配置文件拷贝到当前用户目录,不配置的话kubectl连接集群时找不到证书:

mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config

检查集群状态:

kubectl get nodes kubectl get pods -n kube-system

这个时候有个很常见的情况:Master节点状态是NotReady,coredns和etcd相关Pod显示Pending。千万别慌,这不是集群坏了,是还没安装CNI网络插件,节点没有网络插件驱动,Pod调度不到可运行的网络环境里。在装好Calico之前,NotReady是正常状态,coredns起不来也是正常的。

验证控制面组件是否正常,看kube-system命名空间里这几个核心Pod有没有Running,etcd、apiserver、controller-manager、scheduler这四个起来就说明控制面没有大问题。网络问题就等CNI装完再看。

我在环境配置阶段通常会再多做一个验证:把第二个Master节点和Worker节点通过kubeadm join加入集群。这样能验证节点之间的网络通道、证书分发是否正常。执行加入命令时要带上--v=5参数查看详细日志,出错时能看到具体卡在哪个阶段。加入命令按初始化输出末尾的模板来,不要自己拼命令,证书token和CA证书hash值都在输出里。

5. 环境配置阶段常见问题速查

5.1 卡在拉镜像与网络无关的排查

初始化卡住是出现频率最高的问题。执行kubeadm init后一直停在拉镜像的阶段,进度条不动,这时候很多人去检查网络是否通。实际上镜像仓库的网络连通性没问题,先确认当前kubeadm用的是哪个仓库,执行kubeadm config images list看输出地址,如果地址是registry.k8s.io开头,说明你忘记加--image-repository参数了,或者参数没有正确传入。

另一个坑是版本参数和镜像不匹配。--kubernetes-version=v1.28.2和yum源里装的kubeadm版本必须严格一致,kubeadm会根据这个版本去拼镜像tag。如果装的是1.28.2-0,但init写的是v1.28.3,kubeadm就会去拉1.28.3的镜像,仓库里可能没有这个tag,卡住就很正常。

建议先把镜像预先拉下来。这样init执行时如果镜像都拉好了,集群初始化时间会缩短很多,排查拉镜像问题也更简单:

kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers

5.2 kubelet日志与CNI状态判断

kubelet服务没有启动、不断重启,这是初始化不成功的直接表现。排查顺序是从kubelet日志开始,logs命令拿到实时日志,kubelet的错误信息是很直白的:

journalctl -u kubelet -f

日志里最常见的几类错误。第一类是not found或者permission denied,优先检查SELinux状态,确认是permissive,然后看containerd的cgroup驱动配置。第二类是container runtime is down,说明kubelet连不上containerd,检查containerd服务状态以及crictl是否能正常通信。第三类是节点上存在旧的集群信息,如果你之前重置过一次,kubelet可能还在用旧的证书尝试连接apiserver,这时候需要完整执行kubeadm reset清理环境再重新初始化。

CNI状态的判断逻辑要清楚。kubectl get nodes看到NotReady,先看节点上的Pod状态,执行kubectl describe node观察Conditions部分输出。CNI没装好时节点状态显示NetworkUnavailable,这是正常现象。装完Calico之后如果还是NotReady,就要检查Calico的Pod是否Running,以及Pod网段和节点所在物理网段是否冲突,冲突会导致Calico的BGP邻居起不来。

5.3 重置环境的标准操作

环境配置阶段的错误往往需要反复重来,掌握标准的重置流程能省掉大量时间。我见过有人直接删除/etc/kubernetes目录、清空containerd里的镜像、手动杀掉所有残留进程,这些都是野路子,容易留下隐性问题,后续每次初始化都出怪毛病。

标准做法是:

kubeadm reset -f

这条命令会清理集群配置、清空CNI相关配置、停止kubelet服务。执行完成后再手动清理网络配置残留:

rm -rf /etc/cni/net.d

最后清掉containerd里残留的pause容器和系统镜像组,这个看实际情况,如果kubeadm reset执行后仍有残留容器影响初始化,就重新排查。确认干净之后重新执行kubeadm init。

还有一个细节:重置时如果kubelet一直在重启,系统日志会刷屏,可以先停掉kubelet再执行reset。reset完的节点再加入新集群时,token和CA信息都是全新的,不会互相污染。

搞完这篇之后,下一阶段就是安装Calico网络插件、验证Pod网络的跨节点通信,然后做高可用控制面的负载均衡配置。环境准备阶段做扎实了,后面每一步都会顺畅很多。至少我从这套流程里得到的体会是,环境配置阶段最值得花时间的地方是理解每个参数的行为,而不是照抄命令,参数理解透了,后面集群出问题时排查方向就不会乱。

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

CUPP集成实战:从字段词根到自定义弱口令词库生成

1. CUPP工具的使用边界&#xff1a;它是审计助手&#xff0c;不是无脑扫描器最近接到一个内部安全审计需求&#xff0c;要对公司一套核心业务系统的口令强度做全面评估。常规弱口令扫描器跑完第一轮&#xff0c;报告里基本都是123456、admin、password这类“全民通用型”弱口令…

作者头像 李华
网站建设 2026/9/26 16:52:16

车云协同中枢的1% low帧思维:高可靠与低延迟如何兼得

做车路协同项目这两年&#xff0c;我最深的体会是&#xff1a;智能驾驶和车云协同这种系统&#xff0c;最怕的不是“慢”&#xff0c;而是“忽快忽慢”。有一回我们在测试远程云接管&#xff0c;均值时延才 60ms 出头&#xff0c;数据看上去非常漂亮&#xff0c;结果驾驶员反馈…

作者头像 李华
网站建设 2026/9/26 16:51:45

Atlas 300V 24G深度解析:从环境搭建到YOLOv5推理部署实战

最近总有人问我同一个问题&#xff1a;Atlas 300V 24G到底是不是一张运算加速卡&#xff1f;它能跑YOLO吗&#xff1f;怎么部署&#xff1f;类似的问题这半年里我被问了不下十次。原因很简单&#xff0c;这块卡名字里带着一个“V”&#xff0c;长得又跟显卡差不多&#xff0c;不…

作者头像 李华
网站建设 2026/9/26 16:51:42

昇腾Atlas 300V部署YOLO实战:环境搭建、模型转换与推理优化

1. Atlas 300V 24G 到底算什么卡&#xff1a;这张卡的定位比参数重要得多先说结论&#xff1a;Atlas 300V 24G 是一张推理加速卡&#xff0c;不是通用运算加速卡&#xff0c;也不是训练卡。这个区别搞不清楚&#xff0c;后面部署项目的时候会走很多弯路。我最初接触 Atlas 300V…

作者头像 李华
网站建设 2026/9/26 16:50:30

dsprop.dll丢失报错修复指南:SFC、DISM与系统还原全解

这个问题我遇到过太多次了&#xff0c;不管是帮朋友修电脑&#xff0c;还是自己在折腾旧软件、老游戏的时候&#xff0c;十次有八次都会撞见类似的报错——dsprop.dll文件丢失找不到。弹窗一出&#xff0c;程序闪退&#xff0c;界面卡死&#xff0c;拿它一点办法没有。很多人的…

作者头像 李华
网站建设 2026/9/26 16:50:08

Windows C/C++开发者必备:MinGW GCC 12.2.0配置与诊断指南

简介&#xff1a;Windows 64位平台可用的MingW GCC 12.2.0 完整编译工具链&#xff0c;面向需要在Windows上编译C/C项目、却不想依赖Visual Studio的开发者。此包集成GCC编译驱动、MinGW-w64运行库、标准库头文件与静态/导入库&#xff0c;支持C20及POSIX线程&#xff0c;可与C…

作者头像 李华