☰
K3s轻量级Kubernetes实战:边缘计算场景下的部署与优化
2026/10/8 2:30:57 网站建设 项目流程

1. 为什么"完整版"Kubernetes在边缘场景经常跑不动

1.1 边缘节点和云端节点在资源禀赋上的落差

先说个我实际遇过的场景。工厂车间一台4G内存的工控机,原来跑着一个单机版监控服务,后来业务要上容器编排,我照着云上的习惯直接上了标准Kubernetes。装完那一刻内存还剩不到2.5G,kubelet、etcd、kube-apiserver这几个组件在系统里互相抢CPU,机器温度都上去了。运行了大概一周,节点开始随机NotReady,查日志发现是etcd的磁盘IO和内存压力在折腾,维护成本比业务本身还高。

这不是个例。边缘计算节点的硬件配置,通常就是树莓派4(4G或8G内存)、工业网关(2~4G内存)、嵌入式工控机、车载计算单元这些东西。而标准Kubernetes的控制面,光etcd在三节点集群里就要占掉相当可观的内存和磁盘写入带宽,单控制面节点跑起来至少需要2G内存才敢说从容。再加上网络插件、DNS、Ingress Controller、监控组件,一台边缘小机器还没跑业务就先被基础设施压垮了。

所以问题从来不是"Kubernetes不好用",而是"在错误的场景里用了完整版"。边缘节点要的是能跑容器、能调度、能自愈、能离线存活,而且最好只占用很小一块资源的编排系统。轻量级Kubernetes就是为这种需求出生的,而K3s是目前这个生态里用得最多、社区迭代最活跃的那个发行版。

1.2 资源和运维之外,还有网络这道坎

边缘场景还有另外两个容易被云原生老手忽略的痛点。

第一是运维半径。云端集群一般有专职平台团队,升级、证书轮换、故障恢复都可以由专门的人来处理。但边缘站点往往上百个,散布在各地,每个站点可能只有一台设备,没有专职运维。如果每台设备都跑一套完整Kubernetes,光是证书过期、组件升级、etcd压缩策略这些问题就够运维团队喝一壶的。K3s把控制面压成单进程、把证书轮换做成自动化,就是为了让"没有专职运维"的环境也能跑得起Kubernetes。

第二是网络隔离。很多工业现场、野外基站、海上平台压根没有稳定的公网连接,甚至完全离线。标准Kubernetes的部署和升级高度依赖从镜像仓库拉取组件,离线环境下操作成本极高。K3s的安装包可以整体搬运到内网,支持完全离线的air-gap部署,这一点在边缘场景里是刚需中的刚需。

2. K3s轻量化的核心设计:一个集群是怎么被塞进小机器的

2.1 Kine:用SQL把etcd换掉,这是最狠的一刀

K3s最激进的改动,是默认不跑etcd。Kubernetes的kube-apiserver把集群状态存在etcd里,而etcd本质上是为分布式一致性设计的强一致KV存储,内存和磁盘开销都不小。K3s用了一个叫Kine的项目,在API Server和存储之间做了一个翻译层,把etcd风格的watch、事务操作翻译成普通SQL语句,默认落到节点上的SQLite里。

如果你读过《深入理解Kubernetes源码》里关于存储层的那部分,就会明白Kine本质上是在重新实现etcd存储插件需要满足的那套接口:Watch、Create、Update、Delete、List。SQLite充当后端时,每次watch到变更都会变成一轮SQL查询,事件的推送粒度从etcd底层的流式通知,降级成了轮询加比对。这对边缘集群来说完全够用,因为边缘节点上的对象数量通常很少,几百个Pod、几十个ConfigMap,SQLite承载这种量级的读写毫无压力,但省下的内存和进程数却是实打实的。

代价也在这里埋下了:SQLite的写入锁粒度粗,不支持高并发写;而且Kine这种翻译层天生就不适合大量高频状态变更的场景。你的业务如果频繁创建/更新大量CRD对象,API Server的写请求会直接打在存储层上,SQLite这时候会成为明显的瓶颈。后面我会专门讲什么时候该换回etcd。

