k0sctlは、k0sで構成するKubernetesクラスターを、手元のPCからSSH経由で構築・更新するCLIです。ノードに何かをインストールして回るのではなく、YAMLに「あるべきクラスターの姿」を書いて k0sctl apply を実行すると、k0sctlが各ホストへ接続し、現状との差分だけを埋めます。初回構築とバージョンアップで手順が変わらないことが最大の特徴です。以下は v0.32.2(2026年7月29日リリース、JST)のソースと公式ドキュメントに基づいて整理しています。
まとめ
v0.32.2時点の結論を先に示します。
- 役割:k0s本体のインストーラではなく、複数ホストへの配布・接続・差分適用を担うオーケストレータ
- 構築の流れ:
k0sctl initで雛形生成 → 編集 →k0sctl apply→k0sctl kubeconfig - アップグレード:専用サブコマンドは存在せず、
spec.k0s.versionを上げて再度 apply する - バックアップ:
k0sctl backupで取得し、復旧はk0sctl apply --restore-from - 最大の制約:ノードの追加はできても削除はできない(公式のKnown limitations)
- 向く場面:オンプレやVPS上の複数ノードを、SSHだけで恒常運用したいとき
- 向かない場面:単一ノードの学習環境、SSH到達性の無い環境、マネージドKubernetesが使える環境
ネット上には k0sctl status や k0sctl upgrade といった記述が流通していますが、いずれもv0.32.2のコマンド定義には存在しません。根拠は本文で示します。
k0sctlとk0s本体の役割分担
混同しやすいので、最初に切り分けます。k0sはKubernetesディストリビューション本体で、コントロールプレーンからkubeletまでを単一バイナリに同梱したものです。対してk0sctlは、そのバイナリを複数のホストへ届け、ロールに応じて初期化し、join用トークンをやり取りする外側の道具です。
ノードに直接ログインして k0s install を叩けば、k0sctl無しでもクラスターは組めます。ではなぜ別ツールがあるのか。理由は台数が増えた瞬間に手作業が破綻するからです。コントローラー3台・ワーカー10台の構成では、バイナリの配布、バージョンの一致確認、トークンの受け渡し、アップグレード時のdrain順序まで、すべて人が管理することになります。k0sctlはこれを1つのYAMLへ集約し、実行のたびに現状を検出して差分だけを適用します。設定ファイルにホストを1台追記して apply すれば、既存ノードには触れずに新ノードだけが参加する。何度実行しても結果が変わらない点で、AnsibleでKubernetesを組むKubesprayと発想が近いと言えます。
ただし宣言型が働くのは追加方向だけです。理由と回避手順は制約の章で扱います。
k0sctlのインストール方法と対象ノード側の要件
導入で最初につまずくのは、「どこに何を入れるのか」の理解です。k0sctlを入れるのは操作する手元の端末であり、クラスターを構成するノードではありません。ノード側にk0sctlを配る必要はなく、必要なものはSSHで到達できることだけです。
操作端末へのk0sctl導入(バイナリ・パッケージマネージャ・コンテナ)
公式が案内する導入経路は4系統あります。もっとも確実なのはGitHub Releasesからのバイナリ取得で、v0.32.2では k0sctl-linux-amd64 k0sctl-linux-arm64 k0sctl-darwin-arm64 k0sctl-win-amd64.exe k0sctl-linux-riscv64 などが配布されています。ダウンロード後に実行権限を付け、PATHの通ったディレクトリへ置きます。
公式READMEには、リリースバイナリがまだ署名されていないという注意書きがあります。macOSとWindowsでは、初回起動時にコンテキストメニューの「開く」から明示的に許可してください。この一手間を知らないと、macOSのGatekeeperやWindowsのSmartScreenに弾かれて詰まります。
パッケージマネージャを使う場合は次のとおりです。HomebrewとWinGet以外はコミュニティ管理である点を公式が明記しているため、バージョン追随の速さは経路によって差が出ます。
brew install k0sproject/tap/k0sctl # macOS, Linux
winget install k0sproject.k0sctl # Windows
choco install k0sctl # Windows
apk add k0sctl # Alpine
zypper install k0sctl # openSUSE Tumbleweed
nix profile install nixpkgs#k0sctl # Nixpkgs
yay -S k0sctl-bin # Arch Linux (AUR)
go install github.com/k0sproject/k0sctl@latest # Goツールチェーンがある場合
CI上で使うならコンテナ実行が扱いやすく、ghcr.io/k0sproject/k0sctl:latest が公開されています。なお curl でインストールスクリプトを取得する方式は公式に存在しません。取得元URLを案内する記事を見かけたら、Releasesページかパッケージマネージャに読み替えてください。
対象ノードが満たすべきSSH・OS・スペックの条件
ホスト側の前提は公式READMEが明確に定めています。全ロールをサポートするのはLinuxノードです。WindowsノードはSSHまたはWinRM経由でworkerとしてのみ参加でき、この対応は実験的、かつk0s 1.34以上が必要と記載されています。
権限条件は見落としやすいところです。Linuxでは、SSHユーザーがrootであるか、パスワード無しの sudo(または doas)が使えることが求められます。sudoでパスワードを求められる構成のままだと、接続はできても構築フェーズで止まります。
スペックの下限は、k0s公式のシステム要件が定義しています。
| ロール | 最小RAM | 最小vCPU | 最小ディスク |
|---|---|---|---|
| コントローラー | 1GB | 1 | 約0.5GB |
| ワーカー | 0.5GB | 1 | 約1.6GB |
| コントローラー+ワーカー | 1GB | 1 | 約2.0GB |
これはあくまで起動可能な下限です。公式の推奨値では、ワーカー100台・Pod1万規模のコントローラーでRAM 4〜8GB/vCPU 2〜4、ワーカー1,000台・Pod10万規模ではRAM 16〜32GB/vCPU 8〜16が目安として示されています。ワーカーには「ディスク空き容量15%以上」という条件も付くため、小容量VPSで長期運用するとイメージ蓄積で先に空き容量が枯渇します。
k0s本体が対応するアーキテクチャはx86_64・aarch64・armv7l・riscv64です。このうちriscv64はビルド済みバイナリもCI検証も提供されていません(操作端末側のk0sctlには k0sctl-linux-riscv64 が配布されているため、混同しないでください)。
k0sctl.yamlの構成要素とroleの選び分け
最小構成のk0sctl.yamlと必須フィールド
k0sctlの挙動は、ほぼすべてが設定ファイルで決まります。既定の読み込み先はカレントディレクトリの k0sctl.yaml です。最小構成は次のようになります。
apiVersion: k0sctl.k0sproject.io/v1beta1
kind: Cluster
metadata:
name: my-k0s-cluster
spec:
hosts:
- role: controller
ssh:
address: 10.0.0.1
user: root
port: 22
keyPath: ~/.ssh/id_rsa
- role: worker
ssh:
address: 10.0.0.2
k0s:
version: v1.36.3+k0s.0
apiVersion は現在 k0sctl.k0sproject.io/v1beta1 のみ、kind は Cluster のみが有効です。
role4値の使い分けとcontroller+workerのtaint挙動
設計上の判断が要るのは role です。指定できる値は4つで、用途が明確に分かれます。
controller:コントロールプレーン専用。本番はこれを3台にしてetcdの多数決を成立させますcontroller+worker:同一ノードでワークロードも動かす。台数を抑えたい検証環境向けsingle:単一ノードクラスター。この指定を使う場合、設定ファイルにホストを1つしか書けませんworker:ワークロード専用
controller+worker を選んだときは noTaints の挙動を押さえてください。k0sは既定でコントローラー兼ワーカーのノードに node-role.kubernetes.io/master:NoSchedule のtaintを付けるため、tolerationを持たない通常のPodはスケジュールされません。1台構成のつもりでPodが起動しない場合、原因はほぼここです。noTaints: true を指定するとこの既定taintが外れます。
バージョン固定・閉域配布・踏み台経由の指定方法
spec.k0s.version を書かなければ、k0sctlは最新の安定版、または既にクラスターで動いているバージョンを自動で選びます。プレリリースまで対象に含めたい場合のみ spec.k0s.versionChannel: latest を指定します。本番では自動追随を避けるため、バージョンを明示的に固定する運用を推奨します。
閉域環境では k0sDownloadURL が使えます。%p(アーキテクチャ)、%v(k0sバージョン)、%x(Windowsでの .exe)のトークンが展開されるため、社内ミラーのパスを1行で表現できます。バイナリを手元から配りたい場合は uploadBinary: true、ノード上の既存バイナリをそのまま使う場合は useExistingK0s: true を指定します。
踏み台サーバー越しに接続する構成では、ssh の下に bastion を置きます。踏み台側の項目は通常のSSH接続と同じで、address・user・keyPath を個別に指定できます。WinRM経由の場合は winrm.bastion が同じ役割を担います。
spec:
hosts:
- role: controller
ssh:
address: 10.0.0.2
user: ubuntu
keyPath: ~/.ssh/id_rsa
bastion:
address: 10.0.0.1
user: root
keyPath: ~/.ssh/id_rsa2
クラスター構築の実行手順(init・apply・kubeconfig)
実際の流れは3コマンドで完結します。
# 1. 設定ファイルの雛形を生成(--k0s でk0s側の設定ブロックも出力)
k0sctl init > k0sctl.yaml
# 2. 差分を適用してクラスターを構築
k0sctl apply --config k0sctl.yaml
# 3. 管理用kubeconfigを取得
k0sctl kubeconfig --config k0sctl.yaml > k0s.config
kubectl get node --kubeconfig k0s.config
k0sctl init はホストアドレスを引数に取れます。パイプで繋げば設定ファイルを保存せずに構築まで一気に走らせられます。
k0sctl init 10.0.0.1 10.0.0.2 [email protected]:8022 | k0sctl apply --config -
applyは内部でフェーズに分かれて進みます。公式READMEに掲載された実行例では、ホストへの接続、OS判定、事前準備、ホスト情報の収集、検証、k0s側の状態収集、k0sバイナリのダウンロード、設定投入、クラスター初期化、ワーカーの参加、切断の11フェーズが順に出力されています。失敗したときはどのフェーズで止まったかがそのまま切り分けの起点になります。
並列度は spec.options.concurrency.limit で制御し、既定は30です。ファイルアップロードの同時実行数は uploads で、既定は5です。いずれもコマンドラインの --concurrency・--concurrent-uploads で上書きでき、0を指定すると無制限になります。踏み台越しの細い回線では、この2つを下げると転送失敗が減ります。
ワーカーのReady待ちを省きたいときは --no-wait、applyと同時にkubeconfigを書き出したいときは --kubeconfig-out を付けます。後者を使えばCIでは手順3を省略できます。適用前に影響範囲だけ見たい場合は --dry-run がありますが、v0.32.2のフラグ定義では説明文に「(EXPERIMENTAL)」が付いたままです。出力を最終確認とはせず、検証環境での実行と併用してください。
アップグレードとバックアップ・リストアの実務手順
バージョンを上げて再applyするアップグレード
ここがk0sctlの設計思想がもっとも表れる部分です。アップグレード専用のサブコマンドはありません。設定ファイルの spec.k0s.version を上げて apply し直すだけです。k0sctlは現在のクラスターバージョンを検出し、設定値のほうが新しければアップグレード処理へ入ります。
このとき既定でワーカーのdrainが走ります。spec.options.drain の既定値は有効で、gracePeriodが2分、timeoutが5分です。加えて concurrency.workerDisruptionPercent が既定10に設定されており、同時に停止するワーカーが全体の10%を超えないよう制御されます。ワーカー10台なら1台ずつ更新される計算です。検証環境で待ち時間を削りたい場合のみ --no-drain を使ってください。本番で外すとサービス断に直結します。
停止をワークロード側へ事前通知したい場合は spec.options.evictTaint を使います。既定は無効ですが、有効にするとアップグレードやresetの前にノードへtaintが付き、退避の合図になります。taintの既定値は k0sctl.k0sproject.io/evict=true、effectの既定は NoExecute で、NoSchedule と PreferNoSchedule も選べます。既定ではワーカー専用ノードにしか付かないため、controller+worker のノードにも適用したい場合は controllerWorkers: true を指定してください。
バックアップ取得とリストア時の2つの制約
バックアップはコントロールプレーンの状態を対象にします。
# 取得(既定の出力名は k0s_backup_<unixtime>.tar.gz)
k0sctl backup --config k0sctl.yaml
# 出力先を指定する場合
k0sctl backup -o /var/backups/k0s-20260804.tar.gz
# 復旧は apply のフラグとして実行
k0sctl apply --config k0sctl.yaml --restore-from k0s_backup_1623220591.tar.gz
復元対象はetcdのデータストア内容、証明書、鍵です。公式が明記している制約が2点あります。1つは、バックアップ時と復元時で externalAddress(コントロールプレーンのアドレス)を変えられないこと。全ワーカーがこのアドレスへ接続しており、現状は再設定できないためです。もう1つは、復元がディザスタリカバリ用途を前提としており、対象コントローラーにk0sコンポーネントが存在しない状態を期待している点です。稼働中クラスターへ上書き復元する使い方は想定されていません。
クラスターを撤去するときは k0sctl reset です。設定ファイルに列挙されたホストからk0sの痕跡を削除します。
公式が認める制約と、存在しないサブコマンドの見分け方
ノード削除が非対称という最大の制約
公式ドキュメントのKnown limitationsは2点を挙げています。1つはホストの自動探索を行わないこと。k0sctlは設定ファイルに列挙されたホストにしか作用しません。もう1つが実務で効く制約で、原文は「k0sctl can only add more nodes to the cluster. It cannot remove existing nodes.」です。
つまり、設定ファイルからホストの記述を削除しても、そのノードはクラスターに残り続けます。宣言型と聞いて「YAMLから消せば離脱する」と考えると、確実に事故ります。ノードを外すときは手作業になります。kubectl drain でワークロードを退避し、kubectl delete node でクラスターから登録を消し、当該ノード上で k0s reset を実行してk0s自体を撤去する。この3段階を人が実行したうえで、k0sctl.yamlからも該当ホストを削除して整合を取ります。
実在するサブコマンドと、流通している誤ったコマンド名
k0sctlの解説で誤りが混入しやすいのがコマンド名です。v0.32.2の cmd/root.go が登録するトップレベルコマンドは8つで、うち config が2つのサブコマンドを持つため、実行できる末端は9通りになります。
| コマンド | 公式Usage |
|---|---|
k0sctl apply |
Apply a k0sctl configuration |
k0sctl init |
Create a configuration template |
k0sctl kubeconfig |
Output the admin kubeconfig of the cluster |
k0sctl backup |
Take backup of existing clusters state |
k0sctl reset |
Remove traces of k0s from all of the hosts |
k0sctl config edit |
Edit k0s dynamic config in SHELL’s default editor |
k0sctl config status |
Show k0s dynamic config reconciliation events |
k0sctl version |
Output k0sctl version |
k0sctl completion |
(Usage未定義。Descriptionは Generates a shell auto-completion script.) |
このほか、CLIフレームワークのurfave/cliが help を自動生成するため k0sctl help も動きます。一方で k0sctl status、k0sctl logs、k0sctl upgrade、k0sctl update、k0sctl restore はいずれも定義に存在しません。ノードやPodの状態を見たいなら k0sctl kubeconfig でkubeconfigを取り出し、kubectl get node を使います。ログを追いたい場合はSSHで各ノードへ入り journalctl -u k0scontroller や k0s status を見ます。apply失敗時のログは、エラーメッセージ中に保存先パスが表示されます。
dynamicConfig有効時に反映されなくなる設定範囲
運用で確実に踏むのが動的設定モードの制約です。spec.k0s.dynamicConfig: true(またはコントローラーの installFlags に --enable-dynamic-config がある場合、自動的に有効化されます)を使うと、k0sctlがクラスター全体の設定を反映するのは初回の初期化時だけになります。以降は k0s config edit または k0sctl config edit で編集する必要があり、k0sctl.yaml内の spec.k0s.config をいくら書き換えて apply しても反映されません。ノード固有の設定は毎回のapplyで更新されるため、「一部は反映されるのに一部は無視される」という分かりにくい挙動になります。動的設定を有効にするなら、クラスター全体設定の管理はk0sctl.yamlから切り離す、と決めておくのが安全です。
v0.32系の接続実装刷新とロールバック指針
バージョン選定にも注意点があります。v0.32系はホストへの接続とリモート実行の実装が刷新されており、apply・backup・reset の実行時に「挙動は変わらないはずだが、問題が起きたら報告のうえv0.31.1へロールバックしてほしい」という趣旨の警告が標準エラー出力へ表示されます。既存クラスターを運用中で接続まわりに不安がある場合は、この警告が出ることを前提に検証環境で先に確認してください。
k3s・kubeadm・minikubeとの使い分けと採用を見送る条件
4ツールの層の違いと比較軸
比較対象として並べられがちな3つですが、そもそも競合していないものが混ざっています。
| ツール | 層 | 複数ノード構築 | 主な用途 |
|---|---|---|---|
| k0sctl | 構築・運用ツール | SSHで自動 | k0sクラスターの恒常運用 |
| k3s | Kubernetes本体 | 各ノードで手動またはIaC | 軽量・エッジ用途 |
| kubeadm | 構築ツール | 各ノードで手動実行 | 標準構成のクラスター構築 |
| minikube | ローカル実行環境 | 複数ホストへの分散は対象外 | 学習・開発 |
k3sはk0sと同じくディストリビューション側の存在で、k0sctlの対抗馬ではありません。読み方や導入手順はk3sとKubernetes(k8s)の違いを整理した記事に譲ります。kubeadmとの違いは実行モデルにあります。kubeadmは各ノードへログインして kubeadm init と kubeadm join を実行する必要があり、その手作業を外部から自動化するのがk0sctlの立ち位置です。同じ役割をAnsibleで担うのがKubesprayによるクラスター構築で、既にAnsible資産があるならそちらのほうが統合しやすくなります。minikubeは単一ホスト上の開発環境であり、比較軸が異なります。--nodes で1台のマシン内に複数ノードを作ることはできますが、複数の実機へ分散させる用途は守備範囲外です。ローカル検証の手触りはminikubeのダッシュボード操作を参照してください。
採用を見送るべき3つの条件
採用を見送るべき条件をはっきり書きます。単一ノードしか使わないなら、k0sctlは過剰です。role: single という選択肢は用意されていますが、学習や単発の検証が目的なら、ノード上で k0s install を直接実行するほうが、設定ファイルとSSH鍵の管理コストが不要な分だけ速く済みます。SSH到達性が確保できない環境でも採用できません。k0sctlの動作はSSH(またはWindowsのWinRM)接続が前提で、エージェントをノード側に常駐させる方式ではないためです。踏み台の先に閉じたセグメントがある構成では、まず接続経路の設計が先になります。
そしてマネージドKubernetesが選べる環境なら、そちらを優先してください。k0sctlはコントロールプレーンの可用性設計、etcdのバックアップ、ロードバランサーの用意をすべて自前で負う前提の道具です。オンプレでLoadBalancerサービスを成立させるにはMetalLBのようなベアメタル向け実装を別途組み込む必要があり、その運用まで引き受けられるかが採用判断の分かれ目になります。
よくある質問
k0sctlの読み方は?
「ケーゼロエスコントロール」または「ケーゼロエスシーティーエル」と読まれます。公式に定義された日本語読みはありません。末尾の ctl は kubectl と同様にcontrolの略と解されますが、公式ドキュメントに由来の記述はありません。k0s本体とk0sctlは別のバイナリで、リリースサイクルも独立しています。2026年8月時点でk0sはv1.36.3+k0s.0、k0sctlはv0.32.2です。
k0sctlはWindowsでも使えますか?
操作端末としてのWindowsは正式にサポートされ、k0sctl-win-amd64.exe が配布されているほかWinGetとChocolateyからも導入できます。一方、クラスターを構成するノードとしてのWindowsは扱いが異なり、workerロールに限って、SSHまたはWinRM経由で参加できます。この対応は公式が実験的と位置づけており、k0s 1.34以上が必要です。コントローラーをWindowsで動かすことはできません。
k0sctlのライセンスは?商用利用できますか?
k0sctlとk0sはどちらもリポジトリ直下のLICENSEでApache License 2.0を採用しており、商用利用に制限はありません。ただし両リポジトリとも docs/ 配下だけは例外で、CC-BY-SA-4.0が適用されます。公式ドキュメントの文面をそのまま自社資料へ転載する場合は、同一ライセンスでの継承と出典表示が必要になる点に注意してください。
k0sctl applyが途中で失敗したときは何を見ればよいですか?
まず標準出力に流れるフェーズ名を確認します。「Connect to hosts」で止まればSSHの鍵・ポート・ユーザー設定、「Validate hosts」で止まればsudo権限やOS要件、「Download k0s binaries on hosts」で止まればノードからの外部到達性が疑われます。失敗時のエラーメッセージにはログファイルの保存先パスが含まれるため、そのファイルを開けば詳細が追えます。閉域環境では uploadBinary: true でローカルから配布する方法に切り替えます。
設定ファイルに認証情報を直接書かずに済ませる方法はありますか?
環境変数の展開に対応しています。$VAR と ${VAR} のほか、${VAR:-DEFAULT_VALUE} の形式で既定値も書けます。$ 自体を出力したい場合は $$var のようにエスケープします。CIでSSHユーザーやホストアドレスを秘匿したい場合は、この仕組みでシークレットストアの値を注入してください。