コンテンツにスキップ

Code兄弟@AWSリソース

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. Code兄弟サービス

Code兄弟サービス

▼ CodePipeline

CodeCommit、CodeBuild、CodeDeploy、を連携させてAWSに対するCI/CDパイプラインを作成する。

CodeCommitは、他のコード管理サービスで代用できる。

code-pipeline

▼ CodeCommit

コードをバージョン管理する。

▼ CodeBuild

ビルドフェーズとテストフェーズを実行する。

▼ CodeDeploy

デプロイフェーズを実行する。


02. CodeBuild

buildspec.ymlファイル

▼ ECSの場合

ECSのために、CodeBuildの設定を実行する。

ルートディレクトリの直下に配置しておく。

*実装例*

コンテナをビルドする場合を示す。

コミットのハッシュ値でコンテナイメージをプッシュしたい場合、CodeBuildの設計上、latestタグもプッシュしておいた方が良い。

version: 0.2

phases:
  install:
    runtime-versions:
      docker: 18
  preBuild:
    commands:
      # ECRにログイン
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com
      # ECRのURLをCodeBuildの環境変数から作成
      - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_REPO_NAME}
      # バージョンタグはコミットのハッシュ値を使用
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      # ハッシュ値だけでなく、プレフィクスに日付をつけてもよい。
      - IMAGE_TAG=${COMMIT_HASH:=latest}
  build:
    commands:
      # タグ付けしてイメージをビルド
      - docker build -t $REPOSITORY_URI:latest .
      - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
  postBuild:
    commands:
      # ECRにコンテナイメージをプッシュする。
      # コミットハッシュ値のタグの前に、latestタグのコンテナイメージをプッシュしておく。
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      # ECRにあるデプロイ先のコンテナイメージの情報 (imageDetail.json)
      - printf '[{"name":"hello-world","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json

# デプロイ対象とするビルドのアーティファクト
artifacts:
  files: imageDetail.json


03. CodeDeploy (オンプレミスのサーバーの場合)

利用できるデプロイメント手法

インプレースデプロイメントを利用できる。


インプレースデプロイメント

▼ CodeDeployエージェント

オンプレミスサーバーにCodeDeployエージェントをインストールし、CodeDeployエージェントにサーバー情報を登録する必要がある。

CodeDeployとCodeDeployエージェントは通信し、CodeDeployエージェントがS3バケットからソースコードの圧縮ファイルをプルする。

code-deploy_agent


04. CodeDeploy (EC2の場合)

利用できるデプロイメント手法

インプレースデプロイ、ブルー/グリーンデプロイメント、を利用できる。


インプレースデプロイメント


ブルー/グリーンデプロイメント


04-02. CodeDeploy (Lambdaの場合)

利用できるデプロイメント手法

ブルー/グリーンデプロイメント、を利用できる。


04-03. CodeDeploy (ECSの場合)

利用できるデプロイメント手法

ローリングアップデート、ブルー/グリーンデプロイメント、を利用できる。


ローリングアップデート

imagedefinitions.jsonファイル

新しいリビジョン番号のECSタスク定義を作成するために、新しいコンテナ名とイメージリポジトリURLを定義する。

リポジトリに事前に配置するのではなく、CI/CDパイプライン上で動的に作成するようにした方が良い。

[
  {
    "imageUri": "<イメージリポジトリURL>", # <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/<イメージリポジトリ名>:latest
    "name": "<コンテナ名>",
  },
]


ブルー/グリーンデプロイメント

▼ ブルー/グリーンデプロイメントの仕組み

blue-green-deployment

以下の手順でデプロイする。

(1)

ECRのコンテナイメージを更新

(2)

ECSタスク定義の新しいリビジョンを作成。

(3)

サービスを更新。

(4)

CodeDeployによって、ECSタスク定義を基に、現環境 (Prodブルー) のECSタスクとは別に、新環境 (Testグリーン) が作成される。

ロードバランサーの接続先を、現環境 (Prodブルー) のターゲットグループ (Primaryターゲットグループ) に加えて、新環境 (Testグリーン) にも向ける。

(5)

社内から新環境 (Testグリーン) のALBに、特定のポート番号でアクセスし、動作を確認する。

