状态:草稿 (2026-10-13),基于官方文档 + 部分实测。 结构和默认值已于 2026-10-13 通过查阅官方文档和 GitHub 仓库进行确认(k3s v1.37.1+k3s1、RKE2 v1.37.1+rke2r1、k0s v1.36.4+k0s.1 为当日最新稳定版)。带有“实测”标记的值是在 TT Lab 课程的实验虚拟机中亲自搭建测试的结果(2026-08~09,版本同步记录)。编写规则:以实测数据为准,未能测出的标记为“未实测”,在文档中未找到的标记为“未确认”。
目录
1. 为什么要将这三者放在一起看
尝试自主搭建 Kubernetes 的团队最先遇到的名字就是 k3s、RKE2 和 k0s。这三者都给出了相同的承诺:“下载一个二进制文件并注册为服务,集群即可启动”。因此,它们表面上看起来非常相似。
然而,一旦开始运维,差异就会显现出来。发生故障时去哪里查看日志、 etcdctl 是否可以使用、是否从一开始就安装了 Ingress、控制平面是否显示在节点列表中,这些都完全不同。这种差异并非源于功能列表,而是源于 设计与默认值。本文通过图表对比了它们的设计。安全与运维将在 第二篇中探讨,如何选择将在 第三篇中介绍。
2. 出身与目标
| k3s | RKE2 | k0s | |
|---|---|---|---|
| 最初创建方 | Rancher(现属 SUSE) | Rancher (SUSE) | Mirantis |
| 其他名称 | — | RKE Government | — |
| CNCF | Sandbox(2020-08-19 采纳) | 非 CNCF 项目(仅在认证发行版列表中) | Sandbox(2025-01-19 采纳) |
| 目标场景 | 边缘计算、物联网、ARM 板、CI、开发环境 | 安全与合规,尤其是美国联邦政府部门 | 消除安装与运维阻力的通用发行版 |
| 2026-10-13 最新稳定版 | v1.37.1+k3s1 (2026-09-30) | v1.37.1+rke2r1 (2026-09-30) | v1.36.4+k0s.1 (2026-09-19) |
用一句话总结这三个发行版的特点如下。
- k3s 的核心目标是“精简”。存储库的 README 解释说,它将多个组件在一个进程中运行以减少内存,并从上游 Kubernetes 中删除了内置存储驱动程序和云提供商。它透露对上游代码的自定义修补不到 1,000 行,强调它是一个发行版而非分支。
- RKE2 结合了 k3s 的安装与运维方式以及旧版 RKE1 的“接近上游 Kubernetes”的特点。其目标非常明确:即使运维人员几乎不干预,也能通过 CIS 基准测试,支持 FIPS 140-2,并在构建过程中使用 Trivy 持续扫描 CVE。依赖于 Docker 的 RKE1 已于 2025-07-31 终止支持,SUSE 建议用户迁移到 RKE2 或 k3s。
- k0s 主打“零”。官网提到的“零”有三个:零阻力的安装(Zero Friction)、除了主机内核外无其他依赖的单一二进制文件(Zero Deps)、采用 Apache 2 许可证的免费(Zero Cost)。经常被引用的“zero overhead”(零开销)这一说法在官方页面上并未找到(未确认)。
3. 控制平面是如何启动的
最大的区别在于 以何种形态启动控制平面组件。
k3s:打包在一个进程中
k3s server 单个程序在 同一个进程内 运行 kube-apiserver、调度器、控制器管理器、kubelet、kube-proxy、flannel、网络策略控制器、kine 和 helm-controller。这是 README 将其列为节省内存主要原因的设计,因为每个组件原本需要单独持有的运行时和缓存现在只需使用一次。
containerd 和 runc 会与二进制文件打包在一起,但它们是独立执行的。查看 k3s 源码(pkg/agent/containerd)可知,k3s 会将 containerd 作为单独的进程启动。
在运维中,这种结构意味着:
- 日志集中在一处。
journalctl -u k3s单个程序中混合输出了 apiserver 和 kubelet 的日志。 crictl ps无法通过该命令找到控制平面容器,因为它们根本不是容器。- 在 kubeadm 中学到的“
/etc/kubernetes/manifests的静态 Pod 修改方法”在这里行不通。各种标记是通过 k3s 配置文件或--kube-apiserver-arg等参数传递的。
RKE2:由 kubelet 作为静态 Pod 启动
rke2 server 进程本身不直接运行控制平面。它的工作是监督:启动 containerd,如果 containerd 死亡它自己也会结束;启动 kubelet,如果其停止则将其重启。然后,它将 etcd、kube-apiserver、控制器管理器和调度器的 静态 Pod 清单文件写入 /var/lib/rancher/rke2/agent/pod-manifests/ 中。kubelet 读取这些清单并将其作为容器启动。这与 kubeadm 的形态相同。
kubelet、containerd、kubectl 等可执行文件包含在 rke2-runtime 镜像中,在首次启动时从中解压出来。CNI、CoreDNS、Ingress、metrics-server 等插件由内置的 helm-controller 通过 Helm Chart 进行安装。
这种结构有一个陷阱: systemctl stop rke2-server 不会停止静态 Pod。 在 TT Lab 的 RKE2 实验(v1.36.4+rke2r1)中,即使停止了服务,以 root 身份运行的 etcd 容器仍然完好地保留着(实测)。若要完全关闭节点,需使用安装包中附带的 rke2-killall.sh 。这种差异实际会引发什么样的事故,我们将在第二篇中看到。
k0s:分别独立启动,控制器不是节点
k0s 不将控制平面组件作为容器运行,而是将它们作为 各自独立的进程(文档中称为“naked”进程)启动,并通过 k0s 二进制文件来监督这些进程。etcd、kube-apiserver、调度器、控制器管理器和 konnectivity-server 会分别启动。这些可执行文件包含在 k0s 二进制文件中,并在首次运行时解压到 /var/lib/k0s/bin 中。
最显眼的差异是 控制节点上默认既没有 kubelet 也没有容器运行时。因此,控制器不接收工作负载,也不会出现在 kubectl get nodes 中。当 API 服务器需要与工作节点的 kubelet 或 Pod 通信时,会通过 Konnectivity 隧道(代理 8132 端口)。
如果想打破这种分离,可以使用两个参数:
--enable-worker:让控制器也扮演工作节点的角色。FAQ 建议仅将其用于测试、开发或 PoC。--single:单节点模式。--enable-worker它包含 但关闭了多节点所需的功能,因此 以后无法扩充节点。
此外,k0s 将控制平面组件运行在非 root 的专用系统用户下。文档仅写到 k0s install 会创建这些系统用户,而具体的用户名是在源码(pkg/constant/constant.go,v1.36.4+k0s.1 标签)中确认的:etcd 是 etcd,API 服务器是 kube-apiserver,调度器是 kube-scheduler,Konnectivity 是 konnectivity-server 用户。控制器管理器的用户未能确认(未确认)。
用一句话总结三种结构
| k3s | RKE2 | k0s | |
|---|---|---|---|
| 控制平面形态 | 单个进程 | 由 kubelet 启动的静态 Pod | 每个组件对应独立进程 |
| 容器运行时 | 内置 containerd·runc | 内置 containerd(从运行时镜像中解压) | 内置 containerd·runc |
| 服务器(控制器)是否接收工作负载 | 接收 | 接收 | 默认不接收 |
| 控制平面日志 | 单个 k3s 服务日志 | Pod 日志(/var/log/pods) |
k0s 服务日志 |
| 插件安装方式 | 清单目录 + helm-controller | helm-controller | 内置清单,Helm 扩展可选 |
4. 存储与高可用 (HA)
k3s:以 SQLite 启动,可迁移至 etcd
单个 k3s 服务器的默认存储是 SQLite 。由于 API 服务器只懂得与 etcd 对话,因此中间插入了 kine 来模拟 etcd API,并在底层写入 SQLite。它很轻量,但无法扩展服务器数量,也无法使用 etcd 工具。在 TT Lab 实验(v1.35.8+k3s1)中,如果在 SQLite 状态下执行 k3s etcd-snapshot save ,系统会以 etcd datastore disabled 予以拒绝(实测)。
走向 HA 的途径有两种:
- 内置 etcd。 将第一台服务器以
--cluster-init启动,并将其他服务器通过相同的令牌加入。需要奇数台机器,最少 3 台。原本以 SQLite 运行的服务器如果以--cluster-init重新启动,也会迁移至 etcd。在实验中,重启 12 秒后 API 便恢复正常,state.db变更为state.db.migrated,且迁移前创建的 ConfigMap 的 UID 保持不变(实测,v1.35.8+k3s1)。 - 外部数据库。 2 台或更多服务器指向相同的 MySQL、MariaDB、PostgreSQL 或 etcd。文档认证的版本包括 etcd 3.5.21、MySQL 8.0·8.4、MariaDB 10.11·11.4、PostgreSQL 15.12·16.7·17.3(2026-10-07 更新文档)。此时也是由 kine 在 SQL 数据库前模拟 etcd API。
无论哪种方式,都需要在服务器前面放置一个 固定注册地址(L4 负载均衡器、轮询 DNS 或虚拟 IP 之一)。
RKE2:从一开始就是 etcd
若无其他配置,RKE2 默认使用 内置 etcd 。在高可用(HA)集群中,建议配置奇数台服务器(共 3 台),并且服务器默认也会承担工作负载,因此 3 台服务器、0 个代理节点是最低的高可用(HA)配置。节点通过固定注册地址的 9345 端口加入集群,API 则使用 6443 端口。
虽然也可以使用 SQLite,但文档中将其标注为“实验性(Experimental)”且仅支持单台服务器。外部 SQL 数据库可以通过 kine 使用(文档认证版本包括 etcd 3.6.7、MySQL 8.4.8、MariaDB 11.4.10、PostgreSQL 18.3)。不过,其备份流程在文档中也被归类为“实验性”步骤。
k0s:多台使用 etcd,单台使用 SQLite
k0s 的存储配置(spec.storage.type)支持 etcd 和 kine 两种模式之一,默认生成的配置为 etcd。文档和 README 的功能列表中将默认值描述为“多节点使用 etcd,单节点使用 SQLite”,并指出也可以将 MySQL 和 PostgreSQL 放在 kine 后面。
--single 我们在实操中确认了单节点会使用 SQLite。如果在通过 --single 搭建的 k0s 中执行 k0s etcd member-list ,系统会提示 wrong storage type: kine 并予以拒绝(实际测得)。若要操作 etcd,必须通过 --enable-worker 来搭建。
高可用(HA)建议采用 3 个或 5 个控制器。虽然对 k0s 而言 2 个控制器也属于 HA,但文档指出从 etcd 法定人数(Quorum)的角度来看并非真正的高可用。控制器前方需要部署一个 TCP 负载均衡器,将流量转发至所有控制器的 6443(API)、8132(Konnectivity)和 9443(k0s 加入 API)端口。如果没有外部负载均衡器,可以从以下两种方式中选择:
- CPLB(Control Plane Load Balancing,控制平面负载均衡):各个控制器通过 keepalived 共享虚拟 IP(VIP)。不能与
--single一起使用。 - NLLB(Node-Local Load Balancing,节点本地负载均衡):在每个工作节点上部署一个小型负载均衡器(默认使用 Envoy),将请求分发到各个控制器。默认情况下处于关闭状态。
5. 默认包含的组件
安装后默认运行哪些服务,是这三者之间差异最大的地方。
| 组件 | k3s (v1.37 文档) | RKE2 (v1.36~1.37 文档) | k0s (v1.36 文档) |
|---|---|---|---|
| CNI | flannel(VXLAN) | canal(flannel VXLAN + Calico 策略) | kube-router |
| CNI 选项 | 更改 flannel 后端,或者禁用后自行安装 | cilium、calico、flannel、none、multus(辅助) | calico、custom |
| NetworkPolicy | 内置控制器(基于 kube-router) | canal 的 Calico | kube-router |
| Ingress | Traefik v3 | 从 v1.36 开始,新集群默认使用 Traefik,在此之前使用 ingress-nginx | 无 |
| 服务 LoadBalancer | ServiceLB(klipper-lb) | 提供 ServiceLB 但 默认关闭 | 无内置(未确认文档中的明确表述) |
| StorageClass | local-path | 无(实际测得) | 无(通过 CSI 自行安装) |
| DNS | CoreDNS | CoreDNS(+ 自动扩缩容器) | CoreDNS |
| metrics-server | 有 | 有 | 有 |
| 默认网段(Pod·Service) | 10.42/16 · 10.43/16 | 10.42/16 · 10.43/16(实际测得) | 10.244/16 · 10.96/12 |
对于 RKE2 的 Ingress,需要格外小心,因为答案随版本而异。由于 ingress-nginx 的上游支持已于 2026 年 3 月终止,RKE2 从 v1.36 开始将新集群的默认 Ingress 更改为了 Traefik。服务文档指出 ingress-nginx 在 v1.36 中被标记为废弃(Deprecated)并在 v1.37 中移除,而 v1.37 发行说明记载它仅保留了与 Traefik 一起选择的迁移组合(2026-10-13 确认)。 对于已经运行的集群,即使进行升级也会保留原本使用的 Ingress。 因此,要回答“RKE2 的 Ingress 是什么”,必须先知道集群最初创建时的版本。在 TT Lab 实验虚拟机(v1.36.4+rke2r1)中,默认的 Ingress Class 也是 traefik,CNI 是 canal,且没有 StorageClass(实际测得)。
与此相反,k3s 采取的是“全盘塞给你,再让你去关闭”的路线。可以向 --disable 传递 traefik, servicelb, local-storage, metrics-server, coredns 参数。常见的失误是直接通过 kubectl delete 删除 Traefik。由于 k3s 在每次启动时都会重新写入并应用默认组件的清单(Manifest),因此重启后 Traefik 会死灰复燃。在实操中,在执行 systemctl restart 之后仅 20 秒,Traefik Deployment 就恢复了(实际测得,v1.35.8+k3s1)。若要将其关闭,必须在所有服务器上同时配置 --disable 。
而 k0s 则走的是“什么都不内置,让你自己挑选”路线。README 的范围(Scope)部分明确指出它不内置 Ingress、Service Mesh 和存储,并将 MetalLB、Traefik、OpenEBS 等组件仅作为示例引导。对于将要部署实际服务的集群而言,这种选择是一大优势。因为默认自带的东西只有在其他服务对其产生依赖时才会显现出来,而到那时再将其剥离会变得更加繁琐。
6. 网段看似相同,实则有别
表格的最后一行引发的问题比想象中要严重得多。k0s 的默认网段(Pod 为 10.244/16,Service 为 10.96/12)与标准 Kubernetes 中常用的值相同。Service 网段是 kubeadm 的默认值,而 Pod 网段则是被 flannel 示例广泛普及的值。因此,如果在其他 Kubernetes 集群内部的虚拟机中以默认值搭建 k0s,内部的 k0s 会将外部集群分配的 DNS 服务器地址(即外部 Service 网段 10.96/12 内的地址)误认为是他自己的 Service IP。我们在搭建 TT Lab 实验环境时确实遇到了这种情况(实际测得)。当时 DNS 崩溃导致无法拉取 CNI 镜像,进而因为没有 CNI 导致 CoreDNS 无法启动,陷入了死锁状态,但在屏幕上看到的错误信息却只有镜像拉取超时。
而 k3s 和 RKE2 使用的 10.42/10.43 由于是非标准网段,因此无意中避开了这一问题。记住“用 k3s 行得通”并非因为精心设计,而只是一场巧合,这样在更换发行版时就能避开相同的陷阱。网段必须在初次创建时决定,并且这三个发行版在创建完成后都很难再进行修改。
小 T 总结。 它们三个都号称“单一二进制文件”,长得像孪生兄弟,但拆开一看:一个是一个整体,一个是静态 Pod(Static Pod),另一个是各模块分立。由于发生故障时连日志去哪里找都不一样,因此在最初搭建时,请务必在脑海中理清它们的架构图。
参考资料
所有文档均查阅于 2026-10-13。docs.k3s.io 和 docs.rke2.io 的页面显示更新于 2026-10-07,docs.k0sproject.io 的稳定版为 v1.36.4+k0s.1 版本。
- k3s 文档: https://docs.k3s.io/,架构 https://docs.k3s.io/architecture,数据存储 https://docs.k3s.io/datastore,内置 etcd HA https://docs.k3s.io/datastore/ha-embedded,外部数据库 HA https://docs.k3s.io/datastore/ha,网络 https://docs.k3s.io/networking/basic-network-options,默认服务 https://docs.k3s.io/networking/networking-services,打包组件 https://docs.k3s.io/installation/packaged-components
- k3s 仓库: https://github.com/k3s-io/k3s (README,
pkg/agent/containerd/containerd.go),CNCF 项目页面 https://www.cncf.io/projects/k3s/ - RKE2 文档: https://docs.rke2.io/,架构 https://docs.rke2.io/architecture,内置 etcd https://docs.rke2.io/datastore/embedded,外部数据库 https://docs.rke2.io/datastore/external,HA https://docs.rke2.io/install/ha,网络 https://docs.rke2.io/networking/basic_network_options,默认服务 https://docs.rke2.io/networking/networking_services,v1.37 发行说明 https://docs.rke2.io/release-notes/v1.37.X
- RKE1 终止支持公告 (SUSE): https://suse.com/c/rke-end-of-life-by-july-2025-replatform-to-rke2-or-k3s
- k0s 文档: https://docs.k0sproject.io/stable/,架构 https://docs.k0sproject.io/stable/architecture/,配置 https://docs.k0sproject.io/stable/configuration/,HA https://docs.k0sproject.io/stable/high-availability/,CPLB https://docs.k0sproject.io/stable/cplb/,NLLB https://docs.k0sproject.io/stable/nllb/,网络 https://docs.k0sproject.io/stable/networking/,FAQ https://docs.k0sproject.io/stable/troubleshooting/FAQ/
- k0s 仓库: https://github.com/k0sproject/k0s (README,
pkg/constant/constant.go),主页 https://k0sproject.io/,CNCF 项目页面 https://www.cncf.io/projects/k0s/ - 实测记录:TT Lab“Kubernetes 发行版 — 从零搭建”课程的实验虚拟机记录(k3s v1.35.8+k3s1、RKE2 v1.36.4+rke2r1、k0s v1.36.4+k0s.0,2026-09-15 等)