TOP>コラム一覧>ECS_FargateのCICD実装方法

ECS_FargateのCICD実装方法

はじめに

こんにちは、佐藤です。
クラウドネイティブアーキテクチャが普及してくる中で、CI/CDという言葉を聞く機会が増えてきたのではないでしょうか。今回はCI/CDとは何かAWSのサービスを使ったサンプルを紹介しながら解説します。

CI/CDとは

CI/CDとは、「Continuous Integration/Continuous Delivery/ Continuous Deployment」の略であり、日本語では継続的インテグレーション/継続的デリバリー/継続的デプロイと呼ばれます。CI/CD は、アプリケーション開発の各ステージに自動化を導入し、アプリケーションリリースを柔軟に実施できるようにする手法です。

CI(Continuous Integration):継続的インテグレーション

継続的インテグレーションは、開発者が自分のコード変更を定期的にリポジトリにマージし、その後に自動化されたビルドとテストを実行するDevOpsソフトウェア開発の手法です。継続的インテグレーションの主な目的は、バグを早期に発見して対処すること、ソフトウェアの品質を高めること、そしてソフトウェアの更新を検証してリリースするためにかかる時間を短縮することです

※ 継続的インテグレーションとは:https://aws.amazon.com/jp/devops/continuous-integration/

CD(Continuous Delivery):継続的デリバリー

継続的デリバリーとは、コード変更を本番環境へのリリースに向けて自動的に準備するソフトウェア開発手法です。ビルド段階の後にすべてのコード変更をテスト環境や本番環境にデプロイします。継続的デリバリーによって、開発者は単体テスト以外のテストも自動化できるようになり、顧客にデプロイする前にアプリケーションの更新を複数の側面から検証できるようになります

※ 継続的デリバリーとは:https://aws.amazon.com/jp/devops/continuous-delivery/

CD(Continuous Deployment):継続的デプロイ

継続的デプロイは、アプリケーションへのコード変更が実稼働環境に自動的にリリースされるようにするソフトウェア開発手法です。 この自動化は事前に定義したテストに合格すると、更新を自動的に反映します。

パイプライン

パイプラインはCI/CDにおける一連のプロセス(ビルド、テスト、デプロイなど)の集まりです。パイプラインを実装することにより、CI/CDを実現します。各プロセスはAWSサービスに置き換えた図を以下に記載します。

サンプル構成

構成概要

今回はJavaアプリが稼働するコンテナのCI/CDを実装します。使用するAWSサービスは以下の通りです。

  • 実行環境(コンテナ):ECS/Fargate
  • ロードバランサ:Application Load Balancer(ALB)
  • WAF(IP制限用):AWS WAF
  • コンテナイメージ格納:ECR
  • パイプライン:CodePipeline
  • バージョン管理:CodeCommit
  • ビルド・テスト環境:CodeBuild
  • デプロイ:CodeDeploy

Note
VPC関連など、一般的なサービスは省略します

ECS/Fargateとは

Elastic Container Service(ECS)はコンテナ化されたアプリケーションのデプロイや拡張、管理などを容易にするAWSが提供するオーケストレーションサービスです。

FargateはAWSがマネージドサービスとして提供するコンテナの実行環境であり、ユーザによるコンテナ実行環境の管理が不要になるといったメリットがあります。今回はFargateを使用します。

※ ECSでは実行環境としてユーザが自身で用意する「EC2」と「Fargate」の2種類を使用できます

CodeCommitとは

CodeCommit は、プライベート Git リポジトリをホストする、安全で高度にスケーラブルなマネージド型のソース管理サービスです。CodeCommit を使用して、コードからバイナリまで何でも保存できます。Git の標準機能がサポートされているため、既存の Git ベースのツールをシームレスに使用できます

※ AWS CodeCommitとは:https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/welcome.html

CodeBuildとは

AWS CodeBuild はクラウドで動作する完全マネージド型のビルドサービスです。CodeBuild はソースコードをコンパイルし、単体テストを実行して、すぐにデプロイできるアーティファクトを生成します。ビルド環境をカスタマイズして、CodeBuild で独自のビルドツールを使用することもできます

