hero_picture
Cover Image for CircleCI + GitHub + Amazon Elastic Container Registry (Amazon ECR) + Amazon Elastic Container Service (Amazon ECS) (+ AWS Fargate) で継続的デリバリー環境を構成する

CircleCI + GitHub + Amazon Elastic Container Registry (Amazon ECR) + Amazon Elastic Container Service (Amazon ECS) (+ AWS Fargate) で継続的デリバリー環境を構成する

2019/09/11

クラウド事業部の上野です。

AWSにあるコンテナサービスを使ってみたい!今後の弊社のサービスで活用できるかも!ついでにCIツールでデプロイまで自動化したい!

ということでAmazon ECSとAmazon ECRで継続的デリバリー環境を作ってみました。

今回はCIツールとしてCircleCIを利用してみます。

簡単に各サービスを説明しますと、

CircleCIはCI/CD(継続的インテグレーション/継続的デリバリー)を行うサービスです。

Amazon ECSはDocker コンテナをサポートするAWSのコンテナオーケストレーションサービスです。

Amazon ECRはAWS完全マネージド型のDockerコンテナレジストリです。

これらのサービスを使って、GitHubにプッシュしたら自動的にDockerイメージをビルドし、最終的にAmazon ECSのコンテナにデプロイされるという環境を作ってみたいと思います。

今回の構成としてはこのような形です。

構成図

では、環境を作っていきましょう。

ECRの作成

まずはDockerのコンテナを保管するAmazon ECSを作成します。

AWSマネジメントコンソールよりAmazon ECRのダッシュボードを開き、リポジトリ名を入力して作成します。

今回はお試しということでnginxのDockerイメージを使います。

Amazon ECRにリポジトリを作成すると”プッシュコマンドの表示”というボタンが押せるようになります。

これはDockerイメージの作成からAmazon ECRへのプッシュまで、具体的にどういうコマンドを実行すればいいか教えてくています。

親切ですね、具体的には下記のコマンドになります。

1$(aws ecr get-login --no-include-email --region ap-northeast-1)
2docker build -t seeds-test .
3docker tag seeds-test:latest XXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/seeds-test:latest
4docker push XXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/seeds-test:latest

上記コマンドを実行してAmazon ECRにプッシュするとこのようになります。

ecr_push

Amazon ECSクラスター作成

Amazon ECRのリポジトリにDockerのイメージを準備できましたので、次はAmazon ECSを準備していきます。

まずは土台となるAmazon ECSクラスターを作成します。Amazon ECSクラスターとはコンテナインスタンスの集合体のことです。

コンテナインスタンスにはAWSがマネージドしてくれるAWS Fargateと自分自身で管理するEC2インスタンスの2種類がありますが、今回はAWSが管理してくれるAWS Fargateを利用します。

クラスター作成時にコンテナを動作させるAmazon Virtual Private Cloud (Amazon VPC)を新たに作成するか聞かれますが、今回は既存のAmazon VPCを使用するため、新規作成は行わずにクラスター名だけ記入して作成します。

ecs-cluster

Amazon ECSタスク定義の作成

次はAmazon ECSタスク定義を作成します。

Amazon ECSタスク定義とはアプリケーションの設計図です。どういったコンテナをどの程度のスペック(CPU、メモリ)で起動するかといった内容を定義します。

タスクの定義には起動タイプをAWS FargateかEC2インスタンスのいずれかを選択する必要があります。今回はAWS Fargateを選択します。

タスク定義名とタスクメモリとタスクCPUを指定し、それ以外はデフォルトのままにします。

設定の中段あたりにコンテナの定義という項目がありますので、そこで「コンテナの追加」ボタンを押してタスクで起動するコンテナの設定を行います。

コンテナ追加の画面でコンテナのイメージを選択する部分がありますので、ここでAmazon ECRリポジトリに登録したイメージのURIを指定します。

ポートのマッピングは今回はnginxのコンテナですのでhttpの80番ポートをマッピングします。

ecs

これでタスク定義の作成は完了です。

タスク定義は今後リビジョンとして管理され、更新する度にリビジョンの数値が増えていきます。

Amazon ECSサービスの作成

Amazon ECSサービスとはAmazon ECSクラスター上で起動させるタスクの数やAutoScalingの設定を管理します。

起動タイプはAWS FARGATEを選択し、タスク定義とクラスターは事前に作成したものを指定します。

タスクの数の項目でサービス上で何個のタスクを起動させるかを指定できますので、今回はタスクの数を2に指定して、nginxのコンテナが2つ(タスクごとに1つのコンテナ)起動するようにします。

ecs-service

次にネットワーク構成を定義します。

ここでAmazon ECSサービスが起動するAmazon VPCや利用されるセキュリティグループ、ロードバランサーを指定します。

Amazon VPCやセキュリティグループ、ロードバランサは事前に用意しておいたものを指定しています。

