非常に良い質問です。
Kubernetesの「Desired State(望ましい状態)」は、宣言的構成管理の中核にあたる概念であり、
複数のリソース定義(YAMLマニフェスト)が同じ対象に異なる状態を要求すると、最終的にどの状態が採用されるかは非常に重要です。
以下では、
判定の仕組み
実際の挙動
代表的な矛盾ケース
対策方法
を体系的に解説します。
【1】Kubernetesの「Desired State」判定の仕組み
Kubernetesは「最後に適用されたマニフェストがクラスタの真実(Source of Truth)になる」という原則に基づきます。
この原則を**“last write wins(最後の書き込みが勝つ)”**と呼びます。
各リソース(Pod、Deployment、Serviceなど)はetcdにJSONとして保存されます。
同じリソース名・Namespaceを持つオブジェクトに複数の「Desired State」をkubectl applyやAPI経由で投入した場合、最後に適用されたものがetcd上で上書きされます。
Controller ManagerやSchedulerは、etcd内の最新状態を「正」として同期をとります。
つまり、矛盾があっても競合エラーではなく「上書き更新」として処理されるのが基本です。
【2】実際の挙動の例
例:同一Deploymentを別YAMLで異なる設定
deployment-a.yaml
spec: replicas: 3 template: spec: containers: - name: app image: nginx:1.21
deployment-b.yaml
spec: replicas: 5 template: spec: containers: - name: app image: nginx:1.25
両方を同じDeployment名で適用した場合:
kubectl apply -f deployment-a.yamlkubectl apply -f deployment-b.yaml
結果:
→ Kubernetesは衝突検出をしない。最後の宣言を正とみなす。
【3】代表的な「矛盾」パターン
| 矛盾の種類 | 内容 | 挙動 |
|---|
| 同一リソースを複数マニフェストで管理 | 例:同じDeployment名でreplicasやimageが異なる | 後からapplyした内容で上書き(last write wins) |
| 異なるController間の競合 | DeploymentがPodを作り、同名のPodを別Jobも作成 | コントローラ間で衝突。Pod再作成のループが発生する可能性 |
| Service/Ingress競合 | 同じService名で異なるPort定義 | 上書き。通信経路が一時的に不安定化 |
| ConfigMap/Secret競合 | 同じ名前で異なるデータキー | 直近のapplyが反映。既存値は消える。 |
| Namespace重複定義 | 同名Namespaceをapply | 2回目は無視(Namespaceは一意) |
【4】内部的な判定フロー
API Serverがリソースを受理し、metadata.nameとmetadata.namespaceで一意性を確認。
既に存在する場合は「更新」とみなし、etcd上のオブジェクトを上書き。
Controller Managerが新しいspecとの差分を検知して調整(Podの再起動やスケーリング)。
Reconciler Loopにより、etcd上の最新specと実際のクラスタ状態を一致させる。
→ Kubernetesは「矛盾検知」ではなく「再調整(reconciliation)」を行うアーキテクチャです。
【5】対策方法
① 1リソース=1管理単位の原則
② GitOpsで単一のSource of Truthを確保
③ Namespace・Labelで責務分離
④ kubectl diff や server-side apply の活用
⑤ ResourceQuotasやAdmission Policyの導入
【6】まとめ
| 観点 | 内容 |
|---|
| 衝突時の原則 | last write wins(最後のapplyが有効) |
| Kubernetesの挙動 | 矛盾検知はせず、自動的に最新specで再調整 |
| リスク | 意図しない上書きやPod再起動、設定消失 |
| 主な対策 | GitOps、Namespace分離、server-side apply、ポリシー管理 |
この記事へのコメント