この記事について
Docker学習を終えた方が、AWSのコンテナサービス(ECS/ECR)で本番環境にデプロイできるようになるまでの完全ガイドです。
docker-compose.ymlの知識をそのまま活かして、実際に動くクラウド環境を構築できます。
📚 含まれる内容
- ECRの基本操作 - Dockerイメージの保存・管理
- ECS Fargateの基礎 - サーバーレスでコンテナ実行
- Docker ComposeからECSへの移行 - 実践的な変換手順
- RDS連携 - マネージドDBとの接続設定
- ALB設定 - ロードバランサーによる公開
- ログとモニタリング - CloudWatch活用
- コスト概算 - 月額料金の試算方法
- トラブルシューティング - よくあるエラーと解決策
🎯 対象読者
- Dockerの基本を学び終えた方
- docker-compose.ymlが書ける方
- AWSでコンテナを動かしてみたい方
- ローカル環境から本番環境への移行を考えている方
- ECS/ECRの学習コストを抑えたい方
⏱️ 想定学習時間
- 理論の理解: 2〜3時間
- 実践(手を動かす): 4〜6時間
- 合計: 6〜9時間
目次
- はじめに
- AWS ECS/ECRとは
- 環境準備
- ECRの基本操作
- ECS Fargateの基本
- 実践:Docker ComposeからECSへ移行
- RDSとの連携
- ALBの設定
- ログとモニタリング
- コスト概算
- トラブルシューティング
- まとめと次のステップ
1. はじめに
1.1 この資料について
この資料では、Dockerで学んだ知識をAWSのコンテナサービス(ECS/ECR)で実践する方法を解説します。
学習の流れ:
Docker学習資料(完了)
↓
ECRにイメージをプッシュ
↓
ECS Fargateでコンテナ起動
↓
RDSと連携(実用的な構成)
↓
本番運用の基礎
1.2 前提条件
必須:
- ✅ Docker学習資料の内容を理解している
- ✅ AWSアカウントを持っている
- ✅ AWS CLIがインストール済み
- ✅ 基本的なLinuxコマンドが使える
推奨:
- VPCの基本概念を知っている
- IAMの基本を理解している
1.3 使用するAWSサービス
| サービス | 役割 | Dockerとの対応 |
|---|---|---|
| ECR | コンテナイメージ保存 | Docker Hub |
| ECS | コンテナオーケストレーション | Docker Compose |
| Fargate | サーバーレスコンピューティング | docker run のマネージド版 |
| RDS | マネージドデータベース | MySQLコンテナの代替 |
| ALB | ロードバランサー | Nginxの代替 |
2. AWS ECS/ECR とは
2.1 Amazon ECR(Elastic Container Registry)
概要:
Dockerイメージを保存・管理するプライベートレジストリです。
Docker Hubとの違い:
| 項目 | Docker Hub | Amazon ECR |
|---|---|---|
| 公開範囲 | パブリック/プライベート | プライベートのみ |
| 料金 | 無料プランあり | ストレージ+転送量課金 |
| AWS統合 | なし | 完全統合 |
| セキュリティ | 基本的 | IAM、暗号化等 |
使用場面:
- 本番環境のイメージ管理
- チーム内でのイメージ共有
- CI/CDパイプライン
2.2 Amazon ECS(Elastic Container Service)
概要:
Dockerコンテナを本番環境で動かすためのオーケストレーションサービスです。
2つの起動タイプ:
| タイプ | 説明 | 管理対象 | 用途 |
|---|---|---|---|
| Fargate | サーバーレス | AWSが管理 | 推奨・小〜中規模 |
| EC2 | EC2インスタンス使用 | 自分で管理 | 大規模・細かい制御 |
本資料ではFargateを使用します。
2.3 Docker Composeとの対応関係
docker-compose.yml の各要素がECSではどうなるか:
| docker-compose.yml | ECS |
|---|---|
services: |
タスク定義のコンテナ定義 |
image: |
ECRのイメージURL |
ports: |
portMappings |
environment: |
environment または Secrets Manager |
volumes: |
EFSマウントまたはタスクストレージ |
networks: |
VPC、セキュリティグループ |
depends_on: |
コンテナの起動順序 |
例:
# docker-compose.yml
services:
api:
image: myapp:latest
ports:
- "3000:3000"
environment:
- NODE_ENV=production
↓ 対応する ECSタスク定義
{
"containerDefinitions": [
{
"name": "api",
"image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest",
"portMappings": [
{
"containerPort": 3000,
"protocol": "tcp"
}
],
"environment": [
{
"name": "NODE_ENV",
"value": "production"
}
]
}
]
}
3. 環境準備
3.1 AWS CLIのインストールと設定
インストール(Windows):
# MSIインストーラーをダウンロード
# https://awscli.amazonaws.com/AWSCLIV2.msi
# インストール後、確認
aws --version
# 出力例: aws-cli/2.13.0 Python/3.11.4 Windows/10
認証情報の設定:
# IAMユーザーのアクセスキーを設定
aws configure
# 入力項目:
# AWS Access Key ID: YOUR_ACCESS_KEY
# AWS Secret Access Key: YOUR_SECRET_KEY
# Default region name: ap-northeast-1
# Default output format: json
# 確認
aws sts get-caller-identity
3.2 必要なIAM権限
最低限必要な権限:
-
AmazonEC2ContainerRegistryFullAccess- ECR操作 -
AmazonECS_FullAccess- ECS操作 -
IAMReadOnlyAccess- ロール確認
推奨:管理者権限(学習目的の場合)
AdministratorAccess
3.3 リージョンの選択
推奨リージョン:
-
ap-northeast-1(東京)- 日本からのアクセスが最速
この資料ではap-northeast-1を使用します。
3.4 VPCとサブネットの確認
ECS Fargateを使用する際、VPCとサブネットが必要です。AWSアカウントにはデフォルトVPCが自動的に作成されています。
デフォルトVPCの確認
AWS CLI:
# デフォルトVPCのIDを取得
aws ec2 describe-vpcs \
--filters "Name=isDefault,Values=true" \
--region ap-northeast-1 \
--query 'Vpcs[0].VpcId' \
--output text
# 出力例: vpc-0a1b2c3d4e5f67890
マネジメントコンソール:
- VPC → Your VPCs
- 「Default VPC」列が「Yes」のVPCを確認
サブネットの確認
デフォルトVPCのサブネット一覧:
# VPC_IDを変数に設定(上記で取得したID)
VPC_ID=vpc-0a1b2c3d4e5f67890
# サブネット一覧を取得
aws ec2 describe-subnets \
--filters "Name=vpc-id,Values=${VPC_ID}" \
--region ap-northeast-1 \
--query 'Subnets[*].[SubnetId,AvailabilityZone,CidrBlock]' \
--output table
# 出力例:
# ----------------------------------------
# | DescribeSubnets |
# +----------------------+---------------+
# | subnet-0abc123def | ap-northeast-1a | 172.31.0.0/20 |
# | subnet-0def456ghi | ap-northeast-1c | 172.31.16.0/20 |
# | subnet-0ghi789jkl | ap-northeast-1d | 172.31.32.0/20 |
# +----------------------+---------------+
マネジメントコンソール:
- VPC → サブネット
- VPC IDでフィルター
メモすべき情報
以降の手順で使用するため、以下をメモしてください:
| 項目 | 例 | メモ欄 |
|---|---|---|
| VPC ID | vpc-0a1b2c3d4e5f67890 |
__________ |
| サブネット1 | subnet-0abc123def |
__________ |
| サブネット2 | subnet-0def456ghi |
__________ |
| サブネット3 | subnet-0ghi789jkl |
__________ |
注意:
- ECS Fargateは最低1つのサブネットが必要
- ALBを使用する場合は、異なるAZ(アベイラビリティゾーン)の2つ以上のサブネットが必要
3.5 セキュリティグループの作成
セキュリティグループは、ファイアウォールのようにトラフィックを制御します。
ECSタスク用セキュリティグループの作成
AWS CLI:
# セキュリティグループ作成
aws ec2 create-security-group \
--group-name ecs-tasks-sg \
--description "Security group for ECS Fargate tasks" \
--vpc-id vpc-0a1b2c3d4e5f67890 \
--region ap-northeast-1
# 出力例:
# {
# "GroupId": "sg-0123456789abcdef0"
# }
# セキュリティグループIDをメモ
SG_ECS=sg-0123456789abcdef0
マネジメントコンソール:
- EC2 → セキュリティグループ → 「セキュリティグループを作成」
- 設定:
-
セキュリティグループ名:
ecs-tasks-sg -
説明:
Security group for ECS Fargate tasks - VPC: デフォルトVPC
-
セキュリティグループ名:
- 「セキュリティグループを作成」をクリック
インバウンドルールの設定(後で設定)
現時点ではインバウンドルールは不要です。以下のタイミングで設定します:
- ALB使用時: ALBからのトラフィックを許可(第8章)
- デバッグ時: 自分のIPからのアクセスを一時的に許可
アウトバウンドルール
デフォルトで全開放(0.0.0.0/0)されているため、変更不要です。
メモすべき情報
| 項目 | 例 | メモ欄 |
|---|---|---|
| ECS用セキュリティグループID | sg-0123456789abcdef0 |
__________ |
3.6 以降の手順でのプレースホルダー
この資料では説明の便宜上、以下のプレースホルダーを使用します:
| プレースホルダー | 説明 | 例 |
|---|---|---|
123456789012 |
AWSアカウントID(12桁) | 123456789012 |
vpc-xxxxx |
VPC ID | vpc-0a1b2c3d4e5f67890 |
subnet-xxxxx |
サブネットID | subnet-0abc123def |
sg-xxxxx |
セキュリティグループID | sg-0123456789abcdef0 |
実際に実行する際は、上記でメモした実際の値に置き換えてください。
4. ECR の基本操作
4.1 ECRリポジトリの作成
方法1:マネジメントコンソール
- AWSコンソール → ECR → 「リポジトリを作成」
- 設定:
-
リポジトリ名:
myapp - タグのイミュータビリティ: 無効(学習用)
- スキャン設定: プッシュ時にスキャン(推奨)
-
リポジトリ名:
- 「リポジトリを作成」をクリック
方法2:AWS CLI
# リポジトリ作成
aws ecr create-repository \
--repository-name myapp \
--region ap-northeast-1
# 出力例:
# {
# "repository": {
# "repositoryArn": "arn:aws:ecr:ap-northeast-1:123456789012:repository/myapp",
# "registryId": "123456789012",
# "repositoryName": "myapp",
# "repositoryUri": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp"
# }
# }
重要: repositoryUriをメモしておく
4.2 ECRへの認証
Docker CLIでECRにログイン:
# 認証トークンを取得してログイン
aws ecr get-login-password --region ap-northeast-1 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
# 成功すると:
# Login Succeeded
PowerShellの場合:
(aws ecr get-login-password --region ap-northeast-1) | `
docker login --username AWS --password-stdin `
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
認証の有効期限:
- 12時間(再ログインが必要)
4.3 イメージのプッシュ
ステップ1:ローカルでイメージをビルド
# Dockerfileがあるディレクトリで
docker build -t myapp:latest .
ステップ2:ECR用にタグ付け
# ECRのリポジトリURIを使用
docker tag myapp:latest \
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest
# バージョンタグも推奨
docker tag myapp:latest \
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:1.0.0
ステップ3:ECRにプッシュ
# プッシュ
docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest
docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:1.0.0
# 進行状況が表示される
# latest: digest: sha256:abc123... size: 2345
4.4 イメージの確認
方法1:マネジメントコンソール
- ECR → リポジトリ → myapp → イメージ一覧
方法2:AWS CLI
# イメージ一覧を取得
aws ecr list-images \
--repository-name myapp \
--region ap-northeast-1
# 詳細情報
aws ecr describe-images \
--repository-name myapp \
--region ap-northeast-1
4.5 ECR操作のまとめ
よく使うコマンド:
# リポジトリ一覧
aws ecr describe-repositories --region ap-northeast-1
# ログイン
aws ecr get-login-password --region ap-northeast-1 | \
docker login --username AWS --password-stdin <ECR_URI>
# イメージ一覧
aws ecr list-images --repository-name myapp --region ap-northeast-1
# イメージ削除
aws ecr batch-delete-image \
--repository-name myapp \
--image-ids imageTag=1.0.0 \
--region ap-northeast-1
# リポジトリ削除(中のイメージも削除される)
aws ecr delete-repository \
--repository-name myapp \
--force \
--region ap-northeast-1
5. ECS Fargate の基本
5.1 ECSの主要な概念
階層構造:
クラスタ(Cluster)
├─ サービス(Service)
│ ├─ タスク(Task)
│ │ └─ コンテナ
│ └─ タスク
└─ タスク定義(Task Definition)
各要素の説明:
| 要素 | 説明 | Dockerとの対応 |
|---|---|---|
| クラスタ | リソースの論理的なグループ | - |
| タスク定義 | コンテナの設定(JSON) | docker-compose.yml |
| タスク | 実行中のコンテナグループ | docker run の実行結果 |
| サービス | タスクを常時実行・管理 | docker-compose up -d |
5.2 クラスタの作成
マネジメントコンソール:
- ECS → クラスター → 「クラスターの作成」
- 設定:
-
クラスター名:
myapp-cluster - インフラストラクチャ: AWS Fargate(サーバーレス)
-
クラスター名:
- 「作成」をクリック
AWS CLI:
# クラスタ作成
aws ecs create-cluster \
--cluster-name myapp-cluster \
--region ap-northeast-1
# 確認
aws ecs describe-clusters \
--clusters myapp-cluster \
--region ap-northeast-1
5.3 タスク定義の作成
タスク定義 = docker-compose.ymlに相当
最小限のタスク定義(JSON):
task-definition.json
{
"family": "myapp-task",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "myapp",
"image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest",
"portMappings": [
{
"containerPort": 3000,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "NODE_ENV",
"value": "production"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/myapp",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
}
}
],
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole"
}
重要なパラメータ:
| パラメータ | 説明 | 選択肢 |
|---|---|---|
cpu |
CPUユニット | 256, 512, 1024, 2048, 4096 |
memory |
メモリ(MB) | 512, 1024, 2048, 4096, 8192 |
networkMode |
ネットワークモード |
awsvpc(Fargateは固定) |
essential |
コンテナが必須か | true/false |
CPU/メモリの組み合わせ:
| CPU | 使用可能なメモリ(MB) |
|---|---|
| 256 | 512, 1024, 2048 |
| 512 | 1024〜4096 |
| 1024 | 2048〜8192 |
タスク定義の登録:
# 事前にCloudWatch Logsグループを作成
aws logs create-log-group \
--log-group-name /ecs/myapp \
--region ap-northeast-1
# タスク定義を登録
aws ecs register-task-definition \
--cli-input-json file://task-definition.json \
--region ap-northeast-1
5.4 タスクの実行(単発)
テスト実行:
# 事前にVPCとサブネットを確認(第3.4参照)
# 以下のコマンドで実際の値を取得
VPC_ID=$(aws ec2 describe-vpcs --filters "Name=isDefault,Values=true" --region ap-northeast-1 --query 'Vpcs[0].VpcId' --output text)
SUBNET_ID=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=${VPC_ID}" --region ap-northeast-1 --query 'Subnets[0].SubnetId' --output text)
SG_ID=$(aws ec2 describe-security-groups --filters "Name=group-name,Values=ecs-tasks-sg" --region ap-northeast-1 --query 'SecurityGroups[0].GroupId' --output text)
# タスクを実行
aws ecs run-task \
--cluster myapp-cluster \
--task-definition myapp-task \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={
subnets=[${SUBNET_ID}],
securityGroups=[${SG_ID}],
assignPublicIp=ENABLED
}" \
--region ap-northeast-1
手動で値を指定する場合:
# 第3.4でメモした実際の値に置き換える
aws ecs run-task \
--cluster myapp-cluster \
--task-definition myapp-task \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-0abc123def],
securityGroups=[sg-0123456789abcdef0],
assignPublicIp=ENABLED
}" \
--region ap-northeast-1
重要な注意点:
-
subnets: 第3.4で確認したサブネットIDを指定 -
securityGroups: 第3.5で作成したセキュリティグループIDを指定 -
assignPublicIp=ENABLED: パブリックIPを割り当て(外部からアクセス可能に)
タスクの確認:
# タスク一覧
aws ecs list-tasks \
--cluster myapp-cluster \
--region ap-northeast-1
# タスクの詳細
aws ecs describe-tasks \
--cluster myapp-cluster \
--tasks <タスクARN> \
--region ap-northeast-1
5.5 サービスの作成(常時実行)
サービス = docker-compose up -d に相当
マネジメントコンソール:
- ECS → クラスター → myapp-cluster → 「サービスを作成」
- 設定:
- 起動タイプ: Fargate
- タスク定義: myapp-task
- サービス名: myapp-service
- タスク数: 1
-
ネットワーキング:
- VPC、サブネット、セキュリティグループを選択
- パブリックIPの自動割り当て: 有効
- 「作成」をクリック
AWS CLI:
# サービス作成
aws ecs create-service \
--cluster myapp-cluster \
--service-name myapp-service \
--task-definition myapp-task \
--desired-count 1 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-xxxxx],
securityGroups=[sg-xxxxx],
assignPublicIp=ENABLED
}" \
--region ap-northeast-1
サービスの確認:
# サービス一覧
aws ecs list-services \
--cluster myapp-cluster \
--region ap-northeast-1
# サービスの詳細
aws ecs describe-services \
--cluster myapp-cluster \
--services myapp-service \
--region ap-northeast-1
6. 実践:Docker Compose から ECS へ移行
Docker学習資料の第6章で作成した構成をECSに移行します。
6.1 移行する構成
元のdocker-compose.yml:
version: '3.8'
services:
api:
build: ./backend
ports:
- "3000:3000"
environment:
NODE_ENV: production
DATABASE_URL: postgresql://postgres:dbpass@db:5432/myapp
depends_on:
- db
db:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: dbpass
POSTGRES_DB: myapp
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
ECSでの構成:
- API: ECS Fargateで実行
- DB: RDS PostgreSQLに移行(後述)
6.2 ステップ1:イメージの準備
# 1. APIのイメージをビルド
cd backend
docker build -t myapp-api:latest .
# 2. ECRリポジトリを作成
aws ecr create-repository \
--repository-name myapp-api \
--region ap-northeast-1
# 3. ECRにログイン
aws ecr get-login-password --region ap-northeast-1 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
# 4. タグ付け
docker tag myapp-api:latest \
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp-api:latest
# 5. プッシュ
docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp-api:latest
6.3 ステップ2:タスク定義の作成
変換のポイント:
| docker-compose.yml | ECSタスク定義 |
|---|---|
ports: "3000:3000" |
portMappings: [{containerPort: 3000}] |
environment: |
environment: または secrets:
|
depends_on: |
削除(RDSは常時起動) |
ECSタスク定義:
myapp-task-definition.json
{
"family": "myapp-api-task",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"containerDefinitions": [
{
"name": "api",
"image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/myapp-api:latest",
"portMappings": [
{
"containerPort": 3000,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "NODE_ENV",
"value": "production"
},
{
"name": "PORT",
"value": "3000"
}
],
"secrets": [
{
"name": "DATABASE_URL",
"valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:myapp/db-url"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/myapp-api",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "api"
}
}
}
],
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole"
}
注意: DATABASE_URLは後でSecrets Managerに保存します
6.4 ステップ3:IAMロールの作成
必要なロール:
- ecsTaskExecutionRole - タスク実行用(ECRからpull、ログ出力)
- ecsTaskRole - タスク内からAWSサービスにアクセス(任意)
ecsTaskExecutionRole の作成:
# 信頼ポリシー(trust-policy.json)
cat > trust-policy.json << 'TRUST'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
TRUST
# ロール作成
aws iam create-role \
--role-name ecsTaskExecutionRole \
--assume-role-policy-document file://trust-policy.json
# 管理ポリシーをアタッチ
aws iam attach-role-policy \
--role-name ecsTaskExecutionRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
# Secrets Managerアクセス権限を追加
cat > secrets-policy.json << 'SECRETS'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:myapp/*"
}
]
}
SECRETS
aws iam put-role-policy \
--role-name ecsTaskExecutionRole \
--policy-name SecretsManagerAccess \
--policy-document file://secrets-policy.json
6.5 docker-compose と ECS の対応まとめ
| 機能 | docker-compose | ECS |
|---|---|---|
| 起動 | docker-compose up -d |
ECSサービス作成 |
| 停止 | docker-compose down |
サービス削除 |
| ログ確認 | docker-compose logs -f |
CloudWatch Logs |
| スケール | --scale api=3 |
サービスのタスク数変更 |
| 環境変数 | environment: |
environment: or secrets:
|
| 再起動 | docker-compose restart |
タスク強制停止→自動再起動 |
7. RDS との連携
Docker ComposeのPostgreSQLコンテナをRDSに置き換えます。
7.1 RDSインスタンスの作成
マネジメントコンソール:
- RDS → データベース → 「データベースの作成」
- 設定:
- エンジン: PostgreSQL 15
- テンプレート: 開発/テスト(Free tierも可)
-
DBインスタンス識別子:
myapp-db -
マスターユーザー名:
postgres - マスターパスワード: (強力なパスワードを設定)
- インスタンスクラス: db.t3.micro(Free tier)
- ストレージ: 20GB(Free tier)
- VPC: ECSと同じVPC
- パブリックアクセス: なし(セキュリティのため)
- VPCセキュリティグループ: 新規作成
-
初期データベース名:
myapp
- 「データベースの作成」をクリック
作成には5〜10分かかります。
7.2 セキュリティグループの設定
RDSへのアクセスを許可:
- EC2 → セキュリティグループ → RDSのセキュリティグループ
- インバウンドルール編集:
- タイプ: PostgreSQL
- ポート: 5432
- ソース: ECSタスクのセキュリティグループ
- 保存
セキュリティグループの関係:
ECS タスク(sg-ecs)
↓ PostgreSQL (5432)
RDS(sg-rds)
インバウンド: sg-ecs からの 5432 を許可
7.3 接続情報の取得
エンドポイントの確認:
- RDS → データベース → myapp-db
- 「接続とセキュリティ」タブ
-
エンドポイントをコピー
- 例:
myapp-db.abc123.ap-northeast-1.rds.amazonaws.com
- 例:
接続URL形式:
postgresql://ユーザー名:パスワード@エンドポイント:5432/データベース名
例:
postgresql://postgres:MySecurePassword123@myapp-db.abc123.ap-northeast-1.rds.amazonaws.com:5432/myapp
7.4 Secrets Manager に保存
機密情報(パスワード等)はSecrets Managerで管理:
# シークレット作成
aws secretsmanager create-secret \
--name myapp/db-url \
--description "Database URL for myapp" \
--secret-string "postgresql://postgres:MySecurePassword123@myapp-db.abc123.ap-northeast-1.rds.amazonaws.com:5432/myapp" \
--region ap-northeast-1
# 出力例:
# {
# "ARN": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:myapp/db-url-AbCdEf",
# "Name": "myapp/db-url",
# "VersionId": "xxx-xxx-xxx"
# }
ARNをメモしておく(タスク定義で使用)
7.5 タスク定義での使用
タスク定義のsecrets部分:
{
"secrets": [
{
"name": "DATABASE_URL",
"valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:myapp/db-url-AbCdEf"
}
]
}
コンテナ内での参照:
// Node.jsの例
const databaseUrl = process.env.DATABASE_URL;
const pool = new Pool({
connectionString: databaseUrl
});
7.6 接続テスト
ECSタスクを起動して接続確認:
# タスク定義を登録(Secrets Manager設定済み)
aws ecs register-task-definition \
--cli-input-json file://myapp-task-definition.json \
--region ap-northeast-1
# タスクを実行
aws ecs run-task \
--cluster myapp-cluster \
--task-definition myapp-api-task \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-xxxxx],
securityGroups=[sg-ecs],
assignPublicIp=ENABLED
}" \
--region ap-northeast-1
# ログを確認(CloudWatch Logs)
aws logs tail /ecs/myapp-api --follow --region ap-northeast-1
成功すれば:
Connected to database successfully
8. ALB の設定
Application Load Balancer(ALB)を使って、外部からのアクセスを受け付けます。
8.1 ALBの役割
docker-composeでのNginx ≒ ALB
| 機能 | Nginx | ALB |
|---|---|---|
| 負荷分散 | ○ | ○ |
| ヘルスチェック | ○ | ○ |
| SSL/TLS | ○ | ○ |
| パスルーティング | ○ | ○ |
| 管理 | 自分で設定 | AWSが管理 |
8.2 ターゲットグループの作成
ターゲットグループ = 転送先のコンテナ群
- EC2 → ターゲットグループ → 「ターゲットグループの作成」
- 設定:
- ターゲットタイプ: IP(Fargate用)
-
ターゲットグループ名:
myapp-tg - プロトコル: HTTP
- ポート: 3000
- VPC: ECSと同じVPC
-
ヘルスチェックパス:
/health(アプリに実装必要)
- 「次へ」→「作成」
ヘルスチェックの設定:
- 正常のしきい値: 2
- 非正常のしきい値: 2
- タイムアウト: 5秒
- 間隔: 30秒
8.3 ALBの作成
- EC2 → ロードバランサー → 「ロードバランサーの作成」
- Application Load Balancerを選択
- 設定:
-
ロードバランサー名:
myapp-alb - スキーム: インターネット向け
- IP アドレスタイプ: IPv4
- VPC: ECSと同じVPC
- サブネット: 異なるAZから2つ以上選択
-
セキュリティグループ:
- HTTP (80) を 0.0.0.0/0 から許可
-
リスナーとルーティング:
- プロトコル: HTTP
- ポート: 80
- デフォルトアクション: myapp-tg に転送
-
ロードバランサー名:
- 「ロードバランサーの作成」をクリック
ALBのDNS名をメモ:
- 例:
myapp-alb-123456789.ap-northeast-1.elb.amazonaws.com
8.4 ECSサービスとALBの統合
サービス作成時にALBを設定:
- ECS → クラスター → myapp-cluster → 「サービスを作成」
- 設定:
- タスク定義: myapp-api-task
- サービス名: myapp-api-service
- タスク数: 2(冗長化)
-
ロードバランサー: Application Load Balancer
- 既存のALBを使用: myapp-alb
- ターゲットグループ: myapp-tg
- コンテナ: api:3000
- 「作成」をクリック
AWS CLI:
aws ecs create-service \
--cluster myapp-cluster \
--service-name myapp-api-service \
--task-definition myapp-api-task \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={
subnets=[subnet-xxxxx,subnet-yyyyy],
securityGroups=[sg-ecs],
assignPublicIp=DISABLED
}" \
--load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:...,containerName=api,containerPort=3000" \
--region ap-northeast-1
8.5 動作確認
ブラウザでアクセス:
http://myapp-alb-123456789.ap-northeast-1.elb.amazonaws.com
ヘルスチェックの確認:
- EC2 → ターゲットグループ → myapp-tg → ターゲット
- ステータスが「healthy」になればOK
構成図:
インターネット
↓ HTTP (80)
[ ALB ]
↓ HTTP (3000)
[ ECS タスク × 2 ]
↓ PostgreSQL (5432)
[ RDS ]
9. ログとモニタリング
9.1 CloudWatch Logs
ログの確認方法:
マネジメントコンソール:
- CloudWatch → ロググループ →
/ecs/myapp-api - 最新のログストリームをクリック
AWS CLI:
# ログをリアルタイムで表示(tail -f のように)
aws logs tail /ecs/myapp-api --follow --region ap-northeast-1
# 最新100行を表示
aws logs tail /ecs/myapp-api --since 10m --region ap-northeast-1
# 特定の文字列でフィルタ
aws logs tail /ecs/myapp-api --filter-pattern "ERROR" --region ap-northeast-1
docker logsとの対応:
| docker logs | CloudWatch Logs |
|---|---|
docker logs -f api |
aws logs tail /ecs/myapp-api --follow |
docker logs --tail 100 api |
aws logs tail ... --since 10m |
docker logs api | grep ERROR |
aws logs tail ... --filter-pattern "ERROR" |
9.2 メトリクスの確認
ECSのメトリクス:
- ECS → クラスター → myapp-cluster → メトリクス
- 確認できる項目:
- CPUUtilization(CPU使用率)
- MemoryUtilization(メモリ使用率)
- タスク数
アラームの設定:
# CPU使用率が80%を超えたらアラーム
aws cloudwatch put-metric-alarm \
--alarm-name myapp-high-cpu \
--alarm-description "Alert when CPU > 80%" \
--metric-name CPUUtilization \
--namespace AWS/ECS \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2 \
--dimensions Name=ServiceName,Value=myapp-api-service Name=ClusterName,Value=myapp-cluster \
--region ap-northeast-1
9.3 X-Rayによる分散トレーシング(任意)
アプリケーションの処理時間を可視化:
- タスク定義にX-Rayデーモンコンテナを追加
- アプリケーションコードにX-Ray SDKを組み込む
詳細は省略(高度なトピック)
10. コスト概算
注意: この料金は2024年1月時点の情報です。料金は変動する可能性があるため、最新の料金は AWS料金ページ でご確認ください。
10.1 主要サービスの料金
ECS Fargate(東京リージョン):
| リソース | 料金 |
|---|---|
| vCPU | $0.04656 / vCPU / 時間 |
| メモリ | $0.00511 / GB / 時間 |
例:0.25 vCPU、0.5 GB で24時間稼働
vCPU: 0.25 × $0.04656 × 24時間 × 30日 = $8.38
メモリ: 0.5 × $0.00511 × 24時間 × 30日 = $1.84
合計: 約 $10.22 / 月(約1,530円)
RDS(db.t3.micro、PostgreSQL):
インスタンス: $0.018 / 時間 × 24 × 30 = $12.96
ストレージ: 20GB × $0.138 = $2.76
合計: 約 $15.72 / 月(約2,360円)
ALB:
時間料金: $0.0243 / 時間 × 24 × 30 = $17.50
LCU(処理量): 変動(最小約$5)
合計: 約 $22.50 / 月(約3,375円)
ECR:
ストレージ: 1GB まで無料、以降 $0.10 / GB / 月
転送: 1GB まで無料、以降変動
CloudWatch Logs:
取り込み: $0.76 / GB
保存: $0.033 / GB / 月
10.2 月間コスト概算
小規模構成(タスク1個):
| サービス | 月額 |
|---|---|
| ECS Fargate | $10 |
| RDS (db.t3.micro) | $16 |
| ALB | $23 |
| ECR | $1 |
| CloudWatch Logs | $2 |
| 合計 | 約 $52(約7,800円) |
中規模構成(タスク3個):
| サービス | 月額 |
|---|---|
| ECS Fargate | $30 |
| RDS (db.t4g.small) | $35 |
| ALB | $25 |
| ECR | $2 |
| CloudWatch Logs | $5 |
| 合計 | 約 $97(約14,550円) |
10.3 コスト最適化のヒント
1. Savings Plans / Reserved Instances
- 1年契約で最大40%割引
2. スポットインスタンス(EC2起動タイプの場合)
- 最大70%割引
3. 不要なリソースの削除
# 使っていないタスク定義の削除
aws ecs deregister-task-definition \
--task-definition myapp-task:1 \
--region ap-northeast-1
# 古いECRイメージの削除(ライフサイクルポリシー)
4. オートスケーリング
- 夜間はタスク数を減らす
5. CloudWatch Logsの保持期間設定
# 7日後に自動削除
aws logs put-retention-policy \
--log-group-name /ecs/myapp-api \
--retention-in-days 7 \
--region ap-northeast-1
11. トラブルシューティング
11.1 よくあるエラーと対処法
エラー1:タスクが起動しない
症状:
STOPPED (CannotPullContainerError)
原因:
- ECRへのアクセス権限がない
- イメージが存在しない
- タグが間違っている
対処法:
# 1. イメージが存在するか確認
aws ecr describe-images \
--repository-name myapp-api \
--region ap-northeast-1
# 2. タスク実行ロールの権限確認
aws iam get-role --role-name ecsTaskExecutionRole
# 3. タスクのログを確認
aws ecs describe-tasks \
--cluster myapp-cluster \
--tasks <タスクARN> \
--region ap-northeast-1
エラー2:RDSに接続できない
症状:
Error: connect ETIMEDOUT
原因:
- セキュリティグループの設定ミス
- 接続文字列が間違っている
- RDSが起動していない
対処法:
# 1. セキュリティグループ確認
# ECSタスクのSG → RDSのSGへ 5432 が許可されているか
# 2. 接続文字列の確認
aws secretsmanager get-secret-value \
--secret-id myapp/db-url \
--region ap-northeast-1
# 3. RDS起動状態確認
aws rds describe-db-instances \
--db-instance-identifier myapp-db \
--region ap-northeast-1 \
--query 'DBInstances[0].DBInstanceStatus'
エラー3:ALBのヘルスチェックが失敗
症状:
Target health check failed
原因:
- ヘルスチェックパス(/health)が実装されていない
- コンテナポートが間違っている
- セキュリティグループでALB→ECSが許可されていない
対処法:
// Node.jsでヘルスチェックエンドポイントを実装
app.get('/health', (req, res) => {
res.status(200).json({ status: 'healthy' });
});
# セキュリティグループ確認
# ALBのSG → ECSタスクのSGへ 3000 が許可されているか
エラー4:環境変数が読み込まれない
症状:
DATABASE_URL is undefined
原因:
- Secrets Managerのアクセス権限がない
- ARNが間違っている
対処法:
# 1. Secrets Managerのアクセス権限確認
aws iam get-role-policy \
--role-name ecsTaskExecutionRole \
--policy-name SecretsManagerAccess
# 2. シークレットのARN確認
aws secretsmanager describe-secret \
--secret-id myapp/db-url \
--region ap-northeast-1
11.2 デバッグコマンド集
# タスクの詳細情報(エラー原因を確認)
aws ecs describe-tasks \
--cluster myapp-cluster \
--tasks <タスクARN> \
--region ap-northeast-1
# 最新のタスクARNを取得
TASK_ARN=$(aws ecs list-tasks \
--cluster myapp-cluster \
--service-name myapp-api-service \
--region ap-northeast-1 \
--query 'taskArns[0]' \
--output text)
# タスクのログを表示
aws logs tail /ecs/myapp-api --follow --region ap-northeast-1
# サービスのイベント履歴
aws ecs describe-services \
--cluster myapp-cluster \
--services myapp-api-service \
--region ap-northeast-1 \
--query 'services[0].events[0:10]'
# ターゲットグループのヘルス状態
aws elbv2 describe-target-health \
--target-group-arn <ターゲットグループARN> \
--region ap-northeast-1
11.3 docker-compose との動作の違い
| 項目 | docker-compose | ECS |
|---|---|---|
| 起動時間 | 数秒 | 1〜2分(コールドスタート) |
| ログ確認 | リアルタイム | 数秒の遅延あり |
| デバッグ |
docker exec で直接接続 |
セッションマネージャー経由 |
| 再起動 | 即座 | タスク再作成(1〜2分) |
| ネットワーク | 自動的に疎通 | セキュリティグループ設定必須 |
12. まとめと次のステップ
12.1 学習の振り返り
習得した内容:
✅ ECRの基本操作
- リポジトリ作成
- イメージのpush/pull
- 認証方法
✅ ECS Fargateの基本
- クラスタ、タスク定義、サービスの概念
- docker-compose.yml → タスク定義の変換
- タスクの起動・管理
✅ RDS連携
- PostgreSQLコンテナ → RDSへの移行
- Secrets Managerでの機密情報管理
- セキュリティグループ設定
✅ ALBの設定
- ロードバランサーの作成
- ターゲットグループの設定
- ヘルスチェック
✅ 運用の基礎
- CloudWatch Logsでのログ確認
- コスト概算
- トラブルシューティング
12.2 Docker vs ECS 比較まとめ
| 項目 | Docker(ローカル) | ECS/Fargate |
|---|---|---|
| 起動 | docker-compose up |
サービス作成 |
| スケール | 手動 | Auto Scaling |
| 可用性 | 単一ホスト | マルチAZ |
| ログ | 標準出力 | CloudWatch Logs |
| コスト | サーバー代のみ | 従量課金 |
| 管理 | 自分で | AWSが管理 |
12.3 次のステップ
レベル1:基礎の定着
- 本資料の内容を実際に手を動かして試す
- 自分のアプリケーションをECSにデプロイ
- CloudWatch Logsを日常的に使う
レベル2:実践的な機能
- Auto Scaling(CPU使用率に応じた自動スケール)
- Blue/Greenデプロイ(ダウンタイムなしのデプロイ)
- CI/CD(GitHub Actions + ECR + ECS)
- カスタムドメイン設定(Route 53 + ACM)
レベル3:本番運用
- マルチAZ構成
- セキュリティ強化(WAF、GuardDuty)
- コスト最適化(Savings Plans、Spot)
- 監視・アラート体制の構築
レベル4:高度なトピック
- ECS on EC2(より細かい制御)
- ECS Exec(実行中のコンテナにアクセス)
- App Mesh(サービスメッシュ)
- EKS(Kubernetes)への移行検討
12.4 推奨リソース
公式ドキュメント:
ハンズオン:
コミュニティ:
12.5 実践課題
課題1:シンプルなAPI
- Express.jsで簡単なAPIを作成
- ECRにpush
- ECS Fargateで起動
- ALB経由でアクセス確認
課題2:データベース連携
- RDS PostgreSQLを作成
- APIからRDSに接続
- CRUDができることを確認
課題3:本番レベルの構成
- Auto Scalingを設定
- CloudWatch Alarmを設定
- 独自ドメインでHTTPS化
- CI/CDパイプラインを構築
おわりに
Docker学習資料で学んだ知識が、ECS/ECRでそのまま活用できることが理解できたでしょうか。
重要なポイント:
- Dockerfileはそのまま使える
- docker-compose.ymlの概念がECSタスク定義に対応
- 基本的な考え方は同じ、管理方法が変わるだけ
実際に手を動かして試すことで、より深く理解できます。
まずは小さく始めて、徐々に本番運用レベルに近づけていきましょう!
次のステップ: 実際にECSでアプリケーションをデプロイしてみましょう 🚀