TT Lab
ブログ

한국어 English 日本語 中文

はじめる
ブログ

ブログ

k3s·RKE2·k0s 構造比較: コントロールプレーンはどのように起動し、何がデフォルトで含まれているのか

ステータス: ドラフト (2026-10-13)、公式ドキュメント基準 + 一部実測。 構造とデフォルト値は、公式ドキュメントとGitHubリポジトリを2026-10-13に開いて確認しました(k3s v1.37.1+k3s1、RKE2 v1.37.1+rke2r1、k0s v1.36.4+k0s.1がその日の最新安定版)。「実測」と付いた値は、TT Labコースの実習VMで直接構築してみた結果です(2026-08〜09、バージョンを併記)。 作成規則: 実測データが基本であり、測定できなかったものは「未測定」、ドキュメントから見つからなかったものは「未確認」と表示します。

目次

1. なぜ3つを一緒に見るのか

Kubernetesを自分で構築しようとするチームが最初に目にする名前が、k3s、RKE2、k0sです。3つとも「バイナリを1つダウンロードしてサービスとして登録すればクラスターが起動する」という同じ約束をします。そのため、見た目は似ています。

しかし、運用を始めると違いが表面化します。障害が発生したときにログをどこで見ればよいのか、 etcdctl を使用できるのか、最初からイングレスがデプロイされているのか、ノード一覧にコントロールプレーンが表示されるのかがすべて異なります。この違いは機能リストではなく、 設計とデフォルト値から生じます。この記事では、その設計を図で比較します。セキュリティと運用は 第2部で、選び方は 第3部で扱います。

2. 出身と目標

k3s RKE2 k0s
最初に作成した場所 Rancher (現在はSUSE) Rancher (SUSE) Mirantis
別名 — RKE Government —
CNCF Sandbox (2020-08-19採択) CNCFプロジェクトではない(認証済みディストリビューションリストにのみ存在) Sandbox (2025-01-19採択)
ターゲット エッジ・IoT・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つのディストリビューションの性格を1行ずつまとめるとこうなります。

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 는 기본 꺼짐, 스토리지 클래스는 기본으로 없다.
図: 3つのディストリビューションのコンポーネント構造比較

k3s: 1つのプロセスにまとめる

k3s server 1つが、kube-apiserver、スケジューラー、コントローラーマネージャー、kubelet、kube-proxy、flannel、ネットワークポリシーコントローラー、kine、helm-controllerを 同じプロセス内で 動かします。READMEがメモリ削減の主な理由として挙げる設計です。コンポーネントごとに個別に保持するべきランタイムとキャッシュを一度だけ使用するためです。

containerdとruncはバイナリに同梱されてきますが、実行は個別に行われます。k3sのソース(pkg/agent/containerd)を見ると、k3sがcontainerdを別プロセスとして起動していることがわかります。

運用においてこの構造が意味することは以下の通りです。

RKE2: kubeletが静的ポッドとして起動する

rke2 server プロセスは直接コントロールプレーンを動かしません。行うことは監督です。containerdを起動し、それが終了すれば自らも終了し、kubeletを起動し、停止すれば再起動させます。そして、etcd、kube-apiserver、コントローラーマネージャー、スケジューラーの 静的ポッドのマニフェストを /var/lib/rancher/rke2/agent/pod-manifests/ に書き込みます。kubeletがそのマニフェストを読み込んでコンテナとして起動します。kubeadmと同じ形です。

kubelet・containerd・kubectlなどの実行ファイルは rke2-runtime イメージの中に含まれており、初回起動時にそのイメージから取り出して展開します。CNI・CoreDNS・イングレス・metrics-serverなどのアドオンは、内蔵のhelm-controllerがHelmチャートとしてインストールします。

この構造には1つ罠があります。 systemctl stop rke2-server は静的ポッドを停止しません。 TT LabのRKE2実習(v1.36.4+rke2r1)でサービスを停止した後も、rootとして動作するetcdコンテナがそのまま残っていました(実測)。ノードを完全に停止させるには、インストール物に含まれる rke2-killall.sh を使用します。この違いが実際にどのようなインシデントを引き起こすのかについては、第2部で見ていきます。

k0s: 個別に起動し、コントローラーはノードではない

k0sは、コントロールプレーンのコンポーネントをコンテナとしてではなく、 それぞれ独立したプロセス(ドキュメントの表現では「naked」プロセス)として起動し、k0sバイナリがそれらのプロセスを監督します。etcd、kube-apiserver、スケジューラー、コントローラーマネージャー、konnectivity-serverが個別に起動します。これらの実行ファイルはk3sバイナリの中に含まれており、初回の実行時に /var/lib/k0s/bin に展開されます。

