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つの対策がある(どちらかを実施)
DockerImageAssetにplatform: assets.Platform.LINUX_AMD64を指定してamd64として動かすFargateTaskDefinitionのruntimePlatformにcpuArchitecture: ecs.CpuArchitecture.ARM64を指定し、arm64として動かす
- Dockerfile でビルドイメージの指定もできる