2.2 单二进制架构:一个进程干完控制面的活

K3s第二个关键设计是单二进制。标准Kubernetes的控制面由kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy、etcd这些独立进程组成,每个进程都要单独维护、单独监控、单独升级。K3s把这些组件全部编译进一个二进制文件里,安装后在系统里看到的就是一个叫k3s的进程。

这个设计带来的好处是运维模型被彻底简化了。节点上只要确保一个二进制文件版本正确,升级就是"换文件、重启服务"这两步。进程数量减少直接带来内存占用下降,这也是K3s敢说"512M内存可以跑起来"的主要原因之一。对比一下:完整版K8s控制面空载状态轻轻松松吃掉1.5G以上内存,K3s空载时通常可以控制在几百MB级别,中间差出来的资源就是业务容器的空间。

这里补充一个细节:K3s默认使用内嵌的containerd作为容器运行时,不再额外装Docker。对边缘设备来说,少一个Docker守护进程也是实打实的资源节省。当然它也保留了docker作为CRI的兼容选项,但默认路径就是最省资源的那条。

2.3 内置的组件策略:开箱即用,而不是开箱选型

完整版Kubernetes装完只是个空壳,后面的CNI、Ingress、StorageClass、DNS、监控指标全都要你自己选型安装。K3s的策略反着来:把边缘场景最常见的一批组件直接内置。

  • Ingress:默认装好Traefik,一条Ingress规则就能把流量打进来。
  • Service LoadBalancer:K3s自带klipper-lb,在裸金属和边缘节点上能给Service分配一个本机端口,模拟LoadBalancer语义。
  • 本地存储:内置local-path-provisioner,Pod声明PVC时自动在节点磁盘上创建目录,对单机边缘场景非常实用。
  • DNS集群内解析:CoreDNS直接配好,Pod之间用服务名互相访问开箱即用。
  • Helm控制器:用HelmChart定义的方式维护集群内置组件,省去手动helm install一堆杂事。

这套"全家桶"策略在云端可能会被吐槽不够定制化,但在边缘场景里非常合理。边缘工程师往往不是专职K8s运维,他们要的是"装完就能跑业务",K3s默认给他们一套可用的最小可用集群。大部分组件都可以通过--disable参数关掉,需要自定义的时候再换成自己的方案。

2.4 轻量化不是白来的:缩水项必须心里有数

K3s做减法的同时,有些能力是明确被舍弃或弱化的。我之前踩过坑才意识到,这些不是K3s的bug,而是设计取舍:

  • 存储能力默认是单机磁盘,local-path没有副本概念,磁盘坏了数据就没了。边缘单机接受这个风险,但数据库类任务不能这么干。
  • SQLite不是网络存储,多节点共用一个数据目录的那套玩法不存在,高可用必须另配存储后端(后面细说)。
  • 内置的Traefik版本和社区最新版可能有差异,部分高级路由注解不生效。
  • 去掉了一些云厂商相关的provider代码,公共云上想用云盘、云LB,要么开外挂配置,要么换标准K8s。

我的经验是:把K3s当成"为边缘和受限环境定制的Kubernetes",而不是"功能残缺的Kubernetes",用它的默认能力去匹配业务需求,踩坑概率会小很多。

3. 实操演示:三行命令拉起K3s集群并部署Nginx

3.1 安装前的环境准备与自检

我在实验室里用两台虚拟机演示,一台作为server节点(2C4G,Ubuntu 20.04),一台作为agent工作节点(2C2G)。先把系统基础环境准备好:

sudo apt update && sudo apt install -y curl df -h /var/lib/rancher # K3s数据默认放在这里,确保有5G以上空闲

然后是K3s提供的一个体检工具,安装前看当前环境是否满足运行条件:

sudo k3s check-config

这个命令会检查内核模块、cgroup配置、iptables、swap等一堆项。如果输出里有标红的Warning,先处理掉再装。最常见的是swap没关或者overlay内核模块没加载,装完才发现的坑比提前发现要难处理得多。

3.2 Server节点安装

官方安装脚本一行搞定:

curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644

--write-kubeconfig-mode 644是为了让当前用户直接读kubeconfig,不需要每次操作都sudo。安装脚本做完的事情包括:把k3s二进制放到/usr/local/bin、创建/etc/rancher/k3s/k3s.yaml、注册systemd服务并启动。

装完后验证:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml k3s kubectl get nodes

这时候应该看到server节点状态为Ready。注意这里用的是k3s kubectl,因为K3s把kubectl客户端也打包进同一个二进制里了,不用另外装kubectl。如果你本机已经有kubectl,直接用kubectl --kubeconfig /etc/rancher/k3s/k3s.yaml也可以。

3.3 加入Worker节点

在边缘场景里,一个站点往往是"1台server + 若干台agent"的形态。在server节点上先拿到token:

sudo cat /var/lib/rancher/k3s/server/node-token

然后到agent节点上执行:

curl -sfL https://get.k3s.io | K3S_URL=https://192.168.1.10:6443 K3S_TOKEN=<你的token> sh -

等一两分钟,回到server节点验证:

k3s kubectl get nodes -o wide

两个节点都应该Ready。这里说个经验:边缘agent节点和server之间的网络质量往往不好,如果加入失败先别急着重装,仔细看journalctl -u k3s-agent的日志,十次里有八次是6443端口没通或者token抄错了。

3.4 部署第一个工作负载:Nginx

集群起来了,最快验证业务跑通的方式就是部署一个Nginx并暴露端口:

kubectl create deployment nginx-demo --image=nginx:alpine --replicas=2 kubectl expose deployment nginx-demo --port=80 --type=NodePort kubectl get svc nginx-demo

NodePort默认分配的是30000以上的端口,拿到端口号后直接访问:

curl http://192.168.1.11:307xx

能看到Nginx默认首页就说明整个链路通了。如果想让入口更优雅一点,可以用K3s自带Traefik因为默认装好了,直接建一条Ingress以外的方式其实很多:

kubectl create ingress nginx-demo --rule="nginx.demo.local/*=nginx-demo:80"

然后在访问端把域名解析到任意节点IP,或者加hosts记录,就能通过Traefik访问服务了。

4. 边缘场景里的真实形态:边缘智能、实训设备与轻量工作流

4.1 边缘智能:把AI推理从云端搬到现场

边缘智能这个词这几年很热,核心逻辑很简单:如果所有计算都在云端完成,数据来回传输的延迟可能几百毫秒,工业质检、AGV调度、视频安防这类实时性要求高的场景根本等不起。所以AI模型不能只放在云端服务器上,必须下沉到靠近数据源头的地方,让推理在本地完成,云端只承担训练和下发模型的工作。

K3s在这种架构里扮演的角色是"现场的运行时和调度器"。一套典型的边缘智能部署大概是这样的:K3s节点上跑着模型推理容器,通过设备插件把GPU、NPU或VPU算力挂载进容器;输入侧有摄像头或传感器容器,通过RTSP或者MQTT把数据流喂给推理服务;输出侧接本地告警或断点续传,把关键结果异步回传云端。模型更新时,云端推送新镜像,K3s完成滚动更新。

算力敏感型任务通常用工业PC或带GPU的边缘盒子,这类设备的内存虽然比树莓派大,但和云服务器还是没法比。K3s在这个位置的优势是:占资源少,多出来的算力可以给推理模型;节点自治能力强,断网的时候本地容器继续跑,网络恢复后再同步状态。

4.2 工业互联网边缘计算实训箱:教学设备里的隐藏主角

我接触过不少做工业互联网实训设备的厂商,他们的产品形态是"边缘计算实训箱":一个加固机箱里装着一块边缘计算板卡、若干工业传感器接口模块和一套预装好的软件环境,用来给高职院校和企业培训用。这类设备有个共性——配置不高无法承载完整K8s,但教学大纲里又必须涉及容器编排、微服务部署、工业协议转换这些云原生概念。

