Skip to content

필사 모드: 本地轻量级 Kubernetes 选型标准 —— 用数据存储和合规要求来区分 k3s、k0s、RKE2

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

引言 —— "轻量"不是选型标准

新搭建本地集群时,最常被问到的问题是"k3s 和 RKE2 到底哪个更好"。但如果用一张功能对比表来回答这个问题,通常会答错。三个发行版都是经过认证的 Kubernetes,都接近以单一二进制的形式分发,也都正式支持离线安装路径。光看功能清单是区分不出来的。

真正决定选型的大概有五条轴线,其中第一条 —— 数据存储 —— 是事后最难更改的。装完六个月之后才收到"得再加一台服务器节点"的需求,这时候才发现自己当初是用 SQLite 起步的,类似的情况并不少见。

本文把这些轴线逐一摆出来,最后针对三个具体场景给出答案。以下是核实基准。

发行版核实的版本系列核实时间主要出处
k3sv1.36.2+k3s12026-07-31docs.k3s.io
k0sv1.36.3+k0s.02026-07-31docs.k0sproject.io
RKE2v1.33.1+rke2r1 (文档示例)2026-07-31docs.rke2.io

轴线 1:数据存储 —— 一半的决定在这里就定了

k3s 的默认数据存储是 SQLite。官方 CLI 文档把 --datastore-endpoint 选项描述为"指定 etcd、NATS、MySQL、Postgres 或 SQLite(默认)的数据源名称"。而且在 SQLite 配置下没法扩展服务器节点。如果需要高可用,就必须转向内置 etcd 或接上外部数据存储。

# k3s —— 用内置 etcd 起步(第一台服务器)
k3s server --cluster-init

# k3s —— 外部数据存储(PostgreSQL 示例)
k3s server --datastore-endpoint="postgres://k3s:PASSWORD@10.10.30.5:5432/k3s?sslmode=require"

即便是已经用 SQLite 搭起来的集群,也有迁移路径。官方文档说明,把现有服务器带上 --cluster-init 参数重启,就能迁移到 etcd。不过这不是一个可以在没有备份的情况下在生产环境里尝试的操作。

k0s 通过 spec.storage.type 来指定,有效值是 etcdkine 两个。官方配置文档的示例展示的是 type: etcd;如果用 kine,则通过 spec.storage.kine.dataSource 里的连接字符串来接入 SQLite、MySQL、PostgreSQL 系列的后端。要接入外部管理的 etcd 时,在 spec.storage.etcd.externalCluster 下指定端点和 TLS 文件路径。

# k0s —— 内置 etcd(文档示例的基本形式)
apiVersion: k0s.k0sproject.io/v1beta1
kind: ClusterConfig
spec:
  storage:
    type: etcd
# k0s —— 接入外部管理的 etcd 集群
apiVersion: k0s.k0sproject.io/v1beta1
kind: ClusterConfig
spec:
  storage:
    type: etcd
    etcd:
      externalCluster:
        endpoints:
          - https://10.10.30.11:2379
          - https://10.10.30.12:2379
        etcdPrefix: onprem-cluster
        caFile: /etc/pki/etcd/ca.crt
        clientCertFile: /etc/pki/etcd/client.crt
        clientKeyFile: /etc/pki/etcd/client.key

RKE2 的概览文档没有明确说明数据存储。在这次核实范围内,我没能在官方文档正文中确认 RKE2 是否提供 SQLite 数据存储,如果目标是单节点超轻量配置,请在引入之前直接确认这一项。不过按 RKE2 的定位来看,想把这个发行版当成 SQLite 单节点来用的场景本身就很少见。RKE2 是把控制平面以静态 Pod 的形式启动的结构,文档自己给出的目标就是合规。

从离线部署的角度看,这条轴线的结论是这样的:如果一开始就能把服务器节点数定为 3 台,就用内置 etcd 起步。 在离线网络里,日后想加节点,意味着要从导入审核重新走一遍,迁移成本比普通环境高得多。而且内置 etcd 要求奇数节点。2 台配置的容错能力和 1 台一样,却白白多了一台要运维。

