0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【完全保存版】Docker学習者のための AWS ECS/ECR 実践入門

0
Posted at

この記事について

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時間

目次

  1. はじめに
  2. AWS ECS/ECRとは
  3. 環境準備
  4. ECRの基本操作
  5. ECS Fargateの基本
  6. 実践:Docker ComposeからECSへ移行
  7. RDSとの連携
  8. ALBの設定
  9. ログとモニタリング
  10. コスト概算
  11. トラブルシューティング
  12. まとめと次のステップ

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

マネジメントコンソール:

  1. VPC → Your VPCs
  2. 「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  |
# +----------------------+---------------+

マネジメントコンソール:

  1. VPC → サブネット
  2. 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

マネジメントコンソール:

  1. EC2 → セキュリティグループ → 「セキュリティグループを作成」
  2. 設定:
    • セキュリティグループ名: ecs-tasks-sg
    • 説明: Security group for ECS Fargate tasks
    • VPC: デフォルトVPC
  3. 「セキュリティグループを作成」をクリック

インバウンドルールの設定(後で設定)

現時点ではインバウンドルールは不要です。以下のタイミングで設定します:

  • 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:マネジメントコンソール

  1. AWSコンソール → ECR → 「リポジトリを作成」
  2. 設定:
    • リポジトリ名: myapp
    • タグのイミュータビリティ: 無効(学習用)
    • スキャン設定: プッシュ時にスキャン(推奨)
  3. 「リポジトリを作成」をクリック

方法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 クラスタの作成

マネジメントコンソール:

  1. ECS → クラスター → 「クラスターの作成」
  2. 設定:
    • クラスター名: myapp-cluster
    • インフラストラクチャ: AWS Fargate(サーバーレス)
  3. 「作成」をクリック

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 に相当

マネジメントコンソール:

  1. ECS → クラスター → myapp-cluster → 「サービスを作成」
  2. 設定:
    • 起動タイプ: Fargate
    • タスク定義: myapp-task
    • サービス名: myapp-service
    • タスク数: 1
    • ネットワーキング:
      • VPC、サブネット、セキュリティグループを選択
      • パブリックIPの自動割り当て: 有効
  3. 「作成」をクリック

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ロールの作成

必要なロール:

  1. ecsTaskExecutionRole - タスク実行用(ECRからpull、ログ出力)
  2. 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インスタンスの作成

マネジメントコンソール:

  1. RDS → データベース → 「データベースの作成」
  2. 設定:
    • エンジン: PostgreSQL 15
    • テンプレート: 開発/テスト(Free tierも可)
    • DBインスタンス識別子: myapp-db
    • マスターユーザー名: postgres
    • マスターパスワード: (強力なパスワードを設定)
    • インスタンスクラス: db.t3.micro(Free tier)
    • ストレージ: 20GB(Free tier)
    • VPC: ECSと同じVPC
    • パブリックアクセス: なし(セキュリティのため)
    • VPCセキュリティグループ: 新規作成
    • 初期データベース名: myapp
  3. 「データベースの作成」をクリック

作成には5〜10分かかります。

7.2 セキュリティグループの設定

RDSへのアクセスを許可:

  1. EC2 → セキュリティグループ → RDSのセキュリティグループ
  2. インバウンドルール編集:
    • タイプ: PostgreSQL
    • ポート: 5432
    • ソース: ECSタスクのセキュリティグループ
  3. 保存

セキュリティグループの関係:

ECS タスク(sg-ecs)
    ↓ PostgreSQL (5432)
RDS(sg-rds)
    インバウンド: sg-ecs からの 5432 を許可

7.3 接続情報の取得

エンドポイントの確認:

  1. RDS → データベース → myapp-db
  2. 「接続とセキュリティ」タブ
  3. エンドポイントをコピー
    • 例: 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 ターゲットグループの作成

ターゲットグループ = 転送先のコンテナ群

  1. EC2 → ターゲットグループ → 「ターゲットグループの作成」
  2. 設定:
    • ターゲットタイプ: IP(Fargate用)
    • ターゲットグループ名: myapp-tg
    • プロトコル: HTTP
    • ポート: 3000
    • VPC: ECSと同じVPC
    • ヘルスチェックパス: /health(アプリに実装必要)
  3. 「次へ」→「作成」

ヘルスチェックの設定:

  • 正常のしきい値: 2
  • 非正常のしきい値: 2
  • タイムアウト: 5秒
  • 間隔: 30秒

8.3 ALBの作成

  1. EC2 → ロードバランサー → 「ロードバランサーの作成」
  2. Application Load Balancerを選択
  3. 設定:
    • ロードバランサー名: myapp-alb
    • スキーム: インターネット向け
    • IP アドレスタイプ: IPv4
    • VPC: ECSと同じVPC
    • サブネット: 異なるAZから2つ以上選択
    • セキュリティグループ:
      • HTTP (80) を 0.0.0.0/0 から許可
    • リスナーとルーティング:
      • プロトコル: HTTP
      • ポート: 80
      • デフォルトアクション: myapp-tg に転送
  4. 「ロードバランサーの作成」をクリック

ALBのDNS名をメモ:

  • 例: myapp-alb-123456789.ap-northeast-1.elb.amazonaws.com

8.4 ECSサービスとALBの統合

サービス作成時にALBを設定:

  1. ECS → クラスター → myapp-cluster → 「サービスを作成」
  2. 設定:
    • タスク定義: myapp-api-task
    • サービス名: myapp-api-service
    • タスク数: 2(冗長化)
    • ロードバランサー: Application Load Balancer
      • 既存のALBを使用: myapp-alb
      • ターゲットグループ: myapp-tg
      • コンテナ: api:3000
  3. 「作成」をクリック

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

ヘルスチェックの確認:

  1. EC2 → ターゲットグループ → myapp-tg → ターゲット
  2. ステータスが「healthy」になればOK

構成図:

インターネット
    ↓ HTTP (80)
[ ALB ]
    ↓ HTTP (3000)
[ ECS タスク × 2 ]
    ↓ PostgreSQL (5432)
[ RDS ]

9. ログとモニタリング

9.1 CloudWatch Logs

ログの確認方法:

マネジメントコンソール:

  1. CloudWatch → ロググループ → /ecs/myapp-api
  2. 最新のログストリームをクリック

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のメトリクス:

  1. ECS → クラスター → myapp-cluster → メトリクス
  2. 確認できる項目:
    • 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による分散トレーシング(任意)

アプリケーションの処理時間を可視化:

  1. タスク定義にX-Rayデーモンコンテナを追加
  2. アプリケーションコードに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

  1. Express.jsで簡単なAPIを作成
  2. ECRにpush
  3. ECS Fargateで起動
  4. ALB経由でアクセス確認

課題2:データベース連携

  1. RDS PostgreSQLを作成
  2. APIからRDSに接続
  3. CRUDができることを確認

課題3:本番レベルの構成

  1. Auto Scalingを設定
  2. CloudWatch Alarmを設定
  3. 独自ドメインでHTTPS化
  4. CI/CDパイプラインを構築

おわりに

Docker学習資料で学んだ知識が、ECS/ECRでそのまま活用できることが理解できたでしょうか。

重要なポイント:

  • Dockerfileはそのまま使える
  • docker-compose.ymlの概念がECSタスク定義に対応
  • 基本的な考え方は同じ、管理方法が変わるだけ

実際に手を動かして試すことで、より深く理解できます。

まずは小さく始めて、徐々に本番運用レベルに近づけていきましょう!


次のステップ: 実際にECSでアプリケーションをデプロイしてみましょう 🚀

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?