K3s几乎成了这类实训箱的默认基础设施。原因很简单:实训箱是让学生反复折腾的,经常被玩坏、被重置,K3s的单二进制安装和卸载都很干净,重装一套只要几分钟。而且课堂上通常跑的是Modbus采集、OPC-UA网关、边缘算法等轻量容器,K3s完全撑得住。如果你做类似设备,把K3s预装进镜像里,让学生从kubectl基础命令开始学,比让他们先折腾etcd集群友好太多。

4.3 轻量级工作流和开源边缘平台

边缘站点也需要自动化。很多团队用K3s承载轻量级工作流引擎,比如把Tekton、Argo Workflows这类流水线框架跑在单节点的K3s上,实现边缘侧的定时任务、模型更新流水线、数据清洗作业。这些工作流调度框架在完整K8s上很重,但在K3s上跑反而刚刚好——低资源、秒级调度、够用的持久化。

另外,边缘计算开源平台这个方向上,K3s也经常充当底层底座。像OpenYurt、SuperEdge这类面向边缘的Kubernetes增强项目,它们关注的是边缘自治、云边协同、单元化部署这些上层能力,而不是重造一个容器编排内核。在这些项目的部署拓扑里,边缘侧节点往往就用K3s充当轻量级Kubernetes发行版,云端保留完整K8s控制面。

5. 同类轻量级方案横向对比:K3s、k0s、microk8s、minikube怎么选

5.1 主要候选方案特点

我这些年把市面上的轻量级方案基本都用过一轮,整理了一张对比表供参考:

方案维护方安装方式组件策略最适合的场景
K3sSUSE/Rancher生态脚本或二进制,支持离线包内置Traefik、ServiceLB、local-path等边缘生产、资源受限设备、Rancher托管
k0sk0s开源社区单二进制极简,默认只带containerd,其余自己装需要高度定制、合规要求严的运维团队
microk8sCanonicalsnap命令安装插件式,按需enable/disableUbuntu生态下的开发测试、小团队预生产
minikubeKubernetes社区二进制或包管理器默认最小集,插件丰富本机开发、学习kubectl
kindKubernetes社区Docker容器模拟节点无内置附加件本地CI、测试Kubernetes版本兼容性

这里多说一句k0s。它和K3s在很多方面很像,也是单二进制搞定控制面,也支持外部存储后端做高可用。但k0s默认不给你内置任何Ingress、存储、负载均衡,这意味着你要从头选型安装。对喜欢掌控一切的标准化团队,这是一个优点;对想尽快跑业务的边缘工程师,K3s的开箱即用更实在。K3s名字的由来也是个有意思的梗:K8s砍掉5个字母变成K3s,意思是"比Kubernetes轻一半还多"。

5.2 按场景给出选型思路

我给周围朋友的建议一向很直接:

  • 边缘生产设备、需要长期无人值守运维的,优先K3s。组件齐全、升级路径成熟、出问题能搜到大量实践案例,这是其他轻量级方案比不了的生态优势。
  • 公司内部对组件选型卡得非常死、所有组件都要自己定制的,看k0s。它天生就是"干净的Kubernetes",不带任何偏见。
  • 纯粹自己电脑上学习、练手,或者CI里快速起集群验证代码,用minikube或kind,别占着边缘设备折腾。
  • 如果整个公司已经在用Rancher管理集群,那边缘侧无脑K3s,Rancher对K3s的支持深度是原生级别的。

补充一个容易被忽略的点:K3s现在也是CNCF生态里的重要项目,这意味着它不是某个公司的闭源玩具,而是有独立治理和大量社区贡献的开源项目。选型时这一条可以减少很多"会不会突然没人维护"的顾虑。

6. 生产环境里的坑与调优清单:写在最后面的干货

6.1 SQLite写入瓶颈和正确的高可用姿势

K3s默认用SQLite看似省事,但一旦业务对API Server的写请求密集起来,问题就来了。我遇到过调度大量Job的场景,每分钟要创建几百个Pod对象,控制面CPU没爆,但K3s的API响应开始变慢,Pod创建时间明显拉长。最后查下来瓶颈就是Kine把高频写操作翻译成SQLite的串行写入,事务排队严重。