ecs-service

ecs-service

サービスを作成するとサービスで定義した内容でコンテナが起動してきます。

ecr-service

この状態でElastic Load Balancing のDNS名にアクセスするとnginxのウェルカムページが表示され、コンテナが正常に稼働できていることを確認できます。

ここまででECRとECSの構築は完了です。

CircleCIとGitHubの設定

ここまでの作業でAWSを利用したコンテナサービスとしては稼働していますが、CircleCIとGitHubを使って継続的デリバリーな環境を作ります。

まず、CircleCIからAmazon ECRとAmazon ECSを操作するためのIAMユーザ(CircleCI用のアクセスキー)を作成します。ポリシーは下記のものを付与してください。作成時に表示されるアクセスキーとシークレットアクセスキーは後ほど利用しますのでメモしておいてください。

1ユーザ名 circleci
2ポリシー AmazonEC2ContainerRegistryFullAccess
3     AmazonEC2ContainerServiceFullAccess

次にGitHubにDocker用のリポジトリを作成します。

github

GitHubでリポジトリが用意出来たらCircleCIにアクセスします。CircleCIではGitHubのアカウントを利用してサインアップできます。

GitHubのアカウントを利用してサインアップするとGitHubに用意したリポジトリが表示されていますのでFollowします。

circleci

これでGitHubとCircleCIの連携の準備ができました。

次にCircleCIのジョブの設定を行います。CircleCIのジョブの画面よりEnvironment Variablesを開き、環境変数をセットします。

  • AWS_ACCESS_KEY_ID(circleciユーザのアクセスキー)
  • AWS_SECRET_ACCESS_KEY(circleciユーザのシークレットアクセスキー)
  • AWS_ACCOUNT_ID(AWSのアカウント番号)
  • AWS_ECR_ACCOUNT_URL(ECRのリポジトリURL XXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/seeds-test)
  • AWS_REGION(ap-northeast-1)

GitHubにプッシュされた場合にCircleCIの動作を制御するための設定ファイルを用意します。

.circleciというフォルダを作成し、その中にconfig.ymlというファイルを作成します。

config.ymlでCircleCIの動作を制御するのですが、Amazon ECRリポジトリへのアップロードやAmazon ECSのタスク定義やサービスを更新するためのOrbs(※ジョブ、コマンドなどの設定要素をまとめた共有可能なパッケージのこと)をCircleCIが公式に提供しています。

これらを利用してGitHubにプッシュされた場合、DocerkイメージをビルドしてAmazon ECRにアップロードし、アップロードされたイメージを元にAmazon ECSのタスク定義とサービスを更新するといった内容のconfig.ymlを作成します。

circleci/aws-ecr@6.3.0

circleci/aws-ecs@0.0.11

config.ymlの内容

1version: 2.1
2orbs:
3aws-ecr: circleci/aws-ecr@6.1.0
4aws-ecs: circleci/aws-ecs@0.0.8
5workflows:
6build_and_push_image:
7jobs:
8- aws-ecr/build-and-push-image:
9region: AWS_REGION
10account-url: AWS_ECR_ACCOUNT_URL
11repo: 'seeds-test' # GitHubのリポジトリ名
12tag: "${CIRCLE_SHA1}"
13- aws-ecs/deploy-service-update:
14requires:
15- aws-ecr/build-and-push-image
16family: 'seeds-test-task' # ECSのタスク定義名
17cluster-name: 'seeds-test-container' # ECSクラスター名
18service-name: 'seeds-test-service' # ECSのサービス名
19container-image-name-updates: 'container=seeds-test,tag=${CIRCLE_SHA1}' # タスク定義で指定しているコンテナ名

それではnginxのDocerfileと作成したconfig.ymlをGitHubにプッシュしてみましょう。

github

CircleCIをみるとプッシュを検知してジョブが動いていることを確認できます。

circleci

Amazon ECRの画面をみると新しいイメージが登録されていることを確認できます。

ecr

Amazon ECSのタスク定義も更新されています。

ecs

Amazon ECSのサービスで指定されるタスク定義も新しいものに更新され、自動でAutoScalingが実行されています。

ecs

これでCircleCI + GitHub + Amazon ECR + Amazon ECS で継続的デリバリー環境が構築できました。

今回構築した環境はとりあえず動く環境という状態を作りましたが、細かい設定をしていけばより柔軟な環境が作り上げることができます。例えばdevelopブランチにプッシュした場合は開発環境のAmazon ECSにデプロイ、prodcutブランチにプッシュした場合は本番環境のAmazon ECSにデプロイするといったことも可能です。

今回は案件の関係でCircleCIを利用する機会があったため、CIツールにCircleCIを利用しましたが、AWSにはもともとAWS CodeBuildやAWS CodePipelineなどのCIツールが用意されています。次回はこれらを使って継続的デリバリーの環境を作ってみたいと思います。