最も目立つ違いは、 コントローラーノードにはkubeletもコンテナランタイムもデフォルトで存在しない点です。そのため、コントローラーはワークロードを受け取らず、 kubectl get nodes にも表示されません。APIサーバーがワーカーのkubeletやポッドに通信する必要があるときは、Konnectivityトンネルを介します(エージェントの8132ポート)。

この分離を解除したいときに使用するフラグが2つあります。

また、k0sはコントロールプレーンのコンポーネントをrootではなく専用のシステムユーザーとして動作させます。ドキュメントには k0s install がこのシステムユーザーを作成するという点までしか記載されておらず、ユーザー名はソース(pkg/constant/constant.go、v1.36.4+k0s.1タグ)から確認しました。etcdは etcd、APIサーバーは kube-apiserver、スケジューラーは kube-scheduler、Konnectivityは konnectivity-server のユーザーです。コントローラーマネージャーのユーザーは確認できませんでした(未確認)。

3つの構造を一言で

k3s RKE2 k0s
コントロールプレーンの形態 1つのプロセス kubeletが起動する静的ポッド コンポーネントごとに独立したプロセス
コンテナランタイム containerd・runcバンドル containerdバンドル(ランタイムイメージから取り出し) containerd・runcバンドル
サーバー(コントローラー)がワークロードを受け取るか 受け取る 受け取る デフォルトでは受け取らない
コントロールプレーンのログ k3sサービスログ1つ ポッドログ(/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)도 고를 수 있다.
図: 3つのディストリビューションのデータストアとHAトポロジ

k3s: SQLiteで始めてetcdに移行できる

k3sサーバー1台のデフォルトストレージは SQLite です。APIサーバーはetcdとしか通信できないため、中間層に kine が介在し、etcd APIを模倣しながら背後ではSQLiteに書き込みます。軽量ですがサーバーを増やすことができず、etcdのツールも使用できません。TT Labの実習(v1.35.8+k3s1)でSQLiteの状態で k3s etcd-snapshot save を実行すると、 etcd datastore disabled により拒否されました(実測)。

HAへの移行方法は2つあります。

いずれの場合も、サーバー群の前に 固定登録アドレス(L4ロードバランサー、ラウンドロビンDNS、仮想IPのいずれか)を配置します。

RKE2: 最初からetcd

RKE2は、特に設定を行わない場合、 内蔵etcd です。HA構成ではサーバーを奇数の3台にすることを推奨しており、サーバーでもデフォルトでワークロードを受け付けるため、 サーバー3台、エージェント0台が最小限のHA構成となります。ノードは固定登録アドレスの 9345ポートで参加し、APIには6443ポートを使用します。

SQLiteも使用可能ですが、ドキュメントには「実験的」と記載されており、1台のサーバーでのみ利用可能です。外部SQL DBはkineを経由して使用できます(ドキュメントで検証済みのバージョンは etcd 3.6.7、MySQL 8.4.8、MariaDB 11.4.10、PostgreSQL 18.3)。ただし、そのバックアップ手順は「実験的」な手順として案内されています。

k0s: 複数台ならetcd、1台ならSQLite

k0sのストレージ設定(spec.storage.type)は etcd と kine のいずれかで、デフォルトの生成設定はetcdです。ドキュメントとREADMEの機能一覧には、デフォルト値が「複数ノードはetcd、1ノードはSQLite」と記載されており、kineの後ろにMySQLやPostgreSQLを配置することも可能とされています。

--single これがSQLiteになることはハンズオンで確認済みです。 --single で構築したk0sで k0s etcd member-list を実行すると、 wrong storage type: kine として拒否されます(実測値)。etcdを扱うには --enable-worker として構築する必要があります。

HA構成は コントローラー3台または5台が推奨されています。2台でもk0sの観点ではHAですが、etcdのクォーラムの観点ではHAではないとドキュメントで指摘されています。コントローラーの前段には、6443(API)・8132(Konnectivity)・9443(k0s参加API)をすべてのコントローラーに転送するTCPロードバランサーが必要です。外部ロードバランサーがない場合は、次の2つのいずれかを選択できます。

5. デフォルトで含まれるもの

インストール直後に何がすでに稼働しているかが、3者の間で最も大きく異なる点です。