轴线 2:默认打包了什么 —— 剥离出去的成本

轻量级发行版为了做到"开箱即用",会预先打包一些组件。这在第一天是优点,到了六个月后想换掉 Ingress 控制器的那天,就变成了缺点。

k3s 在这一点上最直白。根据官方 CLI 文档,可以用 --disable 参数关闭的打包组件有 coredns、servicelb、traefik、local-storage、metrics-server、runtimes。这份清单原样写在文档里,这件事本身在实务中意义很大。

# /etc/rancher/k3s/config.yaml —— 想用别的 ingress 代替 Traefik 时
disable:
  - traefik
  - servicelb
# 在已经安装好的集群上关闭组件,manifest 可能会残留下来,导致组件复活。
# k3s 会监视 /var/lib/rancher/k3s/server/manifests,所以要一并清理。
sudo ls /var/lib/rancher/k3s/server/manifests/
sudo systemctl restart k3s
sudo k3s kubectl -n kube-system get pods

k0s 通过 spec.network.provider 指定网络提供方,按官方文档,有效值是 calico、kuberouter、custom,默认是 kuberouter。文档明确说明,选择 custom 意味着"用户要为所有 CNI 配置和主机层面的配置负责"。使用其他 CNI 这个决定,本身就等于宣布"一切自己来",这个结构选择很清晰,但没有中间地带。

RKE2 把 CNI 干脆整个拆成独立的镜像归档来分发。离线导入清单在这里就产生了差异。

RKE2 镜像归档内容离线导入时的判断
rke2-images.linux-amd64.tar.zst包含默认 CNI Canal 的完整打包默认配置的话,只要这一个
rke2-images-core.linux-amd64.tar.zst不含 CNI 的核心镜像替换 CNI 时,核心和 CNI 分开导入
rke2-images-cilium.linux-amd64.tar.zstCilium 专用镜像使用 Cilium 时与核心一起导入
rke2-images-vsphere.linux-amd64.tar.zstvSphere CPI/CSI 镜像vSphere 本地部署时追加

这种拆分在离线环境里确实有用。没有理由把用不到的 CNI 镜像装进介质、提交审核。反过来,如果导入清单没配对,只带进来了核心却漏掉了 CNI,节点就会卡在 NotReady。

轴线 3:进程部署方式 —— 单一二进制与静态 Pod

k3s 和 k0s 把控制平面组件都放在自己的进程里运行。在节点上敲 ps,也看不到一个叫 kube-apiserver 的独立进程。RKE2 不一样。官方概览文档明确说明"RKE2 把控制平面组件作为由 kubelet 管理的静态 Pod 来运行"。

这个差异带来了三个实际后果。

  1. 调试路径不一样。 在 RKE2 上,可以把 API 服务器的日志当作 Pod 日志来读,也能直接修改 manifest。在 k3s 和 k0s 上,只能翻查一份服务日志(journalctl)。在离线环境里得不到外部支持时,这个差异的体感会很明显。
  2. 上游文档能直接套用的程度不一样。 RKE2 自己的文档说,它"从 RKE1 继承了与上游 Kubernetes 的紧密对齐"。在互联网搜索被屏蔽的环境里,手边的 Kubernetes 教材能不能直接照搬使用,是一个比想象中更重要的条件。
  3. 资源占用不一样。 进程一旦分开,内存也会跟着分开。在只有 2 GB 内存的工控机上,这个差异是决定性的。

轴线 4:合规要求 —— RKE2 的 CIS 和 FIPS 到底是给谁用的

这条轴线,就是 RKE2 存在的理由。它的概览文档把目标领域明确写成"美国联邦政府部门的安全与合规",说明它能实现 FIPS 140-2 合规,并让集群能通过"CIS Kubernetes Benchmark v1.7 或 v1.8"。

CIS 配置文件只需一行配置就能打开。

# /etc/rancher/rke2/config.yaml
profile: 'cis'
# RKE2 v1.29 及以上版本可能需要一并添加的 API 服务器参数
kube-apiserver-arg:
  - 'service-account-extend-token-expiration=false'