CodeBuildで実行する処理はbuildspec.ymlに記載します。例を以下に記載します。以下の例はJavaアプリケーションのDockerコンテナを作成し、イメージをECRをPushしています。

  version: 0.2
  env:
      variables:
          IMAGE_REPO_NAME: "xxxxxxxxxx"
          AWS_ACCOUNT_ID: " xxxxxxxxxx "
      phases:
          pre_build:
              commands:
                  - echo $(java -version)
                  - chmod +x gradlew
                  - echo Logging in to Amazon ECR...
                  - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) -REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME
                  - echo $REPOSITORY_URI
                  - IMAGE_TAG=build-$(echo $CODEBUILD_BUILD_ID | awk -F":" '{print $2}')
          build:
              commands:
                  - echo Build started on `date`
                  - echo Building the SpringBoot project...
                  - ./gradlew build -x test
                  - echo Building the Docker image...
                  - docker build --progress=plain -t $REPOSITORY_URI:latest .
                  - echo docker $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
                  - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
          post_build:
              commands:
                  - echo Build completed on `date`
                  - echo Pushing the Docker image...
                  - docker push $REPOSITORY_URI:latest
                  - docker push $REPOSITORY_URI:$IMAGE_TAG
                  - echo Writing image definitions file...
                  - printf '{"ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
                  - cat imageDetail.json
                  - ls -l
          artifacts:
              files:
                  - imageDetail.json
                  - appspec.yml
                  - taskdef.json
    

※ AWS CodeBuildとは:https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/welcome.html

CodeDeployとは

CodeDeployは EC2 インスタンス、オンプレミスインスタンス、サーバーレス Lambda 関数、または Amazon ECS サービスに対するアプリケーションのデプロイを自動化するデプロイサービスです※1。CodeDeployを使用することによりダウンタイム無しで新バージョンのアプリデプロイを実行できます。今回はECSのBlue/Greenデプロイを実装します※2

CodeDeployで実行する処理は「appspec.yml」に記述します。以下の例ではデプロイ対象のコンテナ名やポート番号、Greenにトラフィックを切り替えた後に実行する処理を指定しています。

  version: 0.0
  Resources:
      - TargetService:
          Type: AWS::ECS::Service
          Properties:
              TaskDefinition: "<TASK_DEFINITION>"
              LoadBalancerInfo:
                  ContainerName: "test-app-container"
                  ContainerPort: "8080"
              PlatformVersion: "1.4.0“
  Hooks:
      - AfterAllowTestTraffic: "arn:aws:lambda:aws-region-id:aws-account-id:function:AfterAllowTestTraffic"
    

※1 CodeDeploy の概要:https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/welcome.html
※2 Blue/Greenデプロイとは現状の本番環境(Blue)とは別に新しい本番環境(Green)を構築した上で、ロードバランサーの接続先を切り替えるなどして新しい本番環境をダウンタイム無しでリリースする運用方法のこと

CodePipelineとは

AWS CodePipeline は、ソフトウェアをリリースするために必要なステップのモデル化、視覚化、および自動化に使用できる継続的な配信サービスです。ソフトウェアリリースプロセスのさまざまなステージをすばやくモデル化して設定できます。CodePipelineソフトウェアの変更を継続的にリリースするために必要なステップを自動化します

CodePipelineで各プロセスを実行するステージを設定し、パイプラインを作成します。以下にパイプラインの実装例を記載します。

※ AWS CodePipeline の概要:https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/welcome.html

デモ

Javaのフレームワークである「Spring Boot Web」を使用し、「Hello World」を表示するWebアプリケーションを作成します。CI/CDを使用し表示する文字列を変更してみます。

  package com.satoh.hello;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RestController;

  @RestController
  public class HelloApplicationController {
      @RequestMapping("/")  // ルートへこのメソッドをマップする
      public String test() {
          return "Hello World";
      }
  }
    

  package com.satoh.hello;
  import org.springframework.boot.SpringApplication;
  import org.springframework.boot.autoconfigure.SpringBootApplication;

  @SpringBootApplication
  public class HelloApplication {
      public static void main(String[] args) {
          SpringApplication.run(HelloApplication.class, args);
      }
  }
    

buildspec.yml

デモで使用するbuildspec.ymlは以下の通りです。

  version: 0.2
  phases:
      pre_build:
          commands:
              - echo Logging in to Amazon ECR...
              - aws --version
              - pwd
              - mvn clean install -DskipTests=true
              - cd $CODEBUILD_SRC_DIR
              - pwd
              - $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)
              - REPOSITORY_URI=xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/demo-app-ecr-01
              - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
              - IMAGE_TAG=build-$(echo $CODEBUILD_BUILD_ID | awk -F":" '{print $2}')
      build:
          commands:
              - echo Build started on `date`
              - echo building the Jar file
              - mvn clean install      
              - echo Building the Docker image...
              - docker build -t $REPOSITORY_URI:latest .
              - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
      post_build:
          commands:
              - echo Build completed on `date`
              - echo Pushing the Docker images...
              - docker push $REPOSITORY_URI:latest
              - docker push $REPOSITORY_URI:$IMAGE_TAG
              - echo Writing image definitions file...
              - printf '{"ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
              - cat imageDetail.json
              - ls -l
      artifacts:
          files:
              - imageDetail.json
              - appspec.yml
              - taskdef.json
    

