news 2026/10/14 15:06:48

kubeadm搭建K8S集群实战:CentOS 7.6部署v1.14.2

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
kubeadm搭建K8S集群实战:CentOS 7.6部署v1.14.2

这两年身边越来越多团队开始把服务迁到容器平台,Kubernetes几乎成了基础设施领域绕不开的名词。但真正从零把一个集群搭起来,对新手来说仍然有不少门槛,网上的教程要么版本太老、命令和现有环境对不上,要么关键步骤一笔带过,照着做很容易卡在半路。这篇记录我用一个下午,在3台CentOS 7.6虚拟机上从零部署一个K8S v1.14.2集群的完整过程,包含所有命令、参数解释、环境配置和踩过的坑,目标是让照着操作的读者也能完整跑出一个能用的集群。

写这个系列之前我给自己定了个规则:每篇解决一个具体问题,这篇是第0篇,先把集群搭起来,后续存储、网络、监控、版本升级再一个个补。版本选v1.14.2并不是因为它新,恰恰是因为很多生产环境还在用老版本,而且老版本的kubeadm命令相对直白,对理解K8S核心概念更友好。适合刚接触K8S、想有一套自己的环境练手的人,也适合正在维护老版本集群、需要快速翻查操作命令的运维同学。

我尽量用说话的方式写,把每一步为什么这么做都交代清楚。遇到参数,我会解释参数背后的逻辑;遇到坑,我会把表象、原因和解决路径连起来讲,而不是只丢一句“执行这条命令就好”。

1. 先想清楚:集群怎么规划才合理

1.1 版本组合和部署方式是关键决定

K8S部署最忌讳的是没有全局概念就照着命令抄。版本、操作系统、容器运行时、网络插件、Pod网段这几样是强耦合的,改一个,后面全都得跟着改。这次组合是CentOS 7.6 + Docker 18.09 + Kubernetes v1.14.2 + Flannel,这套组合在当时是经过大量环境验证的,放到现在跑也还算顺。CentOS 7.6的内核是3.10,本身不是新内核,但K8S对内核版本的要求并不高,只要关键模块和参数到位就能跑。

部署方式选kubeadm而不是二进制手装,原因很简单:kubeadm把证书生成、组件配置、健康检查这些繁琐环节都自动化了,能把一两天的工作压缩到半小时。当然,kubeadm本身也在不断变化,1.14.2版本的init参数和现在的新版本已经有很多区别,网上搜到的教程如果没标明版本,很可能就是坑。所以我在下面所有命令里都把版本参数写死,保证可复现。

1.2 节点的角色划分和资源底线

最小可用集群至少需要一台Master和一台Worker。Master承担集群控制面,跑的组件有etcd、kube-apiserver、kube-controller-manager、kube-scheduler,Worker才是真正跑业务Pod的地方。我这里准备了三台机器,一台Master加两台Worker,配置分别是2核CPU、4G内存、20G磁盘。

节点角色主机名硬件规格IP地址
Masterk8s-master2C4G192.168.10.10
Worker1k8s-node12C4G192.168.10.11
Worker2k8s-node22C4G192.168.10.12

这个规格是底线,再低就容易出幺蛾子。有人用1G内存的虚拟机试过,kubeadm init过程中etcd直接OOM,日志里全是连接超时。如果只是个人学习,可以适当降低Worker数量,但Master的2C4G不建议再缩,控制面组件同时跑起来,内存确实吃紧。

1.3 网络规划:Pod网段、Service网段、节点网段要分清

新手最容易搞混的是三个网段:节点网段是虚拟机之间的物理网络,Pod网段是给Pod分配的虚拟IP池,Service网段是给Service分配的虚拟IP池。它们互不重叠,全靠iptables或IPVS规则做转发。我在本文里的取值是:节点网段192.168.10.0/24,Pod网段10.244.0.0/16,Service网段10.96.0.0/12。Pod网段选10.244.0.0/16是因为Flannel的部署清单默认就用这个网段,如果初始化时用了别的值,后面还得手动改yaml,属于给自己找事。

2. 装集群前的基础环境准备

2.1 主机名与hosts解析配置

集群内部节点之间要互相通信,先把主机名和hosts配好,不然后续看日志、执行kubectl都容易搞混。三台机器分别执行:

# Master节点 hostnamectl set-hostname k8s-master # Worker1节点 hostnamectl set-hostname k8s-node1 # Worker2节点 hostnamectl set-hostname k8s-node2

然后每台机器的/etc/hosts都要加上三行解析:

192.168.10.10 k8s-master 192.168.10.11 k8s-node1 192.168.10.12 k8s-node2

这里特别提醒一下,很多人配了/etc/hosts之后不做任何验证,结果后面kubeadm init时apiserver长时间无法就绪,折腾半天才发现是主机名解析不对。配完马上ping一轮,确保三台机器两两互通,这是最廉价的排错方式。我习惯用ping -c 2 k8s-master这种带主机名的方式验证,既能检验网络又能检验DNS解析。

2.2 关闭防火墙与SELinux

K8S的kube-proxy会通过iptables规则做服务负载均衡,如果系统自带firewalld和安全策略还开着,经常会出现“服务明明存在,但访问就是不通”的现象。这次部署直接做干净:关闭firewalld并禁止开机启动,关闭SELinux。

systemctl stop firewalld systemctl disable firewalld # 临时关闭SELinux setenforce 0 # 永久关闭,修改配置文件 sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

这里有个小细节:sed改完配置文件,一定要等下次重启才完全生效。如果只想在本次部署中临时关闭,setenforce 0就够了。但如果忘了改配置文件,服务器一重启,SELinux又回来了,到时候Node节点怎么都加入不了集群,排查起来非常头大。实测过太多次这种“重启后环境失效”的情况,所以这两条命令必须同时执行,缺一不可。

2.3 关闭swap

K8S从早期版本开始就要求节点关闭swap,因为kubelet在做资源管理和Pod内存限制时,依赖的是物理内存与cgroup的映射关系,一旦启用swap,内存回收和OOM判定就乱了套。v1.14.2的kubelet默认会检测swap,开着swap直接不让启动。

关闭操作:

swapoff -a # 注释掉/etc/fstab里的swap行,防止重启后恢复 sed -i '/ swap / s/^/#/' /etc/fstab

用free -h确认一下,Swap一行为0就说明生效了。顺带说一句,如果是虚拟机环境,有些虚拟化平台自己会再包一层swap,这个不用去动,只要系统层面的swap关掉就行,两者不是一回事。

2.4 内核网络参数调整

K8S的Pod网络依赖iptables对桥接流量的处理。CentOS 7.6默认的网桥过滤规则没有启用,如果不开启,后续Pod跨节点通信会莫名失败。需要修改/etc/sysctl.d/k8s.conf:

cat > /etc/sysctl.d/k8s.conf <<EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF

还要先加载br_netfilter模块,不然上面的参数根本不存在,执行sysctl --system时会报错:

modprobe br_netfilter echo "modprobe br_netfilter" >> /etc/rc.local chmod +x /etc/rc.local sysctl --system

顺带确认ip_forward也是开启状态,K8S很多网络组件都依赖它:

sysctl -w net.ipv4.ip_forward=1 echo "net.ipv4.ip_forward=1" >> /etc/sysctl.d/k8s.conf

这几项配置做完之后,我建议直接重启一遍系统,再进系统检查一遍防火墙、SELinux、swap、内核参数是不是都保持在预期状态。这一步虽然多花几分钟,但能过滤掉一批“重启后配置丢失”的问题,后面部署会顺畅很多。

3. Docker与Kubernetes组件安装

3.1 Docker版本选择与安装

K8S v1.14.2对Docker版本有兼容范围,官方当时支持的是Docker 18.09。我没有故意选老版本,而是要匹配kubelet的版本检测逻辑——太新的Docker在某些老版本K8S上会输出非致命警告,看起来总归膈应。安装过程分三步:配置Docker yum源、安装指定版本、启动并调整配置。

# 配置Docker安装源 # 这里需要根据你所在网络环境可访问的源地址来替换 cat > /etc/yum.repos.d/docker.repo <<EOF [docker-ce-stable] name=Docker CE Stable baseurl=你的可用Docker源地址 enabled=1 gpgcheck=0 EOF # 查看可安装版本,锁定18.09 yum list docker-ce.x86_64 --showduplicates | sort -r yum install -y docker-ce-18.09.9-3.el7 systemctl enable docker systemctl start docker

装完之后,我习惯把Docker的cgroup driver改成systemd。K8S官方推荐Docker和kubelet的cgroup驱动保持一致,都用systemd,避免节点上同时存在两份cgroup管理逻辑,导致资源统计和回收时互相干扰。

cat > /etc/docker/daemon.json <<EOF { "exec-opts": ["native.cgroupdriver=systemd"] } EOF systemctl daemon-reload systemctl restart docker