官方加固指南说明,这个通用配置文件会自动套用与 RKE2 版本相匹配的基准控制项,所以升级时不需要修改配置值。不过主机准备工作必须提前做好,没做好的话,RKE2 会以致命错误中止启动

# 1) 创建 etcd 用户和用户组
sudo useradd -r -c "etcd user" -s /sbin/nologin -M etcd -U

# 2) 应用内核参数 —— RPM 系列
sudo cp -f /usr/share/rke2/rke2-cis-sysctl.conf /etc/sysctl.d/60-rke2-cis.conf
sudo systemctl restart systemd-sysctl

# 2') 非 RPM 系列(Ubuntu 等)
sudo cp -f /usr/local/share/rke2/rke2-cis-sysctl.conf /etc/sysctl.d/60-rke2-cis.conf
sudo systemctl restart systemd-sysctl

官方文档警告说,这个 sysctl 改动只应该在部署 Kubernetes 之前的全新安装中应用。在已经运行中的集群上重启 sysctl,会产生意料之外的副作用。

打开 CIS 配置文件之后会发生什么变化,文档里也整理清楚了:Pod 安全准入会在整个集群范围内强制设为 restricted(kube-system、compliance-operator-system、tigera-operator 除外),会部署一条把流量限制在同一命名空间内的网络策略,agent 的 manifest 和配置文件权限会从 644 收紧到 600,etcd 静态 Pod 会以 etcd 用户身份运行。

这里有一项大多数团队会漏掉的内容 —— 审计日志。

# RKE2 的默认审计策略什么都不记录。
# 必须把 level 从 None 改成 Metadata 或更高级别,日志才会被保留下来。
sudo vi /etc/rancher/rke2/audit-policy.yaml
sudo systemctl restart rke2-server.service
sudo tail -f /var/lib/rancher/rke2/server/logs/audit.log

在离线环境的审计中,面对"你们开启审计日志了吗"这个问题,回答"我们开了配置文件"是过不了关的,必须直接修改策略文件。

FIPS 的覆盖范围比想象中要窄

读 FIPS 文档时,有一句话必须确认清楚,是关于 CNI 的。官方文档明确说明,在支持的 CNI 里,只有默认的 Canal 是为 FIPS 合规而重新构建的。Cilium、Calico、Multus 都不在此列。

领域是否支持 FIPS(按官方文档)
API 服务器、控制器管理器、调度器、kubelet、kube-proxy用 GoBoring 编译器静态构建
etcd、containerd 及其 shim、crictl、runc用启用了 FIPS 的 Go 编译器静态构建
CoreDNS、Flannel、Calico Helm chart在范围之内
NGINX IngressGo 控制器用 BoringCrypto,C 服务器用经 FIPS 验证的 OpenSSL
Canal CNI已重新构建(默认项)
Cilium、Calico、Multus CNI未重新构建

所以如果"需要 FIPS"和"想用基于 eBPF 的 CNI"这两个要求同时存在,就必须放弃其中一个。这个决定如果在设计阶段没有做出来,往往会在审计前夕才不得不去更换 CNI。

还有一点值得坦白说清楚。如果合同或审计条款里没有要求 FIPS 和 CIS,就没有必要因为这个理由去选 RKE2。 在国内的金融、政务离线网络里,真正被要求的通常是 CIS 系列的加固和审计日志,而不是 FIPS 140 验证模块本身,这种情况并不少见。应该先确认需求文档里明确写了什么,再区分哪些是 RKE2 会自动帮你做的,哪些是不管选哪个发行版都得自己动手做的。

轴线 5:升级、支持周期,以及在小型节点上的占用

在离线网络里,升级意味着"把新的二进制和新的镜像包带进来,替换掉旧的"。三个发行版在这个骨架上是一样的,但自动化工具的特点不同。

发行版离线升级路径多节点自动化
k3s把新归档放进镜像文件夹并删除旧的,替换二进制,重新运行 install.shsystem-upgrade-controller (需要导入相关镜像)
k0s部署新的镜像包和二进制之后重启服务k0sctl apply,和安装用的是同一条命令
RKE2放置新的制品目录,重新运行 install.shsystem-upgrade-controller 系列

