コンテンツにスキップ

Code兄弟@AWSリソース

はじめに

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


01. Code兄弟サービス

Code兄弟サービス

▼ CodePipeline

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

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

code-pipeline

▼ CodeCommit

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

▼ CodeBuild

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

▼ CodeDeploy

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


02. CodeBuild

buildspec.yml ファイル

▼ Amazon ECSの場合

Amazon ECSのために、CodeBuildの設定する。

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

*実装例*

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

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

version: 0.2

phases:
  install:
    runtime-versions:
      docker: 18
  preBuild:
    commands:
      # Amazon 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
      # Amazon 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:
      # Amazon ECRにコンテナイメージをプッシュする。
      # コミットハッシュ値のタグの前に、latestタグのコンテナイメージをプッシュしておく。
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      # Amazon 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 (Amazon EC2の場合)

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

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


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


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


04-02. CodeDeploy (AWS Lambdaの場合)

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

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


04-03. CodeDeploy (Amazon ECSの場合)

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

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


ローリングアップデート

imagedefinitions.json ファイル

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

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

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


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

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

blue-green-deployment

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

(1)

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

(2)

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

(3)

サービスを更新。

(4)

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

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

(5)

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

(6)

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

(7)

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

(8)

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

appspec.yml ファイル

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

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

version: 0.0

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

imageDetail.json ファイル

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

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

taskdef.json ファイル

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

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

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

{
  "family": "<Amazon ECSタスク定義名>",
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "taskRoleArn": "<タスクロールのARN>",
  "executionRoleArn": "<タスク実行ロールのARN>",
  "cpu": "512",
  "memory": "1024",
  "containerDefinitions":
    [
      {
        "name": "<コンテナ名>",
        "image": "<IMAGE1_NAME>",
        "essential": "true",
        "portMappings": [
            {
              # コンテナポート
              "containerPort": 80,
              # Amazon 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のデプロイの途中、ターゲットグループからインスタンスを切り離すことにより、リクエストのインスタンスへのルーティングを遮断する。

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

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