Terraform で AWS のコンテナ環境(ECS / ECR)を構築すると、どのリソースが・どのタイミングで・何をしているのかが分かりづらくなりがちです。私自身、ECSの仕組みを理解するのにとても時間がかかりました。
本ドキュメントでは、AWS 上で Docker コンテナが起動するまでの流れを、コードを見ながら「役割ベース」で理解することを目的とします。
※ 手順書ではなく、全体構造を掴むためのものですので、そのことを前提に読んでいただけると嬉しいです。
用語の前提整理
| 用語 | 役割 |
|---|---|
| ECR | Docker イメージを保管するレジストリ |
| ECS | Docker コンテナを起動・管理するサービス |
| Task Definition | 「このイメージを、どんな設定で起動するか」を定義する設計書 |
| Service | Task Definition を使って、タスクを起動・維持する仕組み |
※ IAM / VPC / ALB の詳細な構築方法は本ドキュメントでは扱いません
(ECS がそれらを“使って何をするか”に焦点を当てます)
全体像
AWS のコンテナ運用は、大きく次の 2 フェーズに分かれます。
- Docker イメージを作って ECR に置く
- ECS がそのイメージを使ってコンテナを起動する
① Dockerfile作成
② Dockerイメージをビルド
③ ECRリポジトリへイメージをpush
④ ECSタスク定義で ECR のイメージURIを指定する
⑤ ECSクラスター上で サービス or RunTask を実行する
⑥ ECSがタスク定義を参照し、ECRからイメージを pull する
⑦ コンテナが起動し、アプリケーションが起動する
👉 ECS は Dockerfile も build 処理もしません。
👉 ECS が知り得るのは「ECR にあるイメージ」だけになります。
以下の図を参考にしてください。

参照:https://medium.com/%40ahmedSalem2020/deploying-a-docker-nginx-image-using-amazon-ecr-and-ecs-119e7d9b78d9
1. Dockerfile作成
まずはコンテナのベースとなるDockerfileを作成します。
Dockerfileでは以下を定義します。
- どの OS / ランタイムを使うか
- アプリケーションの配置場所
- コンテナ起動時に何を実行するか
# docker/env.prod/node/Dockerfile
# コンテナのベースとなる Node.js 実行環境を指定
FROM node:22-alpine
# コンテナ内での作業ディレクトリ
WORKDIR /work/backend
# ビルド済みの Next.js アプリケーションを配置
COPY ./.next/standalone .
COPY ./.next/static ./.next/static
COPY ./public ./public
# コンテナ起動時に最初に実行されるスクリプトを配置
COPY ./docker/env.prod/node/entrypoint.sh ./entrypoint.sh
RUN chmod +x ./entrypoint.sh
# コンテナが起動したら Node.js アプリを起動する、という定義
EXPOSE 3000
ENTRYPOINT ["./entrypoint.sh"]
CMD ["node", "server.js"]
2. Docker イメージを build & ECR に push(CI)
目的:ECS が使える形で Docker イメージを登録します。
ECS は Dockerfile を直接扱えないため、事前に Docker イメージを作成し、ECR に登録する必要があります。この処理を GitHub Actions で自動化します。
# .github/workflows/app-node.yaml
name: build-and-push
# 本番用ブランチに push されたタイミングで実行
on:
push:
branches: [release/prod]
jobs:
build:
runs-on: ubuntu-latest
# GitHub Actions が AWS にアクセスするための認証設定
steps:
- uses: actions/checkout@v3
# AWS認証(OIDC)
- uses: aws-actions/configure-aws-credentials@v3
with:
aws-region: ap-northeast-1
role-to-assume: arn:aws:iam::<account-id>:role/ExternalGithubForDeploy
# ECR に Docker push するためのログイン
- uses: aws-actions/amazon-ecr-login@v1
# Dockerfile を使ってイメージを build
# build したイメージを ECR に push
- uses: docker/build-push-action@v4
with:
context: .
file: ./docker/env.prod/node/Dockerfile
push: true
# イメージを一意に識別するため、commit SHA をタグに使用
tags: <account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/<service-name>:${{ github.sha }}
👉 ECS は GitHub Actions や Docker build には一切関与しません。
3. ECR(イメージの保管場所)
目的:ECS が参照するイメージの置き場です。
<account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/<service-name>:<tag>
ECS はこの URI を指定されることで、Docker イメージを取得し、「どのバージョンを起動するか」は タグで制御されます。
👉 ECR はただの保管庫、起動はしません。
4. ECS Task Definition(起動設計書)
目的:「このイメージを、どう起動するか」を ECS に伝える
Task Definition では、以下を定義しています。
- 使用する Docker イメージ
- CPU / メモリ
- ポート
- ログ出力設定
resource "aws_ecs_task_definition" "this" {
# タスク定義名
family = "<cluster-name>"
# Fargate 上で確保するリソース量
cpu = 1024
memory = 2048
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
execution_role_arn = var.task_role_arn
task_role_arn = var.task_role_arn
container_definitions = jsonencode([
{
name = "<service-name>"
# ECS が pull する Docker イメージ
image = "<account-id>.dkr.ecr.ap-northeast-1.amazonaws.com/<service-name>:${var.image_tag}"
essential = true
portMappings = [{
containerPort = 3000
}]
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.<service-name>.name
awslogs-region = "ap-northeast-1"
}
}
}
])
}
👉 ECS は Task Definition を見て初めて「何を起動するか」を理解します。
5. ECS Service(タスク起動のトリガー)
目的:Task Definition を使ってタスクを起動・維持します。
Service は「いつ・いくつ」タスクを起動するかを管理します。
resource "aws_ecs_service" "this" {
name = "<service-name>"
cluster = aws_ecs_cluster.default.id
task_definition = aws_ecs_task_definition.this.arn
desired_count = 1
launch_type = "FARGATE"
network_configuration {
subnets = var.vpc_subnets
security_groups = var.vpc_security_groups
}
}
👉 関係性
Service
└─ Task Definition
└─ ECR Image URI
6. タスク起動時に ECS が行うこと(超重要)
① Service / RunTask が実行される
② ECS が Task Definition を取得
③ ECS が ECR にアクセス
④ Docker イメージを pull
⑤ コンテナを起動
⑥ ENTRYPOINT / CMD を実行
👉 ここで初めて Docker コンテナが動きます。
7. コンテナ起動 → アプリケーション起動
- Node.js / Next.js が起動
- ALB 経由でリクエストを受信
- CloudWatch Logs にログ出力
まとめ
- Dockerfile:アプリを起動できる形にする
- CI / ECR:ECS が使える形でイメージを置く
- Task Definition:どう起動するかを ECS に伝える
- Service:タスクを起動・維持する
- ECS:全部を自動で実行する実行役
いかがでしたか?AWS上で動くDockerコンテナ運用のイメージはつきましたか?
本ドキュメントはあくまでDockerコンテナがAWS上で動くための全体構成をざっくり理解するためのものなので、全体のフローを理解する用として参照していただければ嬉しいです。