はじめに
Kubernetes において、マニフェストをもとにリソースの作成を命令するには kubectl create と kubectl apply の 2 種類を利用することができます。
$ kubectl create -f deployment.yaml
$ kubectl apply -f deployment.yaml
これらのコマンドは一見似ていますが、挙動に明確な違いがあります。
命令的 か 宣言的 か
結論から述べると、create サブコマンドは 命令的 で、apply サブコマンドは 宣言的 です。
| サブコマンド | 機能 | 用途 |
|---|---|---|
| create | 新しいリソースを 命令的 に作成 | 初回デプロイや一時的なテスト |
| apply | マニフェストをもとに 宣言的 に適用(作成 or 更新) | 運用・継続的な設定管理 |
『命令的』、『宣言的』とは何かという話ですが、Kubernetes ではこれらのオペレーションに明確な違いがあります。
命令的:Imperative
命令的とは「今すぐこうして」という 手順ベースの指示 のことで、Kubernetes に「やり方」を命令してリソースを操作します。
例えるなら、シェフに対して「鍋を取って、火をつけて、玉ねぎを炒めて」とすべての操作手順を開発者自身が具体的に指示するイメージです。
宣言的:Declarative
一方の宣言的とは、「こういう状態であってほしい」という 結果ベースの宣言 のことで、Kubernetes に対して「望むべき最終状態」を伝達してリソースを操作します。そのため、具体的な手順は Kubernetes が自動的に判断・制御します。
こちらは、例えるなら「カレーを作ってほしい」とシェフに伝えるイメージです。材料の選定や火加減はシェフ(= Kubernetes)が決定します。つまり、指示をした側は「最終的な状態」のみを受け取ります。
create サブコマンド
- リソースを一度だけ新規作成する際に使用する
- すでに同じ名前のリソースがあればエラーとなる
- 設定変更時には
createではなくreplaceまたはapplyが必要
### Deployment の作成
$ kubectl create -f deployment.yaml
もし、存在していれば以下のようなエラーになります。
Error from server (AlreadyExists): deployments.apps "my-app" already exists
apply サブコマンド
- YAML をもとに作成または更新(差分更新)する際に使用する
- 「宣言的」にリソースを管理
- クラスタ内の状態を自動的に調整する
### Deployment の作成
$ kubectl apply -f deployment.yaml
こちらは何度実行しても差分のみが反映されます。
3-way merge
apply サブコマンドの場合、3 つの状態を比較して、どの部分を更新すべきか判断します。これを「3-way merge」と呼んだりします。
| 状態 | 内容 |
|---|---|
| Last Applied | 最後に apply した内容(kubectl.kubernetes.io/last-applied-configuration に保存) |
| Live | 現在のクラスタ上の状態 |
| New | 今回適用する YAML |
apply サブコマンドは、「3-way merge」により、変更部分だけを安全に反映します。そのため、複数人が管理していても衝突しにくくなっています。
Server-Side Apply(SSA)
Kubernetes 1.18 以降では、kubectl apply --server-side が登場しました。これは「差分計算」をサーバ側で行う新しい宣言的管理方式です。SSA は Client-Side Apply(CSA)の課題を解決し、より安全でスケーラブルな「宣言的管理」を実現します。
例えば、マニフェストサイズが極端に大きい場合以下のような問題が発生します。
is invalid: metadata.annotations: Too long: must have at most 262144 bytes
CSA と SSA の違い
Kubernetes の apply には、2 つの方式が存在します。
それぞれの違いを理解することで、より安全なリソース管理が可能になります。
| 比較項目 | Client-Side Apply(CSA) | Server-Side Apply(SSA) |
|---|---|---|
| 差分計算 | クライアント側(kubectl) | サーバ側(kube-apiserver) |
| 状態保持 | アノテーションに保存(last-applied-configuration) |
サーバ内部で管理(フィールドオーナ情報) |
| 競合検出 | 弱い(上書きされやすい) | 強い(競合時にエラーを返す) |
| 処理速度 | 小規模では軽量 | 大規模でも安定 |
| 適用対象 | 単一ユーザ・手動操作 | チーム運用・GitOps・CI/CD 環境 |
| コマンド例 | kubectl apply -f deployment.yaml |
kubectl apply --server-side -f deployment.yaml |
CSA の特徴
-
kubectlがローカルで差分を計算してから API サーバに送信する - 過去の状態をアノテーションに保存して管理
- シンプルだが、複数ツールや複数人で操作すると衝突リスクがある
SSA の特徴
- 差分計算を API サーバ側 が担当
- Kubernetes が各フィールドの 所有者(Field Manager)を追跡
- 同一フィールドを別のツールが変更しようとすると
409 Conflictを返して競合を防止 - GitOps や大規模運用での変更管理に最適
| シーン | 推奨方式 | 理由 |
|---|---|---|
| 開発者が手動で apply する | CSA | シンプルで理解しやすい |
| 複数チーム・ツールで構成を管理する | SSA | フィールド単位で安全に管理できる |
| GitOps(ArgoCD, Flux)環境 | SSA | サーバ側で差分を一元管理できる |
まとめ
| コマンド / 方式 | 操作方式 | 差分計算の場所 | 管理スタイル | 主な用途 |
|---|---|---|---|---|
kubectl create |
命令的 (Imperative) | なし | 手順ベース | 単発・初期作成 |
kubectl apply(CSA) |
宣言的 (Declarative) | クライアント側 | YAML ベース | 基本はこれを利用 |
kubectl apply --server-side(SSA) |
宣言的 (Declarative) | サーバ側 | フィールド所有制 | マニフェストサイズが極端に大きい場合 |
Kubernetes は、基本的に宣言的な状態管理を基本思想として設計されているので、結論 kubectl apply を利用しておけば問題ありません。