複数環境での運用

ecspressoは、開発環境、ステージング環境、本番環境など、複数の環境でECSサービスを管理するための機能を提供しています。このガイドでは、複数環境でecspressoを効果的に使用する方法を説明します。

目次

  1. 環境ごとの設定ファイル
  2. 環境変数ファイルの使用
  3. テンプレート変数
  4. Jsonnetによる設定管理
  5. 環境ごとのデプロイ戦略
  6. CI/CDパイプラインでの環境分離
  7. ベストプラクティス

環境ごとの設定ファイル

複数の環境を管理する最も簡単な方法は、環境ごとに別々の設定ファイルを用意することです。

.
├── ecspresso.dev.yml     # 開発環境用の設定ファイル
├── ecspresso.staging.yml # ステージング環境用の設定ファイル
├── ecspresso.prod.yml    # 本番環境用の設定ファイル
├── ecs-task-def.json     # 共通のタスク定義ファイル
└── ecs-service-def.json  # 共通のサービス定義ファイル

各環境用の設定ファイルの例:

# ecspresso.dev.yml
region: ap-northeast-1
cluster: dev-cluster
service: myservice
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
timeout: 10m
# ecspresso.prod.yml
region: ap-northeast-1
cluster: prod-cluster
service: myservice
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
timeout: 20m

環境ごとの設定ファイルを使用してデプロイする例:

# 開発環境にデプロイ
$ ecspresso deploy --config ecspresso.dev.yml

# ステージング環境にデプロイ
$ ecspresso deploy --config ecspresso.staging.yml

# 本番環境にデプロイ
$ ecspresso deploy --config ecspresso.prod.yml

環境変数ファイルの使用

--envfileオプションを使用して、環境ごとに異なる環境変数ファイルを指定できます。

.
├── ecspresso.yml         # 共通の設定ファイル
├── ecs-task-def.json     # 共通のタスク定義ファイル
├── ecs-service-def.json  # 共通のサービス定義ファイル
├── dev.env               # 開発環境用の環境変数ファイル
├── staging.env           # ステージング環境用の環境変数ファイル
└── prod.env              # 本番環境用の環境変数ファイル

環境変数ファイルの例:

# dev.env
CLUSTER=dev-cluster
DESIRED_COUNT=1
MIN_CAPACITY=1
MAX_CAPACITY=2
MEMORY=512
CPU=256
LOG_LEVEL=debug
# prod.env
CLUSTER=prod-cluster
DESIRED_COUNT=3
MIN_CAPACITY=2
MAX_CAPACITY=10
MEMORY=1024
CPU=512
LOG_LEVEL=info

環境変数ファイルを使用してデプロイする例:

# 開発環境にデプロイ
$ ecspresso deploy --config ecspresso.yml --envfile dev.env

# ステージング環境にデプロイ
$ ecspresso deploy --config ecspresso.yml --envfile staging.env

# 本番環境にデプロイ
$ ecspresso deploy --config ecspresso.yml --envfile prod.env

テンプレート変数

ecspressoは、タスク定義ファイルとサービス定義ファイル内でテンプレート変数を使用することをサポートしています。これにより、環境ごとに異なる値を設定できます。

タスク定義ファイルの例:

{
  "family": "myservice",
  "containerDefinitions": [
    {
      "name": "web",
      "image": "nginx:",
      "essential": true,
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80,
          "protocol": "tcp"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/myservice-",
          "awslogs-region": "",
          "awslogs-stream-prefix": "web"
        }
      },
      "environment": [
        {
          "name": "ENV",
          "value": ""
        },
        {
          "name": "LOG_LEVEL",
          "value": ""
        }
      ],
      "cpu": ,
      "memory": ,
      "memoryReservation": 
    }
  ],
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "networkMode": "awsvpc",
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "cpu": "",
  "memory": ""
}

サービス定義ファイルの例:

{
  "serviceName": "myservice",
  "desiredCount": ,
  "launchType": "FARGATE",
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "subnets": [
        "",
        ""
      ],
      "securityGroups": [
        ""
      ],
      "assignPublicIp": ""
    }
  },
  "deploymentConfiguration": {
    "deploymentCircuitBreaker": {
      "enable": ,
      "rollback": 
    }
  },
  "loadBalancers": [
    {
      "targetGroupArn": "",
      "containerName": "web",
      "containerPort": 80
    }
  ]
}

テンプレート変数を使用してデプロイする例:

# 環境変数を直接指定
$ export IMAGE_TAG=v1.2.3
$ export ENV=prod
$ export AWS_REGION=ap-northeast-1
$ export DESIRED_COUNT=3
$ ecspresso deploy --config ecspresso.yml

# --ext-strオプションを使用
$ ecspresso deploy --config ecspresso.yml --ext-str IMAGE_TAG=v1.2.3 --ext-str ENV=prod