appspec.yml

デモで使用するappspec.ymlは以下の通りです。

  version: 0.0
  Resources:
      - TargetService:
          Type: AWS::ECS::Service
          Properties:
              TaskDefinition: ""
              LoadBalancerInfo:
                  ContainerName: "demo-app-container-01"
                  ContainerPort: "8080"
              PlatformVersion: "1.4.0"
    

Dockerfile

デモで使用するDockerfileは以下の通りです。

  FROM public.ecr.aws/amazoncorretto/amazoncorretto:17
  COPY . /usr/src/app
  WORKDIR /usr/src/app
  ARG JAR_FILE=target/*.jar
  COPY ${JAR_FILE} app.jar
  ENTRYPOINT ["java", "-jar", "app.jar"]
    

パイプライン実行

上記ファイルを使用してパイプラインを作成し、一度実行した結果です。

javaアプリケーションがデプロイされ、「Hello World」が表示されています。

修正後のJavaアプリデプロイ

表示する文字列を修正し、Blue/Green デプロイを実施します。デプロイ処理の流れを以下に記載します。

  1. 1. CodeCommitにfeature/modify_javaブランチを作成してpushし、プルリクエストを作成
  2. 2. プルリクエストを承認し、releaseブランチにマージ
  3. 3. マージを契機にパイプラインが実行される
  4. 4. ビルドを処理が実行され、ECRにコンテナイメージが格納される
  5. 5. CodeDeployによってBlue/Greenデプロイが実行され、ECS上のコンテナが切り替わる

修正後のJavaアプリケーションのコードは以下の通りです。

  package com.satoh.hello;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RestController;

  @RestController
  public class HelloApplicationController {
      @RequestMapping("/")  // ルートへこのメソッドをマップする
      public String test() {
          return “皆さんこんにちは!!!";
      }
  }
    

パイプラインを実行し、CodeDeployの画面を見るとECSタスク(コンテナ)が置き換わっていることが分かります。

再度Webページを確認すると、表示文字列が変わっていることが分かります。

まとめ

AWSのサービス(CodeCommit、CodeBuild、CodeDeploy、CodePipeline)を使用してコンテナのCI/CDを実装することができました。ポイントを以下にまとめます。

ポイント

CodeCommit

  • AWSが提供するGitであり、CodeCommitへのマージをトリガーとしてCI/CDを実行することができる
  • CodePipelineはCodeCommit以外の外部Gitサービスにも対応(例えばGitHubなど)しており、マストではない

CodeBuild

  • AWSが提供するビルドサービスであり、ソースコードのコンパイルやテストなど、柔軟に実行させることが可能
  • バックグラウンドで動いているのはLinuxであるため、大半のことは実装可能。この柔軟さを使いこなせるかどうかが重要

CodeDeploy

  • コンテナのBlue/Greenデプロイの他、Lambda、EC2などのサービスへのデプロイも実装可能
  • CodePipelineにもデプロイ機能が備わっているため、使い分けが重要

CodePipeline

  • CI/CDパイプラインを実装するためのサービス
  • 必要なステージ(ソース、ビルド、テスト、デプロイなど)をどのサービスで実装し、パイプラインに組み込むか考えるスキルが必要

CTCは、AWSのビジネス利活用に向けて、お客様のステージに合わせた幅広い構築・運用支援サービスを提供しています。
経験豊富なエンジニアが、ワンストップかつ柔軟にご支援します。
ぜひ、お気軽にお問い合わせください。

お問い合わせ



【著者プロフィール】

佐藤 和希(さとう かずき)

伊藤忠テクノソリューションズ株式会社 クラウドアーキテクト

AWS上で実装されるクラウドネイティブなシステムの開発プロジェクトに従事。 エンタープライズ向けクラウドネイティブ案件のプリセールス並びにプロジェクトにおけるクラウドアーキテクトとして活躍中。

佐藤 和希(さとう かずき)

TOP>コラム一覧>ECS_FargateのCICD実装方法

pagetop