- Published on
オンプレミス軽量Kubernetes選定基準 — k3s、k0s、RKE2をデータストアと規制で分ける
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに — 「軽い」は選定基準ではありません
- 軸1: データストア — ここで半分が決まります
- 軸2: 何をバンドルするか — 取り除くときのコスト
- 軸3: プロセス配置 — 単一バイナリとスタティックポッド
- 軸4: 規制対応 — RKE2のCISとFIPSは誰のためのものか
- 軸5: アップグレード、サポート寿命、小型ノードのフットプリント
- シナリオ三つと勧告
- おわりに — 元に戻すのがもっとも難しい軸から選んでください
- 参考資料
はじめに — 「軽い」は選定基準ではありません
オンプレミスクラスターを新しく立てるとき、もっともよく出る質問が「k3sとRKE2、どちらがいいですか」です。ところがこの質問に機能比較表で答えると、たいてい間違えます。三つの配布版はすべて認証されたKubernetesであり、三つとも単一バイナリに近い形で配布され、三つとも閉域網インストール経路を公式にサポートしています。機能一覧だけでは区別が付きません。
実際に選択を決めるのは五つほどの軸です。そしてそのうち第一の軸であるデータストアは後から変えるのがもっとも難しいです。インストール後6ヶ月経ってから「サーバーノードをもう一台入れなければならない」という要求が来て、そのときになってSQLiteで始めていたという事実に気づく、という具合です。
この記事はその軸を一つずつ置き、最後に三つの具体的なシナリオに答えを出します。検証基準は以下のとおりです。
| 配布版 | 確認したバージョン系列 | 確認時点 | 主な出典 |
|---|---|---|---|
| k3s | v1.36.2+k3s1 | 2026-07-31 | docs.k3s.io |
| k0s | v1.36.3+k0s.0 | 2026-07-31 | docs.k0sproject.io |
| RKE2 | v1.33.1+rke2r1 (文書の例) | 2026-07-31 | docs.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で指定し、有効な値はetcdとkineの二つです。公式設定文書の例は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はコントロールプレーンをスタティックポッドとして立てる構造で、文書が自ら掲げる目標が規制対応です。
閉域網の観点でこの軸の結論はこうです。最初からサーバーノードを3台に決められるなら、内蔵etcdで始めてください。 閉域網では後でノードを追加しようとすると搬入審議から最初にやり直さなければならないので、移行コストが一般環境よりはるかに大きいです。そして内蔵etcdは奇数ノードを要求します。2台構成は1台と障害許容能力が同じなのに運用対象だけ増えます。
軸2: 何をバンドルするか — 取り除くときのコスト
軽量配布版は「すぐ使えるように」するためにコンポーネントを事前に入れておきます。これは初日には長所ですが、6ヶ月後にIngressコントローラーを変えようとする日には短所になります。
k3sはこの点がもっとも明示的です。公式CLI文書によると--disableフラグで切れるバンドルコンポーネントはcoredns、servicelb、traefik、local-storage、metrics-server、runtimesです。一覧が文書にそのまま書かれていること自体が実務で大きな意味を持ちます。
# /etc/rancher/k3s/config.yaml — Traefikの代わりに別のingressを使うとき
disable:
- traefik
- servicelb
# すでにインストールされたクラスターで切ると、マニフェストが残って復活することがあります。
# 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.zst | Cilium用イメージ | Ciliumを使うときコアと一緒に搬入 |
| rke2-images-vsphere.linux-amd64.tar.zst | vSphere CPI/CSIイメージ | vSphereオンプレミス時に追加 |
この分離が閉域網で実際に役立ちます。使わないCNIイメージを媒体に入れて審議に上げる理由がないからです。逆に搬入リストを間違えると、コアだけ持ち込みCNIを漏らしてノードがNotReadyで止まります。
軸3: プロセス配置 — 単一バイナリとスタティックポッド
k3sとk0sはコントロールプレーンコンポーネントを自分のプロセスのなかで動かします。ノードでpsを打っても、kube-apiserverという別プロセスは見えません。RKE2は違います。公式概要文書が「RKE2はコントロールプレーンコンポーネントをkubeletが管理するスタティックポッドとして実行する」と明示しています。
この違いが生む実務的な結果は三つです。
- デバッグ経路が違います。 RKE2ではAPIサーバーのログをポッドログとして読め、マニフェストを直接直せます。k3sとk0sではサービスログ(journalctl)一つを探らねばなりません。閉域網で外部サポートを受けられない状況なら、この差は体感が大きいです。
- アップストリーム文書がそのまま通用する度合いが違います。 RKE2は文書自ら「RKE1からアップストリームKubernetesとの緊密な整合を引き継いだ」と述べています。インターネット検索が遮断された環境で手元のKubernetes教材がそのまま通用するかは、思ったより重要な条件です。
- リソースフットプリントが違います。 プロセスが分かれればメモリも分かれます。2GBメモリの産業用PCでは、この差が決定的です。
軸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プロファイルをオンにすると何が変わるかも文書に整理されています。ポッドセキュリティ承認がクラスター全体でrestrictedに強制され(kube-system、compliance-operator-system、tigera-operatorを除く)、同じネームスペース内へのトラフィックを制限するネットワークポリシーが配布され、エージェントマニフェストと設定ファイルの権限が644から600に締められ、etcdスタティックポッドが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チャート | 対象に含まれる |
| NGINX Ingress | Goコントローラーは BoringCrypto、Cサーバーは FIPS検証済みOpenSSL |
| Canal CNI | 再ビルドされる(既定値) |
| Cilium、Calico、Multus CNI | 再ビルドされない |
だから「FIPSが必要だ」と「eBPFベースのCNIを使いたい」が同時に要求されると、どちらか一つを諦めなければなりません。この決定を設計段階でできないと、監査直前になってCNIを入れ替えることになります。
そして正直に言っておくべき部分があります。FIPSとCISが契約書や監査項目として要求されていないなら、その理由でRKE2を選ぶ必要はありません。 国内の金融・公共閉域網で実際に要求されるのは、たいていCIS系列のハードニングと監査ログであり、FIPS 140検証済みモジュール自体ではないことが多いです。要求事項文書に明示された項目が何かをまず確認し、その項目がRKE2が自動でやってくれるものなのか、それともどの配布版でも直接やらなければならないものなのかを区別してください。
軸5: アップグレード、サポート寿命、小型ノードのフットプリント
閉域網でのアップグレードは「新しいバイナリと新しいイメージバンドルを搬入して差し替える」ことです。三つの配布版すべてこの骨格は同じですが、自動化ツールの性格が違います。
| 配布版 | 閉域網アップグレード経路 | 複数ノード自動化 |
|---|---|---|
| k3s | 新しいアーカイブをイメージフォルダに入れ旧いものを削除、バイナリを差し替え、install.shを再実行 | system-upgrade-controller (関連イメージの搬入が必要) |
| k0s | 新しいバンドルとバイナリを配置後サービス再起動 | k0sctl apply でインストールと同じコマンド |
| RKE2 | 新しいアーティファクトディレクトリを置きinstall.shを再実行 | system-upgrade-controller系列 |
k3sの自動アップグレードは閉域網で追加作業があります。公式文書は自動アップグレードを使うにはrancher/k3s-upgrade、rancher/system-upgrade-controller、rancher/kubectlイメージがプライベートレジストリになければならないと明示しています。この三つのイメージを搬入リストに入れないと、自動アップグレード自体が最初の試みで止まります。
サポート寿命は三つの配布版すべてアップストリームKubernetesのマイナーバージョン周期に従います。閉域網で重要なのは寿命自体より搬入周期とサポート周期の整合性です。搬入審議が四半期に一回なのにパッチが月単位で出ると、実質的には四半期ごとに累積パッチを一度に上げる運用になります。この場合、マイナーバージョンを一つ低く取って安定化したパッチ系列を使うほうが事故が少ないです。
リソースフットプリントは軸3のプロセス配置ですでに分かれています。正確な数値はCNI選択、ノード数、ワークロードによって大きく変わるので、ここでは数字を引用しません。代わりに判断基準だけ記します。メモリが4GB以下の産業用ノードなら、スタティックポッド方式は候補から外してください。 コントロールプレーンコンポーネントがそれぞれ別のコンテナとして立つ構造は、そのハードウェアでは余裕がありません。
軸整理表
| 軸 | k3s | k0s | RKE2 |
|---|---|---|---|
| 既定データストア | SQLite (文書に明示) | etcd (設定文書の例基準) | 概要文書に未明示 — 要確認 |
| HA拡張 | 内蔵etcdまたは外部DBへの移行が必要 | 内蔵etcdまたは外部etcd | スタティックポッドベースの複数サーバー |
| 外部DBサポート | etcd、NATS、MySQL、Postgres | kineデータソース | 確認できず |
| 既定Ingress | Traefik (disable可能) | 別途デプロイ | ingress-nginx系列 (概要文書に未明示) |
| CNI選択 | 既定Flannel、差し替え可能 | kuberouter既定、calico、custom | Canal既定、Cilium/Calico/Multusアーカイブ分離 |
| コントロールプレーン配置 | 単一プロセス | 単一プロセス | kubeletが管理するスタティックポッド |
| 閉域網イメージ搬入 | リリースアーカイブのコピー | リリースバンドルまたは直接製作 | CNI別アーカイブ選択搬入 |
| プライベートレジストリ設定 | registries.yaml (rewriteサポート) | containerd設定を直接 | system-default-registry設定 |
| 複数ノード自動化公式ツール | なし (外部ツール使用) | k0sctl | なし (外部ツール使用) |
| 規制対応 | 別途ハードニングが必要 | 別途ハードニングが必要 | profile cis、FIPSビルド |
| 小型ノード適合性 | 高い | 高い | 低い |
| コミュニティ資料量 | 多い | 普通 | 普通 |
この表で「確認できず」と残した欄は推測で埋めていません。閉域網導入決定では、確認できていない項目を確認済みであるかのように扱うことがもっとも高くつく間違いです。該当欄が決定に影響するなら、導入前にステージングで直接確認してください。
シナリオ三つと勧告
シナリオ1: 工場現場のエッジノード
ラインごとに産業用PC一台、メモリ4GB、リモートアクセスは点検時のみ開放、ノード数は数十台から数百台。一台が死んでもラインが一つ止まるだけで他のラインは無関係。
勧告: k3s。ノード数が多く構築を繰り返さねばならないならk0sプラスk0sctl。
根拠は三つです。第一に、高可用性が不要な構造なのでSQLite単一ノードがむしろ適切です。etcd定足数の管理はこのシナリオで純粋なコストです。第二に、メモリ4GBでスタティックポッド配置は余裕がありません。第三に、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'一行でポッドセキュリティ承認、ネットワークポリシー、ファイル権限、etcd実行ユーザーが一緒に調整されます。これを手でやると項目ごとに検証が必要で、監査のたびに「なぜこう設定したか」を毎回説明しなければなりません。配布版が公式文書で根拠を提供してくれるほうがはるかに有利です。第二に、スタティックポッド構造なのでアップストリーム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にポッドセキュリティスタンダードとネットワークポリシーを直接適用するほうが運用負担が少ないです。
シナリオ3: 開発者ノートPCとCI
機能開発と統合テスト用。一日に何度も作って捨て、寿命が数分から数時間。
勧告: k3sまたはk0s単一ノード。起動速度と廃棄のしやすさだけを見ます。
このシナリオではデータストアの議論は無意味です。SQLiteが最善で、コンポーネントは極力切って起動時間を短縮します。
# CIランナーで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ランナーが毎回クラスターを新しく作るなら、イメージインポートも毎回発生します。数百MBのバンドルを繰り返し展開するコストがビルド時間を支配するようになるので、ランナーイメージにcontainerdストレージを事前に満たしたスナップショットを使うか、クラスターを再利用する方向へ設計を変えるほうがよいです。
おわりに — 元に戻すのがもっとも難しい軸から選んでください
三つの配布版の機能差は時間が経つほど縮まります。縮まらないのは初期決定が作った制約です。SQLiteで始めたクラスターにサーバーノードを追加すること、FIPSが要求される環境ですでにCiliumで構築してしまったこと、メモリ4GBのノードにスタティックポッド配布版を載せたこと。三つとも後で直そうとするとクラスターを再構築しなければならず、閉域網でクラスターを再構築するということは搬入審議から最初にやり直すということです。
だから順序はこうです。データストアを先に決め、規制要求事項文書を読み、ノードの実際のメモリ容量を確認したうえで、その三つすべてを満たす配布版を選んでください。残りの差は運用しながら吸収できます。