- 物理機リージョン/AZ
- ハイパーバイザVM exit で捕まえる
- VMゲストOS今ここ
- コンテナnamespace / cgroup今ここ
- プロセスアプリ / DB
宣言が記録されることと、世界がその通りになることの間には、比べて埋める者の仕事が挟まります。
まず結論
Kubernetes の apply が `created` を返すのは、望む状態(spec)が記録された時点です。動いているかは、コントローラが観測して書く status を見るまで分かりません。
Terraform の apply は、作成なら provider の Create が返るまで待ちますが、何を待つかは provider と属性で決まります。docker provider の既定では、コンテナのプロセスが生きているかは見ません。
存在しないイメージタグ `busybox:no-such-tag-xyz` を指定した Deployment を `kubectl apply` しました。コマンドはどう返るでしょうか(k3s v1.37.0 で実測)。
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
1つのオブジェクトに、書く欄と書かれる欄がある
Deployment は「同じ Pod をいくつ動かすか」を書くオブジェクトで、数を合わせる仕事は配下の ReplicaSet と、それぞれのコントローラが受け持ちます。
Kubernetes の文書は、ほぼすべてのオブジェクトが2つの欄を持つと書きます。
For objects that have a spec, you have to set this when you create the object, providing a description of the characteristics you want the resource to have: its desired state.
The status describes the current state of the object, supplied and updated by the Kubernetes system and its components.
spec は利用者が書く欄、status はシステムが書く欄です。 apply が書くのは spec(と metadata)で、status には触れません。status に何かが書かれるのは、コントローラや kubelet が世界を見て動いた後です。
- ・apply の成功が保証するのは1段目まで
- ・2段目以降の失敗は、apply の出力ではなく status と Pod の状態に出る
存在しないタグの Deployment は created になる
k3s v1.37.0(rancher/k3s:v1.37.0-k3s1)で、存在しないタグを指定した Deployment を作りました。
apiVersion: apps/v1kind: Deploymentmetadata: {name: web}spec:replicas: 1progressDeadlineSeconds: 20selector: {matchLabels: {app: web}}template:metadata: {labels: {app: web}}spec:containers: [{name: c, image: busybox:no-such-tag-xyz, command: ["sleep","3600"]}]
$ kubectl apply -f l2-dep-bad.yamldeployment.apps/web createdexit=0$ kubectl rollout status deploy/web --timeout=45s # 22:50:32Waiting for deployment "web" rollout to finish: 0 out of 1 new replicas have been updated...Waiting for deployment "web" rollout to finish: 0 of 1 updated replicas are available...error: deployment "web" exceeded its progress deadlineexit=1 # 22:50:53$ kubectl get pods -l app=webNAME READY STATUS RESTARTS AGEweb-b48d44d4d-2d6fs 0/1 ImagePullBackOff 0 21s$ kubectl get deploy web -o jsonpath='{range .status.conditions[*]}{.type}={.status} reason={.reason} lastTransition={.lastTransitionTime}{"\n"}{end}'Available=False reason=MinimumReplicasUnavailable lastTransition=2026-09-27T22:50:32ZProgressing=False reason=ProgressDeadlineExceeded lastTransition=2026-09-27T22:50:52Z$ kubectl get deploy web -o jsonpath='{.metadata.generation} {.status.observedGeneration} {.spec.progressDeadlineSeconds}'1 1 20
apply は created と exit 0 で返りました。失敗が現れたのは別の場所です。Pod の STATUS は ImagePullBackOff、イベントには ErrImagePull と not found が出ていました。status には作成から約20秒後に ProgressDeadlineExceeded が付き、rollout status は exit 1 で終わりました(終了コードは文書に規定が無く、実測です)。2回流して同じ結果でした。Pod 名や秒数はこの実行のものです。
最後の行の 1 1 は、generation と .status.observedGeneration が一致していることを示します。API Conventions は observedGeneration を、the reported status reflects the most recent desired status を確かめるために使えると書きます。コントローラは今の spec を見たうえで、失敗を書いています。
期限を超えた後も、Kubernetes はロールバックしません。
Kubernetes takes no action on a stalled Deployment other than to report a status condition with reason: ProgressDeadlineExceeded.
Deployment の status に `Progressing=False reason=ProgressDeadlineExceeded` が付いた後、Kubernetes は何をしますか。
「返る」が指す時点は、道具ごとに違う
Terraform の apply は executes the operations proposed in a Terraform plan と説明されます。ただ apply の文書には、何をもって完了とするかを述べる文がありません。実際に待つのは、各リソースの操作が返るまで、作成なら provider の Create が返るまでです。何を確かめてから返すかは provider の実装と属性で決まります。
docker provider v4.6.0 の docker_container には、待ち方を決める属性が2つあります。
wait(Boolean) Iftrue, then the Docker container is waited for being healthy state after creation. This requires your container to have a healthcheck, otherwise this provider will error. Iffalse, then the container health state is not checked. Defaults tofalse.
must_run(Boolean) Iftrue, then the Docker container will be kept running. ... If your container is stopped, Terraform will setmust_runtofalseand this will trigger a change. Defaults totrue.
既定では、作った直後に healthy かどうかを見ません。止まったことは、次に比べたときに差分として現れます。
docker provider の apply は何を待っているか
Terraform 1.16.4 と docker provider v4.6.0(Docker Engine 28.4.0)で試しました。実行には /var/run/docker.sock をマウントしており、これはホストの Docker を操作する権限を渡すことです。
######## B: cmd exits immediately with 1$ terraform apply -auto-approve -var=cmd=["sh","-c","exit 1"]docker_container.web: Creating...docker_container.web: Creation complete after 1s [id=6b6ae59de287ae1360cc7475ae98ac5cd9d247dc1301176222361bacc22e3fd3]Apply complete! Resources: 1 added, 0 changed, 0 destroyed.exit=0 elapsed=1s 22:58:31$ docker ps -a --filter name=decl-l2 --format '{{.Status}}'Exited (1) Less than a second ago | "sh -c 'exit 1'"$ sleep 3; terraform plan -no-color # container is stopped now# docker_container.web will be updated in-place~ must_run = false -> truePlan: 0 to add, 1 to change, 0 to destroy.
apply は成功し、コンテナは止まっていました。条件を変えた結果です(2ラウンドとも同じ)。
条件 apply コンテナ既定、8秒後に exit 1 exit=0 elapsed=1s 10秒後 Exited (1)wait=true、healthcheck なし Error: ... does not have a healthcheck ... Up のまま残るwait=true、常に失敗、timeout 15 Error: container failed to be in healthy state elapsed=16s Up 15 seconds (unhealthy)wait=true、healthcheck 成功 Creation complete after 3s Up 3 seconds (healthy)存在しないタグ Error: ... unable to pull image ... not found 作られない
wait=true にすれば healthy まで待ちますが、待ちきれずにエラーになってもコンテナは残りました。そして存在しないタグは、Kubernetes と違って apply のエラーになります。pull が provider の Create の中で行われるからです。
docker provider v4.6.0 の既定(wait=false)で、すぐ `exit 1` するコマンドのコンテナを terraform apply しました。実測で何が起きましたか。
Kubernetes: 存在しないタグ
apply は spec を記録して created で返ります。pull は後で kubelet が行い、失敗は Pod の ImagePullBackOff と、期限後の ProgressDeadlineExceeded として status に現れます。
場所 出たものkubectl apply created / exit=0Pod の STATUS ImagePullBackOffDeployment の status Progressing=False ProgressDeadlineExceeded
Terraform: すぐ止まるコンテナ
apply は provider の Create が返った時点で成功です。既定の wait=false ではプロセスの生死を見ないので、止まったことは次の plan の must_run の差分として現れます。
場所 出たものterraform apply 1 added / exit=0docker ps Exited (1)次の terraform plan ~ must_run = false -> true
片方は記録で返り、片方は作成で返りました。それでも「apply 成功なのに動いていない」が両方で起きたのはなぜでしょうか。
apply の内側で確かめたことと、確かめなかったことを分けてみてください。
この章のまとめ
- spec は利用者が書く欄、status はシステムが書く欄。 apply が書くのは spec(と metadata)で、status には触れない。
- Kubernetes の apply の
createdは 記録されたという応答。存在しないタグでも exit 0 で返った。 - 失敗は Pod の
ImagePullBackOffと status のProgressDeadlineExceededに出る。期限の既定は 600秒(実演は20秒に縮めた)。Kubernetes は報告するだけで、ロールバックしない。 - status を読むときは observedGeneration と generation の一致を見る。
- Terraform の apply は、作成なら provider の Create が返るまで待つ。docker provider の既定ではプロセスの生死を見ず、止まったことは次の plan で差分になる。
- 同じ存在しないタグでも、pull が apply の中にある Terraform ではエラー、後にある Kubernetes では created。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
この回の実演では約20秒で ProgressDeadlineExceeded が付きました。progressDeadlineSeconds を書かなかった場合はどうなりますか。
用語集(5語)
- spec
- オブジェクトに利用者が書く、望む状態。作成時に設定する。
- status
- オブジェクトの現在の状態。Kubernetes のシステムとその部品が書き、更新する。
- progressDeadlineSeconds
- Deployment が進まないと報告するまでの秒数。既定は600。超えると Progressing=False, reason ProgressDeadlineExceeded が付く。
- observedGeneration
- status を書いた者が最後に見た spec の世代。metadata.generation より小さければ、その status は古い spec についての報告。
- must_run / wait(docker provider)
- docker_container の属性。must_run は既定 true で、止まっていれば次の plan で差分になる。wait は既定 false で、true なら healthcheck が healthy になるまで待つ。
出典(一次ソース)
- Kubernetes — Objects in Kubernetes (Last modified November 24, 2025) ↗
- Kubernetes — Deployments (Last modified July 07, 2026) ↗
- Kubernetes — kubectl rollout status (Last modified August 26, 2026, v1.37) ↗
- Kubernetes community — API Conventions (observedGeneration) ↗
- Terraform — terraform apply command (取得 2026-09-28、実演は Terraform 1.16.4) ↗
- kreuzwerker/terraform-provider-docker v4.6.0 — docker_container ↗