如果你的边缘业务也存在类似的高频状态变更,或者你想构建一个多server的高可用集群,建议直接用内置的嵌入式etcd模式。在第一个server节点上初始化:

curl -sfL https://get.k3s.io | sh -s - server --cluster-init

后面的server节点按普通server方式加入,但要把--server指向第一个节点,并带上集群token。三台server组成嵌入式etcd的高可用集群后,控制面具备多数派容错能力,存储层也从SQLite换成了真正的etcd。代价是多占一些内存和磁盘,但换取的是稳定性和容错能力,这笔账在关键业务上很划算。

6.2 证书轮换和升级路径,别拖到过期才发现

K3s默认签发的证书有效期是一年。虽然它内部做了自动轮换逻辑,但我在早期版本上遇到过kubeconfig里admin证书过期导致无法访问集群的情况。遇到这类问题别慌,两个处理思路:一是手动轮换,执行下面命令后重启服务:

sudo k3s certificate rotate sudo systemctl restart k3s

第二个思路是直接升级到新版本。K3s的升级模型很简单,重新跑一遍安装脚本并指定版本号:

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.28.5+k3s1 sh -

脚本会把新版二进制放到/usr/local/bin并重启服务。我要强调的教训是:边缘节点没有专职运维盯着,证书过期这种事最容易发生,最好在监控里设置一个"证书剩余有效期<60天"的告警,别等到Kubectl连不上再排查。

6.3 小内存小磁盘设备的资源规划经验

K3s虽然轻,也不是无底洞。在我那些4G内存、32G硬盘的设备上,长期稳定运行靠的是这几个参数:

curl -sfL https://get.k3s.io | sh -s - \ --write-kubeconfig-mode 644 \ --disable traefik \ --kubelet-arg system-reserved=cpu=200m,memory=200Mi \ --kubelet-arg eviction-hard=memory.available<300Mi

--disable traefik这一步很多人不理解:做边缘业务时我经常不想要默认的Ingress,因为边缘侧流量入口往往是MQTT或私有协议,用不到HTTP路由,关掉能省几十MB内存。system-reserved和eviction-hard是给kubelet划定底线,防止业务容器无限吃内存把系统拖死。还有一个容易忽略的:local-path的PV默认落在/var/lib/rancher/k3s/storage,小硬盘设备上跑日志容器或者模型文件缓存,很容易把根分区写满,建议提前把这个目录挪到大容量分区或者单独挂载。

6.4 离线部署:边缘场景里最实用的技能

最后讲离线部署,这是边缘项目和云端项目最大的差异点。很多边缘现场没有公网,或者只有极差的窄带网络,安装脚本远程拉包这条路直接堵死。K3s支持完整离线安装,我常用的流程是:

在一台能上网的机器上下载离线镜像和二进制:

# 从GitHub Release拿到k3s二进制和k3s-airgap-images-amd64.tar

把文件拷到目标节点后,镜像放到指定目录:

sudo mkdir -p /var/lib/rancher/k3s/agent/images/ sudo cp k3s-airgap-images-amd64.tar /var/lib/rancher/k3s/agent/images/

然后跳过下载直接本地安装:

sudo cp k3s /usr/local/bin/ sudo chmod +x /usr/local/bin/k3s INSTALL_K3S_SKIP_DOWNLOAD=true ./install.sh

安装脚本和二进制、镜像包一起打包,整套东西几百MB左右,用U盘或者内网共享盘就能分发到所有边缘站点。我现在的习惯是每次升级都在本地准备一套离线包,不管现场有没有网,先保证能装、能升、能救急。

最后说点个人的体会。K3s解决了我很大一部分"边缘上也想用Kubernetes"的诉求,但它不是银弹。我现在的选型原则很朴素:节点的资源越紧张、站点数量越多、专职运维越少,就越优先考虑K3s;凡是核心数据库、强一致缓存这类需要高写入性能的场景,就不要指望默认的SQLite扛着,动手换上嵌入式etcd或者干脆用完整版。理解了它做的每一个取舍,你就不容易在边缘场景里翻车。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询