Jsonnetによる設定管理

より複雑な設定管理には、Jsonnetを使用できます。Jsonnetは、JSONのスーパーセットであり、変数、条件分岐、関数などをサポートしています。

.
├── ecspresso.yml         # 共通の設定ファイル
├── ecs-task-def.jsonnet  # Jsonnet形式のタスク定義ファイル
├── ecs-service-def.jsonnet # Jsonnet形式のサービス定義ファイル
└── lib/
    ├── common.libsonnet  # 共通のライブラリ
    ├── dev.libsonnet     # 開発環境用の設定
    ├── staging.libsonnet # ステージング環境用の設定
    └── prod.libsonnet    # 本番環境用の設定

タスク定義ファイルの例(Jsonnet):

// ecs-task-def.jsonnet
local env = std.extVar('ENV');
local common = import 'lib/common.libsonnet';
local envConfig = import 'lib/' + env + '.libsonnet';

{
  family: "myservice",
  containerDefinitions: [
    {
      name: "web",
      image: "nginx:" + std.extVar('IMAGE_TAG'),
      essential: true,
      portMappings: [
        {
          containerPort: 80,
          hostPort: 80,
          protocol: "tcp"
        }
      ],
      logConfiguration: {
        logDriver: "awslogs",
        options: {
          "awslogs-group": "/ecs/myservice-" + env,
          "awslogs-region": envConfig.region,
          "awslogs-stream-prefix": "web"
        }
      },
      environment: common.environment(env) + [
        {
          name: "LOG_LEVEL",
          value: envConfig.logLevel
        }
      ],
      cpu: envConfig.container.cpu,
      memory: envConfig.container.memory,
      memoryReservation: envConfig.container.memoryReservation
    }
  ],
  executionRoleArn: common.roles.executionRole,
  networkMode: "awsvpc",
  requiresCompatibilities: [
    "FARGATE"
  ],
  cpu: envConfig.task.cpu,
  memory: envConfig.task.memory
}

共通ライブラリの例:

// lib/common.libsonnet
{
  environment(env): [
    {
      name: "ENV",
      value: env
    }
  ],
  roles: {
    executionRole: "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
    taskRole: "arn:aws:iam::123456789012:role/ecsTaskRole"
  }
}

環境設定の例:

// lib/dev.libsonnet
{
  region: "ap-northeast-1",
  logLevel: "debug",
  container: {
    cpu: 256,
    memory: 512,
    memoryReservation: 256
  },
  task: {
    cpu: "256",
    memory: "512"
  },
  desiredCount: 1,
  subnets: [
    "subnet-12345678",
    "subnet-87654321"
  ],
  securityGroups: [
    "sg-12345678"
  ],
  assignPublicIp: "ENABLED",
  circuitBreaker: {
    enable: false,
    rollback: false
  }
}
// lib/prod.libsonnet
{
  region: "ap-northeast-1",
  logLevel: "info",
  container: {
    cpu: 512,
    memory: 1024,
    memoryReservation: 512
  },
  task: {
    cpu: "512",
    memory: "1024"
  },
  desiredCount: 3,
  subnets: [
    "subnet-abcdefgh",
    "subnet-hgfedcba"
  ],
  securityGroups: [
    "sg-abcdefgh"
  ],
  assignPublicIp: "DISABLED",
  circuitBreaker: {
    enable: true,
    rollback: true
  }
}

Jsonnetを使用してデプロイする例:

# 開発環境にデプロイ
$ ecspresso deploy --config ecspresso.yml --ext-str ENV=dev --ext-str IMAGE_TAG=v1.2.3

# 本番環境にデプロイ
$ ecspresso deploy --config ecspresso.yml --ext-str ENV=prod --ext-str IMAGE_TAG=v1.2.3

環境ごとのデプロイ戦略

環境ごとに異なるデプロイ戦略を使用することができます。

開発環境

開発環境では、迅速なデプロイと頻繁な更新が重要です。

# 強制的に新しいデプロイメントを作成
$ ecspresso deploy --config ecspresso.dev.yml --force-new-deployment

ステージング環境

ステージング環境では、本番環境と同様のデプロイプロセスをテストします。

# Blue/Greenデプロイメントを使用
$ ecspresso deploy --config ecspresso.staging.yml

本番環境

本番環境では、安全なデプロイと自動ロールバックが重要です。

# ロールバックイベントを指定
$ ecspresso deploy --config ecspresso.prod.yml --rollback-events DEPLOYMENT_FAILURE

CI/CDパイプラインでの環境分離

CI/CDパイプラインで複数環境を管理する例を示します。

GitHub Actionsの例

name: Deploy to ECS

