⚠️ 概要と原因
■概要
Elasticsearchの運用で entrypoint.sh を修正した際、「ECRにプッシュしてTerraformもApplyした。タスク定義も更新された。なのに、なぜか中身が古い…」という事象に遭遇しました。
■原因
原因は、イメージ名にタグを指定せず 「デフォルトの :latest 参照」 に頼っていたことによる、Fargateのキャッシュ挙動でした。
🤧 何が起きたのか?
-
修正:
entrypoint.shを書き換え、Dockerイメージをビルド。 -
プッシュ: ECRへ
elasticsearch-serviceとしてプッシュ。
※タグなしでプッシュすると、自動的に:latestとして扱われる。 -
デプロイ: Terraformでタスク定義を更新。イメージ指定は
elasticsearch-serviceのまま Apply完了。 - 確認: 新しいタスクがRunningになったが、中身は修正前の古いスクリプトのまま。 orz
結局、AWSコンソールから 「新しいデプロイの強制」 を実行してようやく最新版に切り替わりました。
🔍 なぜタスク定義も更新されたのにイメージが古いままだったのか?
原因は、「タスク定義から見た文字列」が変わっていないこと にあります。
1. 「タグなし(latest)」は「変化なし」とみなされる
タスク定義内のイメージ指定が elasticsearch-service:latestだと、イメージを更新して Terraform を実行しても、タスク定義上の定義は 1文字も変わりません。 Terraformは「設定に変更があった」とみなしてリビジョンを新しくはしてくれますが、ECS側から見ると「参照先URL」自体は同一とみなされるそうです。
2. Fargate的には効率化してくれている
Fargateのタスクが起動する際、タグが固定(あるいは未指定)だと、以下のような挙動をとることがあります。
「新しいタスクを起動するぞ。イメージは
elasticsearch-serviceか。…おや、ホスト上のキャッシュにさっき使ったイメージがあるな。 通信節約のためにこれを使おう!」
ECRにある「中身が入れ替わった最新イメージ」を無視して、ノードに残っていた古い実体 でコンテナが立ち上がってしまうのです。
🚀 今後の対策
今回はentrypoint.shで出力してるログの形式を変更していたのでその確認で気づけましたが、場合によっては気づかずに古いイメージが走り続けてるパターンもあると思います。
「タグを指定しない」運用は、キャッシュ問題に当たるので、以下のような構成へ移行を検討しましょう。
イメージタグに「コミットハッシュ」を明示する
CI/CDパイプラインで、ビルドごとにユニークなタグ(GitのSHAなど)を付与し、それをTerraform経由でタスク定義に渡します。
- Terraform側の修正例:
# image_tag = "sha-8b2f3a" のように毎回変わる値を渡す
container_definitions = jsonencode([
{
name = "elasticsearch-service"
image = "[xxx.dkr.ecr.ap-northeast-1.amazonaws.com/elasticsearch-service:$](https://xxx.dkr.ecr.ap-northeast-1.amazonaws.com/elasticsearch-service:$){var.image_tag}"
}
])