(6)

動作確認で問題なければ、Console画面からの入力で、ロードバランサーの接続先を新環境 (Testグリーン) のみに設定する。

(7)

新環境 (Testグリーン) が新しい現環境としてユーザーに公開される。

(8)

元の現環境 (Prodブルー) は削除される。

appspec.ymlファイル

ルートディレクトリの直下に配置しておく。仕様として、複数のコンテナをデプロイできない。

ECSタスク定義名を<TASK_DEFINITION>とすると、taskdef.jsonファイルの値を元にして、新しいECSタスク定義が自動的に代入される。

version: 0.0

Resources:
  - TargetService:
      # 使用するAWSリソース
      Type: AWS::ECS::Service
      Properties:
        # 使用するECSタスク定義
        TaskDefinition: "<TASK_DEFINITION>"
        # 使用するロードバランサー
        LoadBalancerInfo:
          ContainerName: "<コンテナ名>"
          ContainerPort: "80"
        PlatformVersion: "1.4.0"

imageDetail.jsonファイル

新バージョンタグを含むイメージリポジトリURLを、taskdef.jsonファイルの <IMAGE1_NAME>に代入するために必要である。

これはリポジトリに事前に配置するのではなく、CI/CDパイプライン上で動的に作成するようにした方が良い。

taskdef.jsonファイル

デプロイされるECSタスク定義を実装し、ルートディレクトリの直下に配置する。

CodeDeployは、CodeBuildから渡されたimageDetail.jsonファイルを検知し、ECRからコンテナイメージを取得する。

この時、taskdef.jsonファイルのコンテナイメージ名を<IMAGE1_NAME>としておくと、imageDetail.jsonファイルの値を元にして、新バージョンタグを含むイメージリポジトリURLが自動的に代入される。

{
  "family": "<ECSタスク定義名>",
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "taskRoleArn": "<タスクロールのARN>",
  "executionRoleArn": "<タスク実行ロールのARN>",
  "cpu": "512",
  "memory": "1024",
  "containerDefinitions":
    [
      {
        "name": "<コンテナ名>",
        "image": "<IMAGE1_NAME>",
        "essential": "true",
        "portMappings": [
            {
              # コンテナポート
              "containerPort": 80,
              # ECSのホストのポート
              "hostPort": 80,
              "protocol": "tcp",
            },
          ],
        "secrets": [
            # データ永続化用のDBの接続情報
            {"name": "DB_HOST", "valueFrom": "/ecs/DB_HOST"},
            {"name": "DB_DATABASE", "valueFrom": "/ecs/DB_DATABASE"},
            {"name": "DB_PASSWORD", "valueFrom": "/ecs/DB_PASSWORD"},
            {"name": "DB_USERNAME", "valueFrom": "/ecs/DB_USERNAME"},
            # セッションキャッシュ用のインメモリDBの接続情報
            {"name": "REDIS_HOST", "valueFrom": "/ecs/REDIS_HOST"},
            {"name": "REDIS_PASSWORD", "valueFrom": "/ecs/REDIS_PASSWORD"},
            {"name": "REDIS_PORT", "valueFrom": "/ecs/REDIS_PORT"},
          ],
        "logConfiguration": {
            # ログドライバー
            "logDriver": "awslogs",
            "options": {
                "awslogs-group": "<ログストリーム名>",
                # スタックトレースのログを紐付けられるように、日付で区切るようにする。
                "awslogs-datetime-format": "\\[%Y-%m-%d %H:%M:%S\\]",
                "awslogs-region": "ap-northeast-1",
                "awslogs-stream-prefix": "<ログストリーム名の接頭辞>",
              },
          },
      },
    ],
}


04-04. CodeDeployと他のAWSリソースとの連携

AutoScaling


ALB、ELB、NLB

▼ インプレースデプロイメントの場合

CodeDeployのデプロイの途中、ターゲットグループからインスタンスを切り離すことにより、リクエストのインスタンスへのルーティングを遮断する。

そのため、デプロイ中にユーザーはアプリにリクエストできなくなる。

デプロイが正常に完了次第、ターゲットグループにインスタンスを再登録し、リクエストできる。