k3s 的自动升级在离线环境里需要额外的工作。官方文档明确说明,要使用自动升级,rancher/k3s-upgraderancher/system-upgrade-controllerrancher/kubectl 这三个镜像必须在私有仓库里。如果导入清单里没有这三个镜像,自动升级会在第一次尝试时就卡住。

支持周期方面,三个发行版都跟随上游 Kubernetes 的次要版本节奏。在离线环境里,重要的不是支持周期本身,而是导入周期和支持周期之间的匹配度。如果导入审核一个季度才能走一次,而补丁是按月发布的,实质上就变成了每个季度一次性上一堆累积补丁。这种情况下,把次要版本固定得低一档、用一条已经稳定下来的补丁线,事故会更少。

资源占用方面,从轴线 3 的进程部署方式那里就已经拉开差距了。具体数字会因 CNI 选择、节点数量、工作负载而有很大差异,这里就不引用具体数字了。只给出判断标准:如果是内存 4 GB 以下的工控节点,就把静态 Pod 方案从候选里排除。 控制平面组件各自作为独立容器启动的结构,在那种硬件上没有余量。

轴线汇总表

轴线k3sk0sRKE2
默认数据存储SQLite (文档明确说明)etcd (按配置文档示例)概览文档未明确说明 —— 需要确认
高可用扩展需要迁移到内置 etcd 或外部数据库内置 etcd 或外部 etcd基于静态 Pod 的多服务器
外部数据库支持etcd、NATS、MySQL、Postgreskine 数据源未能确认
默认 IngressTraefik (可禁用)单独部署ingress-nginx 系列 (概览文档未明确说明)
CNI 选择默认 Flannel,可替换默认 kuberouter,可选 calico、custom默认 Canal,Cilium/Calico/Multus 镜像归档分离
控制平面部署方式单一进程单一进程由 kubelet 管理的静态 Pod
离线镜像导入复制发行版归档复制发行版镜像包,或自行制作按 CNI 选择性导入归档
私有仓库配置registries.yaml (支持 rewrite)直接配置 containerdsystem-default-registry 配置
官方多节点自动化工具无 (需用外部工具)k0sctl无 (需用外部工具)
合规支持需要单独加固需要单独加固profile cis、FIPS 构建
小型节点适配性
社区资料量一般一般

这张表里标为"未能确认"的格子,没有用猜测去填。在离线环境的引入决策中,把未经确认的项目当成已确认的来处理,是代价最高的错误。如果某个格子会影响你的决策,请在引入之前先在预发布环境里直接确认。

三个场景与推荐

场景 1:工厂现场的边缘节点

每条产线一台工控机,4 GB 内存,远程访问只在检修时开放,节点数量从几十到几百台不等。一台出问题,只影响那一条产线,其他产线互不相干。

推荐:k3s。如果节点数量多、需要反复搭建同样的配置,选 k0s 加 k0sctl。

理由有三个。第一,因为这种结构不需要高可用,SQLite 单节点反而是恰当的选择,管理 etcd 法定人数在这个场景里纯粹是成本。第二,4 GB 内存下静态 Pod 部署方式没有余量。第三,用 k3s 的内置仓库镜像功能,够不到内部仓库的节点之间可以互相分享镜像。

# 边缘节点最小配置 —— /etc/rancher/k3s/config.yaml
disable:
  - traefik
  - servicelb
  - metrics-server
write-kubeconfig-mode: '0600'
kubelet-arg:
  - 'image-gc-high-threshold=70'
  - 'image-gc-low-threshold=50'

调低镜像 GC 阈值的原因是边缘节点的磁盘小。在离线的边缘环境里,一旦磁盘占满,就没有办法重新获取镜像,整个节点就会变得没法用。

如果节点有几百台、需要反复搭建同样的配置,就应该倾向于 k0sctl。用一份 YAML 管理节点列表、用同一条命令一路走到升级的这种结构,在需要重复几百次的场景里,最能减少人为失误。