这里有件事我必须强调:daemon.json不是必须的,不写也能跑,但如果不写,Docker默认的cgroup driver是cgroupfs,kubelet又是systemd,两者不一致时节点上的资源统计经常会出偏差,严重时Pod会被反复驱逐。既然官方文档都推荐统一成systemd,那就别给自己埋雷。

3.2 安装kubeadm、kubelet、kubectl

Kubernetes三件套,kubeadm负责初始化集群和生成令牌,kubelet是每个节点上真正干活的代理进程,kubectl是命令行管理工具。三台机器都需要安装,包括Master和Node。

同样需要先配置Kubernetes的yum源,然后把三个组件的版本锁在1.14.2,避免yum自动升级导致组件之间版本不一致:

# 配置Kubernetes安装源 # 把baseurl替换为你环境中可访问的源地址 cat > /etc/yum.repos.d/kubernetes.repo <<EOF [kubernetes] name=Kubernetes baseurl=你的可用Kubernetes源地址 enabled=1 gpgcheck=0 EOF yum install -y kubeadm-1.14.2-0 kubelet-1.14.2-0 kubectl-1.14.2-0 # 设置开机自启,但先不启动 systemctl enable kubelet

这里有个坑:kubelet装上后不要手动systemctl start。它因为缺少kubeadm生成的配置文件,启动后大概率会反复重启(CrashLoopBackOff),这是正常现象,等kubeadm init之后配置文件落位才能正常跑起来。新手看到kubelet起不来就各种折腾,最后发现其实没事,白费半天劲。

4. Master节点初始化

4.1 初始化前先确认镜像清单

kubeadm init实际要做的事,是把集群控制面组件以Pod的形式跑起来。所以执行init之前,需要把对应版本的镜像拉到本地。先用命令查看它需要哪些镜像:

kubeadm config images list --kubernetes-version=v1.14.2

输出里会有kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy、pause、etcd、coredns这几个。其中pause镜像特别容易被忽略,它是每个Pod里最先启动的“基础设施容器”,所有业务容器都挂靠在它上面。要是没有事先准备好pause,后面所有Pod都会卡在ContainerCreating。

默认情况下,kubeadm会从一个固定仓库拉取这些镜像,但那个地址在部分网络环境下访问速度很慢甚至超时。所以我在初始化时加了--image-repository参数,指定到一个网络可达的镜像仓库路径。这里没有任何神秘技巧,就是换一个能拉通的镜像源而已。

4.2 kubeadm init完整执行

Master节点执行初始化命令。在动手之前,先把几个参数讲清楚:

kubeadm init \ --apiserver-advertise-address=192.168.10.10 \ --image-repository=你确认可用的镜像仓库路径 \ --kubernetes-version=v1.14.2 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12
  • --apiserver-advertise-address:Master节点对外提供API服务的地址,就填Master的IP,别填错成Node的。
  • --image-repository:镜像仓库路径,替换成你实际能拉到的地址。
  • --kubernetes-version:要匹配已经安装的kubeadm版本。
  • --pod-network-cidr:Pod网段,我选的10.244.0.0/16,对应后面Flannel默认网段。这里和网络插件强相关,如果之后想换Calico,网段通常不同,所以要先决定网络插件再定数值。
  • --service-cidr:Service网段,默认10.96.0.0/12,一般不用动。

执行顺利的话,最后会输出一段信息,包括kubeconfig文件位置、部署网络插件的提示、以及把Node加入集群的命令。我的习惯是先把最后那段join命令完整复制下来,存到一个临时文件里,因为token默认有效期只有24小时,等要用的时候再找,命令可能已经过期。

4.3 配置kubectl并查看节点状态

初始化完成后,root用户需要配置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,正常情况下能看到Master节点处于NotReady状态。这个状态正常吗?正常。因为此时还没有安装Pod网络插件,集群内部通信还没打通。等网络插件部署完成后,它才会变成Ready。所以看到NotReady先别慌,继续往下走。

5. 部署Pod网络插件

5.1 为什么这次选用Flannel

Pod网络插件是K8S集群能正常工作的关键组件,负责给每个Pod分配IP并打通跨节点通信。可选方案很多,Flannel和Calico是两个主流,我这次选了Flannel,理由很直接:配置简单,资源占用小,且和前面规划的Pod网段直接对齐。

