资讯动态

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

发布时间:2026/10/14 15:06:51 来源:尧图企业网站定制
这两年身边越来越多团队开始把服务迁到容器平台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-schedulerWorker才是真正跑业务Pod的地方。我这里准备了三台机器一台Master加两台Worker配置分别是2核CPU、4G内存、20G磁盘。节点角色主机名硬件规格IP地址Masterk8s-master2C4G192.168.10.10Worker1k8s-node12C4G192.168.10.11Worker2k8s-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/24Pod网段10.244.0.0/16Service网段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 关闭防火墙与SELinuxK8S的kube-proxy会通过iptables规则做服务负载均衡如果系统自带firewalld和安全策略还开着经常会出现“服务明明存在但访问就是不通”的现象。这次部署直接做干净关闭firewalld并禁止开机启动关闭SELinux。systemctl stop firewalld systemctl disable firewalld # 临时关闭SELinux setenforce 0 # 永久关闭修改配置文件 sed -i s/^SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config这里有个小细节sed改完配置文件一定要等下次重启才完全生效。如果只想在本次部署中临时关闭setenforce 0就够了。但如果忘了改配置文件服务器一重启SELinux又回来了到时候Node节点怎么都加入不了集群排查起来非常头大。实测过太多次这种“重启后环境失效”的情况所以这两条命令必须同时执行缺一不可。2.3 关闭swapK8S从早期版本开始就要求节点关闭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.confcat /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_forward1 echo net.ipv4.ip_forward1 /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] nameDocker CE Stable baseurl你的可用Docker源地址 enabled1 gpgcheck0 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.cgroupdriversystemd] } EOF systemctl daemon-reload systemctl restart docker这里有件事我必须强调daemon.json不是必须的不写也能跑但如果不写Docker默认的cgroup driver是cgroupfskubelet又是systemd两者不一致时节点上的资源统计经常会出偏差严重时Pod会被反复驱逐。既然官方文档都推荐统一成systemd那就别给自己埋雷。3.2 安装kubeadm、kubelet、kubectlKubernetes三件套kubeadm负责初始化集群和生成令牌kubelet是每个节点上真正干活的代理进程kubectl是命令行管理工具。三台机器都需要安装包括Master和Node。同样需要先配置Kubernetes的yum源然后把三个组件的版本锁在1.14.2避免yum自动升级导致组件之间版本不一致# 配置Kubernetes安装源 # 把baseurl替换为你环境中可访问的源地址 cat /etc/yum.repos.d/kubernetes.repo EOF [kubernetes] nameKubernetes baseurl你的可用Kubernetes源地址 enabled1 gpgcheck0 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-versionv1.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-address192.168.10.10 \ --image-repository你确认可用的镜像仓库路径 \ --kubernetes-versionv1.14.2 \ --pod-network-cidr10.244.0.0/16 \ --service-cidr10.96.0.0/12--apiserver-advertise-addressMaster节点对外提供API服务的地址就填Master的IP别填错成Node的。--image-repository镜像仓库路径替换成你实际能拉到的地址。--kubernetes-version要匹配已经安装的kubeadm版本。--pod-network-cidrPod网段我选的10.244.0.0/16对应后面Flannel默认网段。这里和网络插件强相关如果之后想换Calico网段通常不同所以要先决定网络插件再定数值。--service-cidrService网段默认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 为什么这次选用FlannelPod网络插件是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 nodesMaster的状态应该已经变成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:xxxxxxhash值会自动从集群的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 --imagenginx:1.14 kubectl get pods -o wide观察Pod调度在哪个Node、状态是否为Running。如果想从集群外部访问到这个服务再用NodePort方式暴露Servicekubectl expose deployment nginx-test --port80 --target-port80 --typeNodePort kubectl get svc得到Service的NodePort后用浏览器访问任意一台Node的IP加这个端口能看到Nginx欢迎页就说明整个容器网络链路是通的。这时候还可以顺手验证一下Service的负载均衡效果把nginx-test的副本数扩到3个再反复访问端口看请求是否会分布到不同Podkubectl scale deployment nginx-test --replicas3虽然没有可视化界面直接展示流量去向但通过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里的Podkubectl 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和主机名有变化其他没有任何区别。哪天你想验证什么新组件多准备两台机器复用这套流程很快就能把环境搭出来。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