構成要素 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
イングレス Traefik v3 v1.36以降の新規クラスターはTraefik、それ以前はingress-nginx なし
サービス LoadBalancer ServiceLB(klipper-lb) ServiceLBはあるが デフォルトで無効 バンドルなし(ドキュメントに明示的な記載は未確認)
ストレージクラス local-path なし(実測値) なし(CSIで直接導入)
DNS CoreDNS CoreDNS(+オートスケーラー) CoreDNS
metrics-server あり あり あり
デフォルトCIDR(ポッド・サービス) 10.42/16 · 10.43/16 10.42/16 · 10.43/16(実測値) 10.244/16 · 10.96/12

RKE2のイングレスはバージョンによって仕様が異なるため注意が必要です。ingress-nginxのサポート終了が2026年3月に控えているため、RKE2ではv1.36以降の新規クラスターにおけるデフォルトがTraefikに変更されました。サービスのドキュメントではv1.36でingress-nginxが非推奨(deprecated)として残り、v1.37で削除されると記載されていますが、v1.37のリリースノートにはTraefikと併用するマイグレーション用の組み合わせのみが残ると記載されています(2026-10-13確認)。 すでに稼働しているクラスターは、アップグレードしてもそれまで使用していたイングレスが維持されます。 そのため、「RKE2のイングレスは何なのか」という問いに対する答えは、クラスターを最初に作成したバージョンを知る必要があります。TT Labのハンズオン用VM(v1.36.4+rke2r1)でも、デフォルトのイングレスクラスはtraefik、CNIはcanal、ストレージクラスはなしでした(実測値)。

これに対してk3sは、「すべて詰め込んでおいて、不要なら無効化してもらう」という方針です。 --disable に traefik, servicelb, local-storage, metrics-server, coredns を指定できます。よくある間違いは、 kubectl delete でTraefikを削除することです。k3sは起動するたびにデフォルト構成要素のマニフェストを再適用するため、再起動するとTraefikが復活します。ハンズオンでは、 systemctl restart の実行後、わずか20秒でTraefikのDeploymentが復活しました(実測値、v1.35.8+k3s1)。無効化するには、すべてのサーバーに --disable を同時に指定する必要があります。

k0sは「何も含めず、ユーザーに選択させる」という方針です。READMEのスコープセクションには、イングレス、サービスメッシュ、ストレージはバンドルされていないと記載されており、MetalLBやTraefil、OpenEBSなどは例としてのみ紹介されています。実際にサービスをデプロイするクラスターにおいては、このアプローチの方がメリットがあります。デフォルトで含まれている機能は、何らかの理由でそれに依存している場合に初めて存在に気づくものであり、その時点から不要なものを排除する方が手間がかかるためです。

6. CIDRは似て非なるもの

最後の行が、思いがけないトラブルを引き起こします。k0sのデフォルトCIDR(ポッド 10.244/16、サービス 10.96/12)は、標準的なKubernetesでよく使用される値と同じです。サービスCIDRはkubeadmのデフォルト値であり、ポッドCIDRはflannelのサンプルで広く普及した値です。そのため、k0sを別のKubernetes上のVM内にデフォルト設定で構築すると、外側のクラスターから提供されたDNSサーバーのアドレス(外側のサービスCIDRである 10.96/12 内のアドレス)を、内側のk0sが自分のサービスIPとして誤認してしまいます。TT Labのハンズオン教材を作成する際にも実際にこの現象が発生しました(実測値)。DNSが機能せずCNIイメージの取得に失敗し、CNIがないためCoreDNSが起動しないというデッドロックに陥りましたが、画面に表示されるエラーはイメージ取得のタイムアウトのみでした。

k3sやRKE2の 10.42 / 10.43 は非標準であるため、偶然にもこの問題が回避されます。「k3sではうまくいった」という経験は設計によるものではなく偶然にすぎないという点を覚えておけば、ディストリビューションを変更する際に同じ罠を避けることができます。CIDRは初期作成時に決定されるものであり、3つのディストリビューションのいずれにおいても、作成後の変更は困難です。

TTの一言。 3つとも「単一のバイナリ」であるため双子のようによく似ていますが、中身を開けてみると、1つは一体型、1つは静的ポッド型、もう1つは完全に分離型です。障害発生時にログをどこで探すべきかも異なるため、最初に構築する際は、全体像のアーキテクチャ図を必ず頭に入れておきましょう。

参考

すべてのドキュメントは2026年10月13日に閲覧しました。docs.k3s.io および docs.rke2.io のページは2026年10月7日更新と表示されており、docs.k0sproject.io の stable は v1.36.4+k0s.1 バージョンです。

ログインするといいねできます

コメント

まだコメントはありません。

ログインするとコメントできます