Calico功能更强,支持NetworkPolicy等精细网络策略,但对应的组件也更多,对刚搭好的环境来说,运维复杂度更高。先用Flannel把集群跑起来,后续需要网络策略时再迁移或叠加,是这个阶段更合理的路径。生产环境选型另说,但实验环境把复杂度降到最低是原则。

5.2 安装与状态验证

下载Flannel的部署清单,注意清单里的Network参数必须和kubeadm init时指定的pod-network-cidr保持一致。如果清单里写的是10.244.0.0/16,而我们初始化用的也是10.244.0.0/16,那就完美匹配,直接应用即可:

# 先下载Flannel配置 # 这里替换为你实际可获取的配置文件地址或缓存好的本地文件 kubectl apply -f kube-flannel.yml

部署后等待一两分钟,用下面命令查看kube-system命名空间的Pod状态:

kubectl get pods -n kube-system -o wide

重点看flannel的Pod是不是Running,以及节点上的kube-proxy是否Running。如果一切正常,再执行kubectl get nodes,Master的状态应该已经变成Ready。如果flannel的Pod一直Pending,优先看Pod的Events,多半是节点亲和或污点容忍没对上,这类yaml一般自带容忍配置,排查时要先看事件再下结论。

6. Worker节点加入集群

6.1 重新生成Join命令

kubeadm init完成时输出过一段join命令,如果当时没保存,或者token过期了,不用重新init,直接在Master上重新生成:

kubeadm token create --print-join-command

这条命令会输出类似下面的内容:

kubeadm join 192.168.10.10:6443 --token xxxxxx --discovery-token-ca-cert-hash sha256:xxxxxx

hash值会自动从集群的CA证书里计算出来,不需要手动处理。这里强调一下,token本身有时效性,如果token列表里已经有未过期的token,也可以直接复用,但更稳妥的方式是重新生成一条新鲜的。

6.2 在Node上执行加入操作

登录node1,先确认前置条件已经满足:防火墙关闭、SELinux关闭、swap关闭、Docker运行中、kubelet已安装。一条条过一遍,别嫌啰嗦,我见过太多人直接跳过去执行join,结果加不进来,回头排查才发现基础环境没准备好。

确认没问题后,直接执行上面生成的join命令。两台Node都执行一次。join成功后,节点会启动kubelet,并向Master注册。此时不要着急,kubelet首次启动需要拉取镜像、启动组件,耐心等上一两分钟是正常的。

6.3 验证集群节点状态

回到Master节点执行:

kubectl get nodes

如果看到三台机器都处于Ready状态,集群的基础建设就大功告成了。有时候Node会显示NotReady,原因是kube-flannel的Pod还没完成部署,多等一会再刷新即可。如果是join时卡在等待控制平面,先回到Master用kubeadm token list检查token是否真实有效。

7. 跑一个测试服务验证集群

7.1 部署Nginx测试Pod

集群搭好不代表真能用,必须跑一个业务容器来验证端到端链路。我这里先用nginx做冒烟测试:

kubectl create deployment nginx-test --image=nginx:1.14 kubectl get pods -o wide

观察Pod调度在哪个Node、状态是否为Running。如果想从集群外部访问到这个服务,再用NodePort方式暴露Service:

kubectl expose deployment nginx-test --port=80 --target-port=80 --type=NodePort kubectl get svc

得到Service的NodePort后,用浏览器访问任意一台Node的IP加这个端口,能看到Nginx欢迎页,就说明整个容器网络链路是通的。这时候还可以顺手验证一下Service的负载均衡效果,把nginx-test的副本数扩到3个,再反复访问端口,看请求是否会分布到不同Pod:

kubectl scale deployment nginx-test --replicas=3

虽然没有可视化界面直接展示流量去向,但通过kubectl get endpoints能看到后端Pod列表的变化,这已经能证明集群调度和Service转发都正常工作。

7.2 可选:安装Dashboard

很多初学者想装一个Web界面来看集群状态,K8S Dashboard确实直观,但v1.14.2对应的Dashboard版本和新版差异比较大,需要匹配版本号安装。如果你和我一样更习惯用命令行操作,可以先不装Dashboard,把kubectl用熟练,后面再补也不迟。等到后续需要做多租户隔离、权限管理的时候,再回过头来安装Dashboard会更理解它的价值。

8. 部署过程中的常见问题与排查

8.1 kubeadm init失败:端口被占用

如果之前有过一次不完整的初始化,或者同一台机器重复安装,6443、10259、10257这些端口可能残留占用。用ss -lntp查端口,找到对应PID后杀掉再重试。更彻底的办法是执行kubeadm reset清理现场,再重新走一遍init流程。

