ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

零基础用kubeadm搭建K8s集群:前置配置与排错全攻略

零基础用kubeadm搭建K8s集群:前置配置与排错全攻略 我到现在还记得第一次搭k8s集群时的狼狈样照着网上的教程敲到第8条命令就报错一查才知道swap没关。Kubernetes已经是容器编排的事实标准你去搜“k8s集群搭建”“k8s部署教程”“k8s和docker区别”很容易被一堆概念和报错淹没。这篇文章就是写给零基础新手的用的是官方推荐的kubeadm方式从节点规划、系统预置、三件套安装到控制面初始化、工作节点加入、CNI网络插件部署最后把集群跑起来顺带整理几起我实际遇到过的故障排查链路。你不需要先懂架构只需要准备一台或者几台Linux机器跟着操作就能得到一套可以正常跑业务的k8s环境。整个过程我会按自己搭建时的顺序写把每个步骤前面的“为什么”也讲清楚这样你后面自己排错的时候才能有个方向感。1. 新手动手前必须想清楚的三件事1.1 安装方式怎么选我为什么推荐kubeadm很多新手一上来会去装minikube一条命令就能拉起来一个单节点k8s确实很爽。但它毕竟是在你本机里模拟出来的“独立环境”很多真实集群里会遇到的问题它根本暴露不出来——比如证书怎么签发、kubelet和apiserver怎么通信、工作节点怎么加入。生产环境还有一种做法是纯二进制方式安装把etcd、apiserver、controller-manager、scheduler这些组件一个个下载下来自己写systemd服务、自己签证书步骤长到能把人劝退。kubeadm属于中间路线而且它是官方维护的集群搭建工具。它把控制面组件的初始化封装成了标准化流程在master上只需要执行kubeadm init它就会自动生成证书、启动apiserver和etcd、配置好kubeconfig之后工作节点用kubeadm join一条命令加入。对于新手来说kubeadm的另一个好处是报错信息在网上一搜一大把因为大多数人都在用它很多坑早就被人趟平了。别以为kubeadm只是学习玩具生产环境里也有大量团队用它来做初始化后续的证书更新、升级路径官方都有文档支撑。1.2 k8s和Docker到底什么关系这年头Docker不是必须的这大概是新手最常问的问题热搜里也总出现“k8s和docker区别”“k8s和docker的关系与区别”。简单说k8s是一个容器的编排调度平台它负责决定你的容器跑在哪台机器上、需要几个副本、怎么暴露服务而Docker属于容器运行时负责真正把容器跑起来。早期k8s确实深度依赖Docker但从某个版本开始k8s定义了CRI也就是容器运行时接口只要底层运行时实现这个接口就能被k8s接进来。所以你现在去搭新版集群会发现官方根本不会要求你安装Docker默认装的是一套叫containerd的运行时。这个containerd独立于Docker专门负责容器的创建、启动、停止这些底层操作。你以前用docker build打出来的镜像是标准OCI镜像放到containerd同样能跑。新手如果还在照着老教程先装Docker其实是在走弯路后面还会遇到cgroup driver不一致之类的连锁问题。1.3 版本选择这一步决定你能不能往下走通k8s发布节奏很快版本很多新手最容易在这里栽跟头。记住一条铁律kubeadm、kubelet、kubectl这三个组件必须保持相同的次要版本比如统一用v1.28.2不能一个1.27一个1.28。containerd的版本也要匹配太老的版本对新版k8s的特性支持不够。操作系统方面CentOS 7.9自带的内核是3.10旧是旧了点也能跑但新版k8s对内核特性有要求有条件建议直接用Rocky Linux 9或者Ubuntu 22.04内核5.x体验会顺畅很多。我见过太多人不是死在命令上而是死在版本混乱上kubeadm是1.27的kubelet却装成了1.28节点join进来之后kubelet反复重启日志里全是证书或版本不匹配。所以开始动手之前先把版本定下来后面所有安装命令里的版本号都锁死。组件建议版本说明kubeadm / kubelet / kubectlv1.28.2三件套必须对齐containerd1.7.x适配k8s 1.28操作系统Rocky 9 / Ubuntu 22.04内核5.x更省心Master配置2C4G起内存太小init直接卡住2. 节点规划与系统预置这些前置步骤不做后面全是报错2.1 硬件和系统清单先算好你要几台机器最少需要一台master和一台worker两台机器就能构成一个最标准的集群。如果你手头只有一台机器也能做单节点集群把所有角色都压在这台上但那样你体会不到“node join”这个过程我还是建议至少准备两台虚拟机。硬件方面master官方要求是2核2G但实际跑起来你会发现2G内存真的很紧张apiserver加etcd加各种控制面组件很容易把内存吃满我给你的建议是2C4G起步。worker按2C2G起步就行。磁盘每台至少30GB镜像拉多了之后20G根本不够用。系统统一用一个版本不要一台CentOS一台Ubuntu混着来后面的软件源和排查命令都不通用。网络方面保证所有节点之间能互相ping通最好把IP规划好从第一步就给每台机器设置固定的hostname。2.2 五条预配置命令和它们背后的原因新手搭集群最烦的就是前置配置又多又碎我直接给你一套可以照抄的后面附带解释。# 每台机器都要执行IP和hostname按你的实际情况换 hostnamectl set-hostname master01 cat /etc/hosts EOF 192.168.1.10 master01 192.168.1.11 node01 EOF # 关闭swapkubeadm检测到swap默认会直接拒绝初始化 swapoff -a sed -i / swap / s/^/#/ /etc/fstab # 关闭SELinuxCentOS/Rocky系必须做Ubuntu跳过 setenforce 0 sed -i s/^SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config # 加载内核模块k8s网络转发依赖这些 cat /etc/modules-load.d/k8s.conf EOF overlay br_netfilter EOF modprobe overlay modprobe br_netfilter # 调整内核参数让iptables能处理桥接流量 cat /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 sysctl --system解释一下为什么这些步骤缺一不可swap不关kubeadm init会在前置检查阶段直接报“running with swap on is not supported”SELinux是强制访问控制开着经常导致kubelet无法读取某些目录权限br_netfilter模块控制桥接流量的iptables规则k8s的Service转发依赖它net.ipv4.ip_forward是开启IP转发Pod之间的跨节点通信必须用到。2.3 防火墙和端口学习环境可以直接放行别在这上面内耗生产环境的防火墙规则要精细控制但新手学习阶段最省心的是直接把firewalld停掉或者至少把k8s相关端口全部放行。我建议你学习期间不要跟防火墙较劲等集群跑通了再研究怎么锁端口。systemctl stop firewalld systemctl disable firewalld如果是Ubuntu对应的是ufw直接ufw disable。有些教程说“生产环境不建议关防火墙”这句话没错但你现在是学搭建不是学防守先把集群跑起来再说。真到要开放端口的时候主要记住这几类6443是apiserver的入口2379到2380是etcd通信10250是kubelet30000到32767是NodePort服务的端口范围。你现在不理解这些也没关系后面排错会遇到。3. 三件套安装kubeadm、kubelet、kubectl的版本对齐逻辑3.1 配置软件源并安装三件套kubeadm、kubelet、kubectl这三个组件一般统称“三件套”安装方式取决于你的系统。CentOS/Rocky这边我习惯配阿里云的yum源cat /etc/yum.repos.d/kubernetes.repo EOF [kubernetes] nameKubernetes baseurlhttps://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled1 gpgcheck0 EOF yum install -y kubeadm-1.28.2 kubelet-1.28.2 kubectl-1.28.2如果你用的Ubuntu用apt源的方式curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - echo deb https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main /etc/apt/sources.list.d/kubernetes.list apt-get update apt-get install -y kubeadm1.28.2-00 kubelet1.28.2-00 kubectl1.28.2-00所有节点master和worker都要装三件套。worker节点虽然不需要执行init但join命令本身和kubelet的运行都依赖它们。安装时可以指定版本号也可以装完用yum versionlock kubelet kubeadm kubectl把版本锁住防止哪天手滑升级导致版本不一致。重点提醒一下装完先执行systemctl enable kubelet但是不要在意它当前是不是active。这个阶段kubelet因为没有配置文件会不断重启这是正常现象新手经常在这里被吓到以为装坏了。3.2 containerd安装与关键配置cgroup驱动必须对齐容器运行时我们选containerd它比Docker更轻也是k8s官方现在的默认选择。安装可以用Docker的软件源来装yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum install -y containerd.io安装完之后不要直接启动先做两步最关键配置。第一步生成默认配置把SystemdCgroup改成true第二步把pause镜像换成国内镜像仓库地址。pause镜像是每个Pod里第一个启动的“占位容器”它负责维系Pod的网络命名空间这个镜像默认地址拉取不稳定不改的话后面所有Pod都会卡在ContainerCreating。mkdir -p /etc/containerd containerd config default | tee /etc/containerd/config.toml sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml sed -i s#registry.k8s.io/pause:3.9#registry.aliyuncs.com/google_containers/pause:3.9# /etc/containerd/config.toml systemctl restart containerd systemctl enable containerd为什么要强调SystemdCgroup这个参数因为kubelet默认使用的cgroup driver是systemd如果containerd还是cgroupfs两边管理方式不一致节点能加入成功但Pod在运行的时候资源统计会错乱甚至经常重启。这个错误不会在节点加入时报出来而是等部署应用之后才暴露非常隐蔽。4. 控制面初始化镜像拉取失败和新手最容易改错的参数4.1 完整init命令与每个参数的用途前置都准备完毕就可以在master节点上初始化控制面了。初始化最怕的就是镜像拉取失败所以可以先用kubeadm config images pull把镜像预拉下来这一步能提前暴露问题省得init执行到一半才卡住。kubeadm config images pull \ --image-repositoryregistry.aliyuncs.com/google_containers预拉完成后执行初始化kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --image-repositoryregistry.aliyuncs.com/google_containers \ --kubernetes-versionv1.28.2 \ --pod-network-cidr10.244.0.0/16逐条说下这几个参数。--apiserver-advertise-address填master节点的IP这是整个集群的API入口地址填错了其他节点根本连不上来。--image-repository指定镜像仓库默认走的是registry.k8s.io国内环境拉取很不稳定换成阿里云的镜像仓库可以少掉很多头发。--kubernetes-version要和三件套对齐写成v1.28.2。--pod-network-cidr是Pod网段这个参数取决于你后面装什么网络插件Flannel默认用10.244.0.0/16Calico默认是192.168.0.0/16。我这边按Flannel来所以写10.244。4.2 初始化成功后的配置与单节点特殊处理初始化成功之后终端会打印一大段英文输出里面最关键的其实是最后几行提示大意是让你配置kubectl的权限。照着执行mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config这一步是让当前用户获得访问apiserver的权限。admin.conf是初始化时生成的集群连接凭证相当于一把管整个集群的钥匙。如果你只有一台机器做单节点集群初始化后master节点默认是带污点的也就是Pod不会调度到master上。执行下面的命令去掉污点kubectl taint nodes --all node-role.kubernetes.io/control-plane-注意这是单节点学习环境才这么干生产环境不要轻易去污点。4.3 初始化失败先别重装常见报错与兜底命令新手初始化失败的时候特别喜欢直接删除虚拟机重来。实际上大部分初始化失败都不需要重装系统一条kubeadm reset就能清理干净。常见报错我整理在下面这张表里报错特征常见原因处理方式[ERROR Swap]swap没关干净swapoff -a检查/etc/fstab[ERROR FileContent--proc-sys-net-bridge...]内核参数没设置重做2.2的内核参数再sysctl --systemfailed to pull image镜像仓库地址不可达确认image-repository配置检查网络kubelet isnt running or healthykubelet配置缺失或版本不一致看journalctl -u kubelet日志如果真的走到需要重来的一步在master上执行kubeadm reset -f rm -rf /etc/cni/net.d ~/.kube /var/lib/etcd清理完之后可以重新执行init不需要重装系统。这条命令你要记牢后面做实验会反复用到。5. 工作节点加入与CNI插件部署网络通了集群才算活5.1 生成加入指令并让worker加入master初始化成功后终端输出里其实已经带了一条kubeadm join命令但那条命令里的token有效期只有24小时如果你隔了很久才去加workertoken早过期了。更稳妥的做法是在master上重新生成kubeadm token create --print-join-command这条命令会直接打印出完整的join指令类似kubeadm join 192.168.1.10:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx把这条命令在worker节点上用sudo执行。执行完等一小会儿回到master上kubectl get nodes你应该能看到worker节点出现在列表里但如果它的状态是NotReady先别慌——大概率是网络插件还没安装这就是下一节的内容。5.2 安装Calico还是Flannel新手默认选Flannel网络插件是k8s里最容易被忽略却又最关键的部分。没有它节点之间的Pod无法通信coredns也永远起不来节点状态就会一直NotReady。插件选择上新手我建议默认Flannel它配置简单只有一个yaml文件网段规划好基本一次通过。Calico功能更强支持NetworkPolicy网络策略和BGP路由适合生产环境但它的组件更多排错也复杂。你不需要纠结学习阶段Flannel足够。安装Flannel前一定要确认init时写的--pod-network-cidr是10.244.0.0/16因为Flannel的默认配置就绑定这个网段。如果对不上后面的Pod网络会非常混乱。安装命令kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml我对从GitHub直接拉取yaml文件保留一个建议如果这条命令因为网络问题拉不下来不要反复重试先在能访问的机器上下载好文件再拷贝到master上执行kubectl apply -f kube-flannel.yml。装完之后持续观察kubectl get pods -n kube-flannel等Flannel的Pod变成Running再执行kubectl get nodes大概率节点状态已经变成Ready。5.3 网络到底通没通用一个Pod验证集群就绪后我建议你亲手验证一下数据面是否真的通了毕竟get nodes显示Ready只代表kubelet和网络插件握手成功不代表Pod之间能互通。最简单的方式是启动一个测试Pod进入容器然后解析集群的Service名称kubectl run test --imagebusybox --rm -it -- sh进入容器后执行nslookup kubernetes.default如果DNS解析正常说明CoreDNS工作正常Pod网络和Service网络都通了。能走到这一步说明你的集群已经是一个真正可用的环境了。6. 集群验证与高频kubectl命令速查6.1 每个新手都应该先跑一遍的健康检查集群搭建完成后建议按固定顺序做一遍健康检查这样后续你排错的时候也有个标准流程。第一步看节点状态kubectl get nodes理解一下输出NAME是节点名STATUS是Ready就正常ROLES区分master和workerVERSION是k8s版本。第二步看所有命名空间下的Podkubectl get pods -A注意kube-system和kube-flannel命名空间下都应该是Running或Completed状态。如果看到CrashLoopBackOff或者Pending说明集群还有问题别急着部署应用。第三步确认集群API入口kubectl cluster-info这条命令会打印master的地址和端口能正常输出说明apiserver健康。第四步可选用kubectl get events --all-namespaces查看有没有异常事件很多隐患都能从事件里提前发现。6.2 六个高频kubectl命令速查整理一份新手最常用的命令表用于日常操作命令用途kubectl get pods -A -o wide查看所有Pod及所在节点和IPkubectl describe pod pod名 -n 命名空间查看Pod事件排错第一步kubectl logs pod名 -n 命名空间查看容器日志kubectl apply -f xxx.yaml部署或更新资源kubectl delete -f xxx.yaml删除资源kubectl exec -it pod名 -- sh进入Pod容器kubectl scale deployment 名称 --replicas3扩缩容特别说一下kubectl describe这条命令它是新手排错的第一工具。任何Pod状态不对先describe看最下面的Events区域那里会直接告诉你这个Pod到底卡在哪个环节是镜像拉不到、资源不足还是探针失败。我自己的习惯是先get看状态再describe看事件最后才去logs看日志。顺序反了容易浪费时间。这里提一下如果想要kubectl top nodes查看资源占用需要额外部署metrics-server默认集群里没有。新手可以先不管等你要排查资源问题时再补。7. 替新手踩过的坑三起真实故障的完整排查链路7.1 节点一直NotReady先看CNI而不是怀疑kubelet我印象很深的一次一个同事把node节点join进来之后kubectl get nodes一直显示NotReady他反复重启kubelet折腾了大半天。其实问题的真相是他完全忘了安装Flannel或Calico。节点加入和网络插件是两件事加入成功只代表节点被apiserver接受了网络插件没装好节点状态就会停在NotReady。排查链路是这样的先kubectl describe node node01查看Conditions区域能看到一条NetworkPluginNotReady的提示这就是在明示网络插件的问题。然后kubectl get pods -A会发现kube-system里有个coredns Pod一直Pending因为node的网络插件没就绪Pod调度过去也没办法分配Pod网段。搞清楚机制之后安装Flannel等Pod起来节点状态自动变Ready。记住这个顺序以后再看到NotReady第一反应应该是“网络插件装了吗”而不是急着动kubelet。7.2 kubelet反复重启journalctl是排错的第一入口有一次我在一台全新的worker上执行join节点始终没有出现在集群里。检查systemctl status kubelet一会儿active一会儿又是failed状态来回跳。很多新手这个时候会反复restart kubelet但这基本没用。正确做法是看日志journalctl -u kubelet -f-f参数实时跟踪日志输出。那次我看到的日志核心线索是版本不匹配kubelet的版本是1.28而kubeadm和其他组件是1.27两者握手失败。因为版本不一致节点和apiserver之间的TLS握手和资源协议都对不上。后来把三个组件统一版本后问题彻底消失。所以这里给你一个经验kubelet反复重启绝大多数不是kubelet程序本身坏了而是配置不对、版本不对、或者证书不对。日志里会明确告诉你原因千万别凭感觉重启。遇到证书过期或异常可以用kubeadm certs renew all更新证书然后重启kubelet但前提是版本本身对齐。7.3 Pod一直ContainerCreating典型是pause镜像没拉到有次集群刚装完任何Pod都创建不成功状态清一色是ContainerCreating。我describe了一个Pod事件里写着Failed to pull image registry.k8s.io/pause:3.9一下子就锁定问题了。pause镜像虽然不承担业务逻辑但每个Pod启动都会先拉起它它负责创建Pod的网络命名空间和共享的Linux命名空间。如果默认镜像地址拉取不稳定所有Pod都会卡住。我在前面第3.2节特别强调要改containerd的sandbox_image配置就是防止这个问题。如果你当时忘了改处理方式也很简单修改/etc/containerd/config.toml里的sandbox_image为registry.aliyuncs.com/google_containers/pause:3.9然后systemctl restart containerd最后把异常Pod删掉让它重建。这里还藏着一个常见的二次坑配置文件改完忘了重启containerd导致看起来改了却一直不生效。重启这个动作一定要养成肌肉记忆。7.4 常见错误速查表最后我把新手阶段最高频的几个错误汇总成一张速查表你可以收藏起来遇到问题直接对号入座症状可能原因第一步排查init时报swap错误swap没关干净swapoff -a检查fstab节点NotReadyCNI插件没装或网段不一致get pods -A查cnidescribe nodePod一直ContainerCreatingpause镜像没改国内源describe pod看事件join节点超时token过期或6443端口不通token create重新生成检查防火墙kubelet反复重启版本不一致、证书异常journalctl -u kubelet -f看日志coredns一直Pending网络插件未就绪先装Flannel/Calico我一般遇到新手提问都是拿这张表来引导他们自己排查。你会发现很多人最终卡住的不是某个高深问题而是最基础的那些前置步骤。所以我在前面第2章、第3章花了大量篇幅讲预配置和配置原因就是希望你把地基打牢后面每一层都不容易塌。最后再分享一个小习惯任何时候看到集群状态异常不要急着删Pod、重装节点先执行kubectl describe和journalctl -u kubelet -f看事件和日志这两个命令能回答绝大多数“为什么”。等你亲自从报错里把问题找出来的那一刻你对这套集群的掌控感会和照着教程敲命令完全不一样。
返回列表