on:
  push:
    branches:
      - develop  # 開発環境へのデプロイ
      - staging  # ステージング環境へのデプロイ
      - main     # 本番環境へのデプロイ

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1
      
      - name: Setup ecspresso
        uses: kayac/ecspresso@v2
        with:
          version: v2.3.0
      
      - name: Set environment variables
        id: env
        run: |
          if [[ $GITHUB_REF == 'refs/heads/develop' ]]; then
            echo "::set-output name=env::dev"
            echo "::set-output name=config::ecspresso.dev.yml"
          elif [[ $GITHUB_REF == 'refs/heads/staging' ]]; then
            echo "::set-output name=env::staging"
            echo "::set-output name=config::ecspresso.staging.yml"
          elif [[ $GITHUB_REF == 'refs/heads/main' ]]; then
            echo "::set-output name=env::prod"
            echo "::set-output name=config::ecspresso.prod.yml"
          fi
      
      - name: Deploy to ECS
        env:
          IMAGE_TAG: ${{ github.sha }}
          ENV: ${{ steps.env.outputs.env }}
          CONFIG: ${{ steps.env.outputs.config }}
        run: |
          ecspresso deploy --config $CONFIG --ext-str IMAGE_TAG=$IMAGE_TAG --ext-str ENV=$ENV
          ecspresso wait --config $CONFIG --timeout 10m

ベストプラクティス

1. 環境ごとの設定を分離

環境ごとに異なる設定を明確に分離します。

.
├── config/
│   ├── dev/
│   │   ├── ecspresso.yml
│   │   ├── ecs-task-def.json
│   │   └── ecs-service-def.json
│   ├── staging/
│   │   ├── ecspresso.yml
│   │   ├── ecs-task-def.json
│   │   └── ecs-service-def.json
│   └── prod/
│       ├── ecspresso.yml
│       ├── ecs-task-def.json
│       └── ecs-service-def.json
└── scripts/
    ├── deploy-dev.sh
    ├── deploy-staging.sh
    └── deploy-prod.sh

2. 環境変数の管理

機密情報は環境変数として管理し、リポジトリにコミットしないようにします。

# .envファイルを使用
$ ecspresso deploy --config ecspresso.yml --envfile .env

3. デプロイスクリプトの作成

環境ごとのデプロイスクリプトを作成して、デプロイプロセスを簡素化します。

#!/bin/bash
# scripts/deploy-prod.sh
set -e

# 環境変数の読み込み
source .env.prod

# デプロイ前の差分確認
ecspresso diff --config config/prod/ecspresso.yml

# 確認プロンプト
read -p "本番環境にデプロイしますか? (y/n): " confirm
if [[ $confirm != "y" ]]; then
  echo "デプロイをキャンセルしました"
  exit 1
fi

# デプロイ実行
ecspresso deploy --config config/prod/ecspresso.yml --rollback-events DEPLOYMENT_FAILURE
ecspresso wait --config config/prod/ecspresso.yml --timeout 20m

4. 環境ごとのタスク定義の検証

デプロイ前に、環境ごとのタスク定義を検証します。

# 開発環境の検証
$ ecspresso verify --config ecspresso.dev.yml

# 本番環境の検証
$ ecspresso verify --config ecspresso.prod.yml

5. 環境ごとのリソース制限

環境ごとに適切なリソース制限を設定します。

// 開発環境のタスク定義
{
  "cpu": "256",
  "memory": "512"
}

// 本番環境のタスク定義
{
  "cpu": "1024",
  "memory": "2048"
}

6. 環境ごとのロギング設定

環境ごとに適切なロギング設定を行います。

// 開発環境のロギング設定
{
  "logConfiguration": {
    "logDriver": "awslogs",
    "options": {
      "awslogs-group": "/ecs/myservice-dev",
      "awslogs-region": "ap-northeast-1",
      "awslogs-stream-prefix": "web"
    }
  }
}

// 本番環境のロギング設定
{
  "logConfiguration": {
    "logDriver": "awslogs",
    "options": {
      "awslogs-group": "/ecs/myservice-prod",
      "awslogs-region": "ap-northeast-1",
      "awslogs-stream-prefix": "web"
    }
  }
}

7. 環境ごとのスケーリング設定

環境ごとに適切なスケーリング設定を行います。

// 開発環境のスケーリング設定
{
  "desiredCount": 1,
  "deploymentConfiguration": {
    "maximumPercent": 200,
    "minimumHealthyPercent": 100
  }
}

// 本番環境のスケーリング設定
{
  "desiredCount": 3,
  "deploymentConfiguration": {
    "maximumPercent": 150,
    "minimumHealthyPercent": 100
  }
}

関連コマンド

  • deploy - サービスをデプロイ
  • diff - ローカルの設定ファイルと現在のサービスとの差分を表示
  • verify - 設定ファイルの検証
  • render - 設定ファイルをレンダリングして標準出力に表示