以下の内容はhttps://syobochim.hatenablog.com/entry/2025/03/03/141050より取得しました。


M1 MacでビルドしたコンテナをECS上にデプロイしたらヘルスチェック失敗して一生デプロイが終わらなかった

TL;DR

  • M1 MacでDockerイメージをビルドしてECS (Fargate) にデプロイしたら、ヘルスチェックが失敗し続けてCDKのデプロイが完了しなかった。
  • 原因は M1 Mac 上で arm64 でビルドされていたこと。Fargate はデフォルト amd64 で動作するため、platform: assets.Platform.LINUX_AMD64 を指定したら解決。
  • もしくは、Fargate のタスク定義のランタイムに arm64 を指定する

☝️ はじめに

gRPC のサービスをECS(Fargate)上にデプロイしようとしたところ、タスクは起動するのに、ヘルスチェックが通らずに一生 CloudFormation が "CREATE_IN_PROGRESS" のまま デプロイが終わらないという事象に遭遇しました。
その原因と解決策について、記録を残しておきます。

☁️ 環境

  • 開発マシン: MacBook Pro (M1)
  • ECS実行環境: AWS Fargate (x86_64)
  • コンテナ: Go製のgRPCサービス
  • CDKでのデプロイ

ちなみに、デプロイしたのは、作ってわかる! はじめてのgRPC でした!gRPC をわかりやすく学べてオススメ!

💥 発生事象

AWS CDKを使ってECSにデプロイしたところ、デプロイが全く終わらなかった。
環境を見に行くと、ECS のタスクは起動しているものの、 ヘルスチェックがずっと成功しない。結果としてタスクが起動と終了を繰り返し続けていました。

ヘルスチェックが終わらないので、ECSの execute-command を使って、タスク内で直接 /bin/sh を実行してみた。

aws ecs execute-command \
  --cluster GrpcApiCluster \
  --task <task-id> \
  --command "/bin/sh" \
  --interactive

すると、以下のエラーが発生。

SessionId: ecs-execute-command-2v4gc4qaj4grjrlf6dk8krrcz8 : 
----------ERROR-------
Unable to start command: Failed to start pty: fork/exec /bin/sh: exec format error

本来、正常なコンテナであれば sh のプロンプト (sh-4.2# など) が表示され、シェルの入力が始まる 。(実際に、問題解決後は実行できた。)
なので、このエラーから /bin/sh 自体が破損しているか、アーキテクチャの不一致で実行できない ことがわかった。

💡 解決策

CDKで DockerImageAsset を定義する際に、platform: assets.Platform.LINUX_AMD64 を明示的に指定すればOK。

修正前(arm64のままビルドされる)

import * as assets from 'aws-cdk-lib/aws-ecr-assets';
(略)
const asset = new assets.DockerImageAsset(this, 'GrpcApiImage', {
  directory: path.join(__dirname, '../path'),  // Dockerfileのフォルダまでのパス
});

修正後(amd64でビルドするよう指定)

import * as assets from 'aws-cdk-lib/aws-ecr-assets';
(略)
const asset = new assets.DockerImageAsset(this, 'GrpcApiImage', {
  directory: path.join(__dirname, '../path'),  // Dockerfileのフォルダまでのパス
  platform: assets.Platform.LINUX_AMD64  // platform の記述を追加
});

この変更により、M1 Macでも x86_64 向けのコンテナイメージをビルドできるようになり、ECS上で正しく動作するようになった。

また、Dockerfile 内で --platform を指定する方法もある。

Dockerfile の修正例(amd64 でビルドする)

FROM --platform=linux/amd64 golang:1.23 as builder

これを指定することで、M1 Mac上でも amd64 向けのビルドが可能になり、ECS (Fargate) での互換性を確保できる。(こっちの方が良さそう)

↓なお、 platform の説明は以下。

FROM でマルチプラットフォーム対応のイメージを参照する場合には、オプションの --platform フラグを使うと、特定のプラットフォーム向けイメージを指定できます。たとえば、 linux/amd64 や、 linux/arm64 や、 windows/amd64 です。デフォルトでは、今まさに利用しているプラットフォームを対象として構築します。 グローバル構築引数global build arguments が、このフラグの値をとして利用できます。たとえば 自動的なプラットフォーム ARG は、構築段階でネイティブな構築プラットフォームを上書きでき( --platform=$BUILDPLATFORM )、これを、そのステージ内で対象プラットフォーム向けのクロス・コンパイルとして利用できます。
Dockerfile リファレンス — Docker-docs-ja 24.0 ドキュメント

ARM64 のまま実行したいときはランタイムを指定

arm64 のイメージのまま実行したいときは、タスク定義にて cpuArchitecture を指定する

import * as ecs from 'aws-cdk-lib/aws-ecs';
(略)

    // Task definition
    const taskDefinition = new ecs.FargateTaskDefinition(this, 'GrpcApiTaskDef', {
      runtimePlatform: {
        cpuArchitecture: ecs.CpuArchitecture.ARM64,  // この部分を追加
      },
    });

class CpuArchitecture · AWS CDK

📝まとめ

  • M1 MacでDockerをビルドすると、デフォルトで arm64 になるので要注意
  • ECS(Fargate)でデフォルトの設定で動かすなら amd64 でビルドする必要がある
  • AWS CDKを使う場合は2つの対策がある(どちらかを実施)
    • DockerImageAssetplatform: assets.Platform.LINUX_AMD64 を指定して amd64 として動かす
    • FargateTaskDefinitionruntimePlatformcpuArchitecture: ecs.CpuArchitecture.ARM64 を指定し、arm64 として動かす
  • Dockerfile でビルドイメージの指定もできる



以上の内容はhttps://syobochim.hatenablog.com/entry/2025/03/03/141050より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14