场景 2:金融或政务离线网络中的内部服务集群

承载内部业务系统的集群。节点 10 到 30 台,属于审计对象,存在安全检查清单,出故障时业务会中断。

推荐:RKE2 —— 但仅限于需求文档里确实包含 CIS 系列条款的情况。

理由有两个。第一,一行 profile: 'cis',就能一并调整 Pod 安全准入、网络策略、文件权限、etcd 运行用户。如果手动去做,每一项都需要单独验证,每次审计都得解释一遍"为什么这么配置"。让发行版通过官方文档来提供依据,明显更有优势。第二,因为是静态 Pod 结构,上游 Kubernetes 的知识和工具能直接套用,在没有外部支持、需要靠内部人员长期维护的情况下更有优势。

# /etc/rancher/rke2/config.yaml —— 离线合规集群的基本形式
profile: 'cis'
system-default-registry: 'registry.internal.example:5000'
tls-san:
  - k8s-api.internal.example
  - 10.10.20.10
kube-apiserver-arg:
  - 'service-account-extend-token-expiration=false'

system-default-registry 在离线环境里特别有用。官方文档明确说明,这个值只接受 RFC 3986 URI authority,也就是说只能用主机名加可选端口,不能带路径。想在这里再拼上一段项目路径而导致失败的案例并不少见。

反过来,如果需求文档里既没有 CIS 也没有 FIPS,只写了"加强安全性"这种笼统的说法,选 RKE2 的理由就站不住脚。这种情况下,直接在 k3s 上应用 Pod 安全标准和网络策略,运维负担会更小。

场景 3:开发者笔记本电脑与 CI

用于功能开发和集成测试。一天要建了又扔好几次,生命周期从几分钟到几小时不等。

推荐:k3s 或 k0s 单节点。只看启动速度和是否方便丢弃。

在这个场景里,数据存储的讨论没有意义。SQLite 是最好的选择,组件也应该尽量都关掉,以缩短启动时间。

# 在 CI runner 上跑 k3s 单节点 —— 把不需要的都关掉
sudo INSTALL_K3S_SKIP_DOWNLOAD=true \
  INSTALL_K3S_EXEC="server --disable traefik --disable servicelb --disable metrics-server --disable local-storage --write-kubeconfig-mode 0644" \
  ./install.sh
# k0s 单节点 —— 不用安装脚本,只靠子命令
sudo k0s install controller --single
sudo k0s start
sudo k0s kubectl get nodes
# 销毁
sudo k0s stop && sudo k0s reset
# 或者用 k3s
sudo /usr/local/bin/k3s-uninstall.sh

离线 CI 有一点需要注意。如果 CI runner 每次都重新建一个全新的集群,镜像导入也会每次都发生一遍。反复解压几百 MB 镜像包的成本会主导整个构建时间,所以更好的做法是把设计改成用一个预先填充好 containerd 存储快照的 runner 镜像,或者干脆复用集群。

结语 —— 从最难反悔的那条轴线开始选

三个发行版之间的功能差异,会随时间推移而缩小。不会缩小的,是初始决策所造成的约束。给一个用 SQLite 起步的集群加服务器节点、在一个后来发现需要 FIPS 的环境里已经用 Cilium 搭好了、在 4 GB 内存的节点上部署了静态 Pod 类型的发行版 —— 这三种情况,事后想修正都得重建集群,而在离线网络里重建集群,就意味着要从导入审核重新走一遍。

所以顺序应该是这样的:先定数据存储,再读合规需求文档,然后确认节点的实际内存容量,最后从同时满足这三条的发行版里选一个。剩下的差异,可以在运维过程中慢慢消化。

参考资料

현재 단락 (1/156)

新搭建本地集群时,最常被问到的问题是"k3s 和 RKE2 到底哪个更好"。但如果用一张功能对比表来回答这个问题,通常会答错。三个发行版都是经过认证的 Kubernetes,都接近以单一二进制的形式分...

작성 글자: 0원문 글자: 10,324작성 단락: 0/156