ARTICLE DETAIL

资讯详情

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

k3s实战:十分钟搭建Kubernetes集群从单节点到高可用

k3s实战:十分钟搭建Kubernetes集群从单节点到高可用 《k8s权威指南》翻到第五版还在纠结控制平面组件怎么编排的时候我已经在考虑要不要放弃学习Kubernetes了。说实话大部分卡在k8s入门阶段的人不是看不懂概念而是根本凑不出一套能跑起来的集群环境。标准k8s安装对机器配置、网络环境、依赖版本的要求摆在那里光是一个kubeadm init失败后的排错就够劝退一批人。后来换了k3s十分钟内拿到了一个可用的k8s集群才真正把精力从“装环境”挪回到“学k8s本身”。这篇文章就把我用k3s搭建k8s集群的完整过程、原理拆解、踩坑记录和实测数据写清楚给也想快速拿到一套k8s环境的人一条能直接走通的路。1. 为什么我没直接装标准k8s资源门槛和依赖复杂度1.1 标准k8s对硬件和系统的要求远比文档写的更现实kubeadm方式部署标准k8s官方文档写的是2核4G起步节点数至少是1主2从。但这个配置指的是“能装完”而不是“能用得动”。装完之后控制平面的etcd、kube-apiserver、kube-controller-manager、kube-scheduler这四件套常驻内存基本吃满2G剩下的内存分给工作负载后跑个pod就频繁OOM。实测过在2核4G的机器上装标准k8s装完系统可用内存只剩800M左右随便部署个nginx加上监控组件节点直接进入NotReady状态。公网云服务器如果选择包年包月4核8G的实例和2核4G的实例差价接近一倍。为了学一个k8s去专门买高配机器很多人就是在这步犹豫着犹豫着就放弃了。加上标准k8s安装对系统版本、内核模块、网络插件Calico或Flannel、CRI运行时containerd或CRI-O都有严格的版本匹配矩阵任何一个组件版本对不上报错信息都看不懂。1.2 k3s到底简化了什么组件打包、数据库和运行时k3s做的事情不是砍功能而是把k8s控制平面的多个组件合并进同一个二进制文件再替换掉几个重量级依赖。具体来说最核心的三处改造是控制平面合并kube-apiserver、kube-controller-manager、kube-scheduler被封装进同一个k3s server进程进程数从4个变成1个。存储后端的替代默认不再单独部署etcd而是用嵌入式SQLite单节点模式或嵌入式etcd高可用模式来保存集群状态。运行时简化默认集成containerd不需要单独安装和配置容器运行时。这些改造直接砍掉了标准k8s安装和运维中最复杂的几个环节。装标准k8s时etcd要单独配置TLS证书、要设置集群成员、要维护备份策略k3s把这些东西全部包装起来用户只需要关心一条install脚本。1.3 k3s是“阉割版”吗兼容性和生产使用情况这是很多人听到k3s时的第一反应。实际上k3s是一个通过了CNCF一致性认证的Kubernetes发行版API层面和标准k8s保持兼容kubectl、Helm、Prometheus Operator这些工具都能直接用。生产环境里k3s被大量部署在边缘计算网关、ARM开发板、工业控制设备上Rancher自家也把它作为轻量集群的标准方案。它和标准k8s的关系更像是一个预装好依赖和默认配置的发行版而不是功能打折的替代品。判断k3s是否适合你核心标准只有一个有没有用到k8s的扩展接口和高级特性。如果你的重点是跑常规工作负载、学习核心概念、做CI/CD测试k3s完全够用如果项目要求深度定制调度器、自定义API扩展、特殊网络方案建议还是用标准k8s。2. 搭建前必须想清楚的三件事节点角色、操作系统和网络规划2.1 单节点还是多节点视角完全不同k3s支持两种部署模式。单节点模式一个server节点适合学习、开发测试、边缘设备运行高可用模式多个server节点多个agent节点适合生产环境。两种模式的安装复杂度差距很大单节点基本一条命令搞定高可用模式需要额外处理server节点的初始化、join参数和数据存储配置。如果你是想学k8s第一台机器强烈建议先单节点跑通把kubectl、Pod、Deployment、Service这些核心概念摸熟再考虑扩容成高可用。一上来就搭三节点集群遇到问题定位起来会非常痛苦排错范围太大。2.2 server和agent的分工先分清角色再动手k3s里server节点等同于标准k8s的控制平面节点运行apiserver、controller-manager、scheduler和集群数据存储同时也承担工作负载。agent节点等同于工作节点只负责运行业务Pod。装之前先把角色分清楚避免后面加节点时混淆验证逻辑。2.3 操作系统选型与初始化准备k3s官方对操作系统的宽容度比标准k8s好很多Ubuntu 20.04/22.04、Debian 11/12、CentOS 7/8/Rocky Linux都能跑。我推荐用Ubuntu 22.04 LTS主要原因是内核版本较新对iptables、overlayfs这些容器相关内核模块的支持更完善遇到兼容性问题的概率更低。树莓派或国产ARM开发板用官方Raspberry Pi OS或对应的ARM64系统镜像也完全可以。不管选哪个系统装k3s之前要做三件事关闭swapkubelet默认不允许swap开启虽然k3s可以通过参数绕过但没必要在入门阶段给自己埋坑。加载必要内核模块overlay和br_netfilter是容器网络转发的基础。确认防火墙规则如果云厂商安全组或主机防火墙比较严格至少需要放通TCP 6443端口API Server、UDP 8472端口VXLAN通信以及TCP 10250端口kubelet metrics。提示大多数VPS默认防火墙规则宽松可以跳过后两步。但如果用云厂商安全组请务必提前确认端口放通情况否则kubectl get nodes会一直报连接拒绝。2.4 版本选择与获取方式k3s官方发布节奏是每月一个稳定版本版本号沿用k8s的命名规则。直接用官方快速安装脚本默认拉取最新稳定版即可。但有一个细节值得注意如果你计划后续对接Rancher管理平台或某些特定CSI存储插件需要先确认它们对k3s版本的最低要求避免装到过新的版本导致兼容问题。国内服务器从GitHub下载相关资源偶尔会超时需要配置代理或使用镜像加速这个后面在踩坑部分详细说。3. 十分钟搭起第一个单节点k3s集群3.1 一路默认的安装命令每个参数都拆开看单节点安装最简单的方式就是执行官方脚本curl -sfL https://get.k3s.io | sh -这条命令做了几件事下载k3s二进制到/usr/local/bin、生成systemd服务、启动k3s server进程、配置kubectl生成/etc/rancher/k3s/k3s.yaml。执行完之后等几十秒就能看到集群状态。但实际项目中我更推荐显式指定参数把控制权握在自己手里curl -sfL https://get.k3s.io | INSTALL_K3S_EXECserver \ --disabletraefik \ --disableservicelb \ --data-dir/data/k3s \ --node-namek3s-server-01 sh -逐项说明--disabletraefikk3s默认自带Traefik作为Ingress Controller如果暂时用不到Ingress关掉能少占约100M内存并且避免端口80/443被占用导致的本机端口冲突。--disableservicelbk3s默认的Service Load BalancerKlipper LB会为每个LoadBalancer类型Service分配一个宿主机端口。单节点学习环境用不到关掉可以减少iptables规则数量排查网络问题时少一层干扰。--data-dir/data/k3s默认数据目录在/var/lib/rancher/k3s。如果系统盘空间不大提前规划数据目录到数据盘非常重要etcd和容器镜像都存这里。--node-namek3s-server-01给节点起一个可读名字不设置时默认使用主机hostname。多节点环境强烈建议显式设置避免后面一片Node名字都叫localhost。等待脚本执行完毕用kubectl检查集群状态export KUBECONFIG/etc/rancher/k3s/k3s.yaml kubectl get nodes状态为Ready说明控制平面和容器运行时都已经正常启动。接着检查核心组件kubectl get pods -A正常情况下能看到coredns、local-path-provisioner、metrics-server这几个系统Pod全部处于Running状态。3.2 部署一个测试应用验证链路是否通畅集群起来之后第一时间部署一个无状态应用验证整个链路kubectl create deployment whoami --imagenginx:alpine kubectl expose deployment whoami --port80 --typeNodePort kubectl get svc whoami访问http://节点IP:NodePort能看到nginx默认页面就说明容器运行时、kubelet、kube-proxy、Service网络全部正常。很多人在装完集群后忽略了这一步直接开始学Deployment、Service的YAML写法结果集群底层有问题而不自知。先跑通一个最小化链路后面排错时才有对照基线。3.3 单节点集群的运维日常配置kubectl和查看日志k3s的kubectl配置文件默认生成在/etc/rancher/k3s/k3s.yaml文件里的server地址是https://127.0.0.1:6443。如果需要在本地电脑远程管理集群把这个文件复制到本地然后把server地址改成https://节点IP:6443再把certificate-authority-data替换成节点上的/var/lib/rancher/k3s/server/tls/server-ca.crt内容或者直接用insecure-skip-tls-verify: true绕过证书校验只建议内网测试环境用。查看k3s系统服务日志用journalctljournalctl -u k3s -f如果server进程启动失败日志里基本能看到完整的堆栈和错误原因大部分安装失败问题都在这个日志里能直接定位。3.4 关闭和重启集群的正确方式最后补充一个日常运维常用的操作。k3s作为systemd服务运行关闭集群systemctl stop k3s启动集群systemctl start k3s如果只是重启节点机器k3s服务会随着系统启动自动拉起不需要额外配置。4. 把集群升级成高可用三节点嵌入式etcd方案4.1 为什么单节点集群不能直接上生产单节点k3s把所有组件集中在一个进程单机运行服务器宕机意味着API Server、数据存储、业务Pod全部不可用关键数据存储在没有主从复制或备份机制的SQLite里。生产环境任何单点故障都不可接受更麻烦的是单节点模式下数据全部存在本地SQLite一旦数据目录损坏没有副本可以恢复。k3s官方给出的高可用方案是使用嵌入式etcd。多台server节点组成一个etcd集群数据自动复制到所有server节点上部分节点挂掉不影响整体可用性。4.2 高可用集群的两项硬性条件server节点数量必须是奇数1、3、5……这样保证etcd在任何分区场景下都容易出现多数派选主逻辑才能跑通。server节点数量至少3个三节点中允许挂掉一个五节点中允许挂掉两个。两个节点也能组成etcd集群但任何一个节点故障都会导致失去多数派集群不可写所以没有实际意义。4.3 三节点高可用完整操作流程假设三台服务器计划都作为server节点IP分别为192.168.1.11、192.168.1.12、192.168.1.13。第一步在第一台节点上启动server。curl -sfL https://get.k3s.io | INSTALL_K3S_EXECserver \ --cluster-init \ --disabletraefik \ --disableservicelb sh ---cluster-init告诉k3s初始化一个嵌入式etcd集群而不是默认的单节点SQLite模式。这个参数只加在第一台节点上。第二步从第一台节点获取join token。cat /var/lib/rancher/k3s/server/node-tokennode-token是其他节点加入集群的凭证内容是一长串包含随机密钥和哈希的字符串。第三步在第二、第三台节点上执行join操作。curl -sfL https://get.k3s.io | INSTALL_K3S_EXECserver \ --serverhttps://192.168.1.11:6443 \ --tokennode-token值 sh -这里的关键是把--server指向第一台节点的API Server地址并且不指定--cluster-init。k3s会检测到这是一个加入既有etcd集群的操作自动从--server指定的节点同步集群数据并加入etcd成员。第四步验证etcd集群状态。在三台server节点全部启动完毕后登录第一台节点执行kubectl get nodes正常情况下能看到三个server节点状态都是Ready。接着查看etcd健康状态k3s etcd-snapshot ls能看到快照列表说明etcd集群工作正常成员间通信没有问题。4.4 扩容agent工作节点高可用环境下工作负载最好调度到agent节点上避免和控制平面抢占资源。加入agent节点的命令和加入server节点类似唯一的区别是把server替换成agentcurl -sfL https://get.k3s.io | INSTALL_K3S_EXECagent \ --serverhttps://192.168.1.11:6443 \ --tokennode-token值 sh -agent节点上运行的systemd服务名是k3s-agent排错时注意日志服务名称和server节点不一样。4.5 高可用集群的备份与恢复多一个节点不意味着不需要备份。配置了嵌入式etcd的高可用k3s集群官方推荐的备份方式是定期执行etcd快照。直接在任意一个server节点执行k3s etcd-snapshot save --namemanual-backup恢复时在故障节点上执行k3s server --cluster-reset --cluster-reset-restore-path/var/lib/rancher/k3s/server/db/snapshots/manual-backup恢复操作需要先把其他节点停掉避免恢复节点加入一个仍然健康的etcd集群导致数据冲突。这一点务必注意我在测试环境曾经因为图省事直接对着运行中的集群做cluster-reset导致etcd成员列表混乱最后把三台机器全部清空重来。提示如果追求更完善的备份策略可以把快照文件定期同步到对象存储或另一台机器。k3s支持通过配置etcd-snapshot-dir、etcd-snapshot-schedule-cron和etcd-snapshot-retention参数实现自动快照。5. 真实环境踩坑复盘四条最容易卡住的报错和解决路径5.1 kubelet一直Startingcgroup驱动不一致现象kubectl get nodes能看到节点但状态永远是NotReady查看k3s日志反复出现Failed to run kubelet和failed to validate kubelet cgroup相关报错。排查过程打开journalctl日志确认具体报错发现kubelet启动时传入的cgroup驱动是systemd但containerd默认配置的cgroup驱动是cgroupfs。k3s在检测到系统init进程是systemd时kubelet使用systemd驱动但容器运行时如果用的不是同一套cgroup驱动kubelet无法正确感知容器资源状态就会一直卡在启动阶段。解决方案检查系统是否以systemd作为init进程多数现代发行版都是确认后给k3s启动参数加上--kubelet-argcgroup-driversystemd同时在agent节点上如果存在同样问题需要关闭--docker参数默认使用containerd无需处理。实际上新版k3s对这个场景做了很多自动化适配如果你用的是Ubuntu 22.04Debian 12这些新系统很少遇到但CentOS 7这一类老系统遇到概率很高。5.2 安装脚本执行完毕但集群一直Waiting for node现象install脚本正常执行完systemd服务状态是running但kubectl get nodes卡在Waiting for node或者报connection refused。排查过程这类问题八成防火墙或者网络端口问题。先看本地能不能连6443端口ss -lntp | grep 6443端口没监听说明k3s server进程没绑定成功继续看日志。端口有监听但外部连不上那就检查云厂商安全组和本机防火墙。VXLAN端口8472如果没放通节点间通信会异常也会导致节点注册不进来。另一个隐蔽原因是系统时间偏差过大apiserver签发证书的通信握手中会校验时间。遇到过一台VPS时间落后8分钟导致证书验证失败的情况timedatectl set-ntp true同步时间后问题消失。解决方案按顺序检查端口监听、防火墙规则、安全组、系统时间四项逐一排除。平时写排错文档时我习惯从最外层网络逐步往里层排查直接从应用层入手容易看半天日志发现只是端口没通。5.3 断电后etcd数据损坏集群无法启动现象测试环境突然断电重启后systemctl start k3s直接失败日志提示etcd wal文件损坏。排查过程断电后写操作中断etcd的WAL日志容易损坏。单节点SQLite模式相对皮实但嵌入式etcd对断电非常敏感。遇到这类情况第一反应不是删数据而是先看看快照文件是否还在ls /var/lib/rancher/k3s/server/db/snapshots/如果有快照直接用cluster-reset参数恢复损失最多是快照之后新增的数据。没有快照的情况下可以尝试把/var/lib/rancher/k3s/server/db/etcd目录下的member文件夹备份后删除再用--cluster-reset初始化一个新的etcd节点但所有历史资源都会丢失。解决方案给k3s环境搭配一个定时快照任务同时确保ups电池正常。生产环境的k3s集群建议开启自动快照并设置保留天数避免手动备份不及时。5.4 国内下载k3s安装脚本和二进制超时现象curl -sfL https://get.k3s.io | sh -执行到一半卡住或者报Unable to download错误。排查过程install脚本默认从GitHub Releases下载二进制。国内网络访问GitHub稳定性确实不理想尤其是带宽高峰期。解决方案k3s官方提供了镜像加速方案设置环境变量指向国内镜像站这是我推荐的第一选择export INSTALL_K3S_MIRRORcn curl -sfL https://get.k3s.io | sh -设置后脚本会从国内镜像下载二进制速度快非常多。如果安装机器本身无法访问外网还有完全离线安装的路径准备一台能访问外网的机器下载好二进制和镜像通过docker save导出镜像再传输到目标机器用ctr images import导入。这个过程稍复杂但确实能解决内网环境问题。5.5 镜像拉取慢导致Pod一直ImagePullBackOff现象测试应用部署后Pod状态一直ImagePullBackOffkubectl describe pod显示拉取镜像时超时。排查过程国内的网络环境拉取Docker Hub镜像确实不稳定这个问题常见于使用nginx、redis等默认官方镜像时。解决方案给containerd配置镜像加速。k3s的containerd配置目录在/var/lib/rancher/k3s/agent/etc/containerd/修改config.toml在[plugins.io.containerd.grpc.v1.cri.registry.mirrors]段配置国内镜像源然后重启k3s服务。配置完成后新拉取的镜像会走加速源原来失败的应用重新创建Pod即可恢复。6. 实测性能数据和几个值得关注的参数6.1 安装耗时与资源占用实测在一台2核2G的腾讯云轻量服务器Ubuntu 22.04和一台1核1G的阿里云抢占式实例Debian 12上分别做了单节点安装测试数据如下配置Ubuntu 22.04 2C2GDebian 12 1C1G安装耗时约50秒约1分30秒安装后空闲内存850M左右420M左右k3s进程数1个主进程子协程1个主进程子协程部署nginx应用耗时约8秒约15秒1核1G的机器装完k3s后内存还剩不到一半客观说跑复杂应用会比较吃力但启动一个几MB的轻量服务、做配置验证还是完全可能的。这个成绩在标准k8s下不敢想象同样配置装标准k8s大概率直接在kubeadm init阶段就OOM了。6.2 稳定运行阶段的关键参数设置生产环境长时间运行有几个参数建议根据机器资源情况进行调整。kubelet资源预留默认情况下kubelet会贪婪吞掉节点空闲内存导致节点上可分配的Pod资源无限大极端情况一个Pod把节点内存打满控制平面进程被OOM Kill。建议给每个agent节点设置系统预留和kubelet预留--kubelet-argsystem-reservedcpu200m,memory512Mi --kubelet-argkube-reservedcpu200m,memory512Mi镜像垃圾回收阈值如果节点的磁盘比较小可以调整镜像GC策略--kubelet-argimage-gc-high-threshold70 --kubelet-argimage-gc-low-threshold50这个配置含义是磁盘使用率达到70%时启动垃圾回收回收到使用率降到50%为止。Pod数量限制k3s默认允许每节点运行110个Pod边缘场景下这个数字偏大且每个Pod会占用一个IP和对应网络资源。通过参数限制每节点的最大Pod数--kubelet-argmax-pods50根据实际场景设置合理的值可以减少CNI的IP分配压力。参数建议值说明system-reservedcpu200m,memory512Mi系统进程预留kube-reservedcpu200m,memory512Mikubelet预留image-gc-high-threshold70镜像GC触发阈值image-gc-low-threshold50镜像GC停止阈值max-pods50节点Pod上限6.3 容器存储local-path-provisioner的使用问题k3s默认自带local-path-provisioner提供基于节点本地磁盘的PV能力。学习环境里用它跑持久化存储很简单创建PVC时指定storageClassName: local-pathPV会自动创建在/var/lib/rancher/k3s/storage/目录下。但这个方案有致命限制数据无法跨节点迁移。Pod调度到另一台节点时PVC不会跟着走数据仍然留在原节点的磁盘上。如果你在测试环境里模拟Pod故障转移会发现应用起在新节点但数据还在老节点出现数据不一致。高可用环境建议不要使用local-path改用支持分布式存储的CSI插件如Longhorn或Rook Ceph。如果纯粹学习用这个问题可以忽略。7. 从k3s通往标准k8s哪些经验可以直接迁移哪些地方容易栽跟头7.1 核心概念和操作完全通用在k3s上学的kubectl命令、YAML写法、Pod/Deployment/Service/Ingress/ConfigMap/Secret这些核心资源对象在标准k8s上完全一样。k3s的API和标准k8s保持兼容意味着你写的所有应用编排文件可以在标准k8s上无缝运行。从k3s迁移到标准k8s最大的成本不在知识层面而在集群本身的运维层面。7.2 差异点集中在集群运维层面标准k8s的etcd要手动配置TLS、手动管理成员、手动做快照备份k3s把这一切都封装好了。标准k8s的CNI插件Calico、Cilium要单独安装和配置k3s默认集成了一个简化的CNI。标准k8s的Ingress Controller要自己选型部署k3s默认带Traefik。这些差异在学习阶段基本不感知但一旦涉及系统调优和排障就会发现自己欠缺的是k8s底层原理的理解而不是使用经验。7.3 建议的学习路线先用k3s掌握k8s的基本操作和核心概念部署几个有状态应用和无状态应用把Deployment滚动更新、Service负载均衡、Ingress域名访问、PV/PVC持久化存储这些日常操作跑熟。然后尝试自己手动搭建一次标准k8s集群理解每个组件的作用和它们之间的协作关系。最后卸载重来一次尝试通过k3s etcd-snapshot save做备份模拟节点故障恢复把高可用集群的运维能力练出来。这样一条路线走下来既有动力因为环境好搭又有深度因为最终要接触底层组件比直接啃官方文档效率高很多。最后说点实际的k3s解决了Kubernetes学习过程中最大的拦路虎——装环境。如果你现在的目标是学会k8s、拿到集群练手、跑几个项目验证想法不用犹豫直接上k3s。用最低的成本把环境跑起来把核心概念玩明白这笔账怎么算都划算。根据我个人的使用体验有几个小建议第一节点命名从一开始就规范化不要默认hostname后面加多台节点管理起来会非常清晰第二数据目录和数据盘分区提前规划k3s集群运行久了镜像和etcd数据增长速度超出预期临时迁移数据目录的代价远比提前规划高得多第三不要因为k3s安装简单就跳过监控和备份轻量集群同样是生产环境该有的底线不能省。踩过几次坑之后我的体会是k3s不是玩具它是帮助你聚焦业务本身、降低基础设施心智负担的好工具。先把它用熟再往标准k8s深入这个路径对新手来说踏实得多。
返回列表