TT Lab
博客

한국어 English 日本語 中文

开始
博客

博客

k3s·RKE2·k0s 结构对比:控制平面如何启动以及默认包含什么

状态:草稿 (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)

用一句话总结这三个发行版的特点如下。

3. 控制平面是如何启动的

最大的区别在于 以何种形态启动控制平面组件。

k3s 서버 한 대 · v1.37 문서 기준 k3s server — 한 프로세스 안에서 함께 돈다 kube-apiserver scheduler controller-manager kubelet kube-proxy flannel(CNI) kine → SQLite 네트워크 정책 helm-controller 따로 띄우는 자식 프로세스 containerd(번들) 애드온(파드): CoreDNS · Traefik · ServiceLB · local-path · metrics-server RKE2 서버 한 대 · v1.36~1.37 문서 기준 rke2 server — 감독만 한다 containerd(번들) kubelet kubelet 이 띄우는 정적 파드 etcd kube-apiserver scheduler controller-manager 애드온(헬름 차트): Canal · CoreDNS · Traefik(1.36+) · metrics-server k0s 컨트롤러·워커 분리 · v1.36 문서 기준 k0s controller 각각 따로 뜨는 프로세스 etcd kube-apiserver scheduler controller-manager konnectivity-server kubelet·containerd 없음 k0s worker 다른 노드, 프로세스 containerd(번들) kubelet 파드로 뜨는 것 kube-router(CNI) kube-proxy CoreDNS · metrics-server k0s 는 인그레스·서비스 LB·스토리지를 번들하지 않는다. RKE2 도 ServiceLB 는 기본 꺼짐, 스토리지 클래스는 기본으로 없다.
图:三种发行版的组件结构对比

k3s:打包在一个进程中

k3s server 单个程序在 同一个进程内 运行 kube-apiserver、调度器、控制器管理器、kubelet、kube-proxy、flannel、网络策略控制器、kine 和 helm-controller。这是 README 将其列为节省内存主要原因的设计,因为每个组件原本需要单独持有的运行时和缓存现在只需使用一次。

containerd 和 runc 会与二进制文件打包在一起,但它们是独立执行的。查看 k3s 源码(pkg/agent/containerd)可知,k3s 会将 containerd 作为单独的进程启动。

在运维中,这种结构意味着:

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 端口)。

如果想打破这种分离,可以使用两个参数:

此外,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 k3s server kine(etcd API 흉내) SQLite 서버를 늘릴 수 없다 백업: db 폴더 + 토큰 ② k3s HA — 내장 etcd 또는 외부 DB 고정 등록 주소 :6443 고정 등록 주소 :6443 server etcd server etcd server etcd 홀수 대, 최소 3대 첫 서버에 --cluster-init server server DB 2대 이상 + 외부 DB MySQL · PostgreSQL · etcd ③ RKE2 HA — 서버 3대, etcd 정적 파드 고정 등록 주소 — 등록 :9345 · API :6443 server etcd 파드 server etcd 파드 server etcd 파드 agent agent 홀수 대, 3대 권장 · 서버도 워크로드를 받는다 에이전트는 0대여도 된다 ④ k0s HA — 컨트롤러 3대, 워커는 따로 컨트롤러 etcd 컨트롤러 etcd 컨트롤러 etcd 로드밸런서 또는 CPLB 컨트롤러는 노드 목록에 나오지 않는다(kubelet 없음) 워커 워커 워커 워커는 LB 를 거쳐 붙는다 (노드 로컬 LB 도 있음) 저장소는 기본 etcd, kine(SQLite·MySQL·PostgreSQL)도 고를 수 있다.
图:三种发行版的数据存储与 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 的途径有两种:

无论哪种方式,都需要在服务器前面放置一个 固定注册地址(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)端口。如果没有外部负载均衡器,可以从以下两种方式中选择:

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 版本。

登录后即可点赞

评论

还没有评论。

登录后即可发表评论