8.2 Node一直是NotReady

先看kube-system里的Pod:

kubectl get pods -n kube-system -o wide

如果flannel Pod处于ImagePullBackOff,基本就是镜像拉取问题,检查镜像仓库地址和网络连通性,或者手动把镜像拉好再让Pod重试。如果flannel是Running,则检查这台节点上的kubelet日志,路径一般是/var/log/messages,用journalctl -u kubelet -f实时观察更直观。还有一种隐蔽原因是节点时间偏差太大,导致证书校验失败,此时需要先同步时间再重启kubelet。

8.3 Pod一直ContainerCreating

最常见的原因是pause镜像没准备好,或者网络插件还没就绪。用kubectl describe pod查看Events,里面会写得很清楚。如果是sandbox image拉取失败,解决方式就是在所有节点上手动把pause镜像拉一遍,确认每个节点都有这个镜像。另一个常见元凶是DNS解析,coredns没起来的话,Pod内解析Service名会超时,表现为Pod反复重启,所以看到ContainerCreating先查coredns状态。

8.4 Join命令执行后没有反应

kubeadm join长时间卡住,多数情况是Master的6443端口连不通。在Node上telnet一下Master的IP和端口,能通再继续。如果发现不通,检查节点网段、防火墙规则有没有漏掉。另一个隐藏问题是Node系统时间与Master偏差太大,证书校验会失败,先同步时间再重试。

最后分享一个体会:K8S集群部署这类事情,最忌的就是东抄一段西抄一段。版本、网段、镜像仓库、内核参数这些都是连在一起的,有一个变量不一致,后面全是坑。照着这篇的顺序把基础准备做扎实,剩下的就只是时间问题了。我自己把同样的流程跑了不止一遍,机器从2台加到4台,除了IP和主机名有变化,其他没有任何区别。哪天你想验证什么新组件,多准备两台机器,复用这套流程,很快就能把环境搭出来。

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

多模态视觉+云端真机实操:AI助手如何从聊天框走向真干活

我见过太多号称“AI助手”的产品&#xff0c;打开就是聊天框&#xff0c;背后挂一个大模型API&#xff0c;用户问一句&#xff0c;它答一段。这种产品严格来说不能叫助手&#xff0c;只能叫“聊天机器人套了个壳”。今天我想认真聊一个正在被验证的新路径&#xff1a;多模态视觉…

作者头像 李华
网站建设 2026/10/14 15:06:17

Java Web三层架构企业简历管理系统:课设答辩实战解析

简介&#xff1a;一套基于Java Web的企业简历管理系统完整源码包&#xff0c;适合课程设计、毕业设计及Java初学者进阶练习&#xff0c;可直接用于毕业设计答辩演示。压缩包内共162个文件&#xff0c;包含55个java源码、17个jsp页面、10个jar依赖包、2个sql数据库脚本&#xff…

作者头像 李华
网站建设 2026/10/14 15:04:59

基于Vue和Spring Boot的在线考试系统全栈开发实践

1. 项目概述在线考试系统是教育信息化进程中的重要组成部分&#xff0c;它彻底改变了传统纸质考试的运作模式。作为一名参与过多个在线考试系统开发的技术人员&#xff0c;我想分享一个基于Web的完整解决方案&#xff0c;包含前端界面、后端逻辑和数据库设计的全栈实现。这个系…

作者头像 李华
网站建设 2026/10/14 15:04:58

WX‑0813/ AI‑ENC 降噪/ 100dB 回声消除 / 双 5W 功放/USB 免驱一站式语音

标签&#xff1a;# 语音模组 #AI 降噪 #AEC 回声消除 #DSP 音频 #嵌入式音频 #全双工对讲前言做对讲、会议、门禁、监控拾音类硬件&#xff0c;经常遇到几个老大难问题&#xff1a;环境噪声大、喇叭麦克风距离近回声严重、还要额外设计功放电路&#xff0c;主控平台多还需要适配…

作者头像 李华
网站建设 2026/10/14 15:04:54

背单词总忘怎么办黑龙江家长可试这三步

哈尔滨一位四年级家长跟我聊&#xff0c;孩子每晚抄单词抄到十点半&#xff0c;第二天听写还是错一半。她翻着本子给我看&#xff0c;每个词抄了二十遍&#xff0c;字迹工整&#xff0c;可合上本子就忘。这不是态度问题&#xff0c;是方法把“手在动、脑没动”当成了记忆。词汇…

作者头像 李华