このチュートリアルの例では、シンプルな Go アプリケーションを Amazon EC2コンテナサービス(ECS)にデプロイします。次に、CircleCI を使用して、アプリの後続バージョンを自動的にビルド、テスト、デプロイします。使用されているテクノロジーを正しく確実に理解できるように、次の主な手順を段階的に行っていきます。

  1. セキュリティグループを作成する
  2. 1 つのインスタンスで ECS クラスタを作成する
  3. ECS タスク定義を作成する
  4. タスク定義を実行するサービスを作成する
  5. CircleCI クラスタの ECS サービスに関連付ける Amazon Elastic Load Balancer(ELB)およびターゲットグループを作成して構成する
  6. CircleCI の ELB で DNS 名を使用してアプリケーションにアクセスする(動作することをテストするため)
  7. circleci/aws-ecr@6.2.0 orb を使用して CircleCI を構成し、更新されたイメージをビルドして Amazon Elastic Container Registry(ECR) にプッシュする
  8. circleci/aws-ecs@0.0.11 orb を使用して CircleCI を構成し、先ほど作成したクラスタに更新されたイメージをデプロイする

Amazon ECS の利点を十分に理解するには、まず Docker を理解する必要があります。このチュートリアルでは、Docker とコンテナの知識が必要となります。さらに、継続的インテグレーションと継続的デプロイメント(CI/CD)の基本の理解している必要があります。次のセクションでは、使用するテクノロジーと用語の一部を説明します。

使用されるテクノロジーと用語の概要

  • ECS の概要: ECS は、コンテナを管理する Amazon Web Services(AWS)のクラウドコンピューティングサービスです。開発者は、アプリケーションプログラミングインターフェイス(API)呼び出しとタスク定義を通じて、クラスタと呼ばれるサーバーのグループで実行されるスケーラブルなアプリケーションデプロイおよび管理できます。基本的に、ECS はタスクスケジューラです。ECS が作成するタスクは、実行中の Docker コンテナにマップされます。使用可能なリソースに基づいて、クラスタ内のリソースでタスクを実行する場所を決定します。Docker が広く採用されていることから、他のコンテナテクノロジー(LXC、RKTなど)も利用できるようになっていますが、ECS は Docker コンテナでネイティブに動作するように設計されています。

  • タスク定義: タスク定義は、コンテナの実行方法を説明するレシピと考えることができます。コンテナに公開するポート、割り当てるメモリと CPU、コンテナを起動する Docker イメージなどの情報がタスク定義に含まれます。この例のタスク定義では、1 つのコンテナ、使用するイメージ、割り当てる CPU とメモリ、および公開するポートが設定されます。

  • タスク: ECS タスクは、タスク定義からインスタンス化された実行中のコンテナの単位です。これらは、同じインスタンスで一緒に実行される 1〜N 個のコンテナの論理グループです(N は 1〜10 の間で定義されます)。需要に応じて、1 つのタスク定義で複数のタスクを作成できます。

  • サービス: ECS サービスは、常にいくつかのタスクが常に実行されていることを保証するために使用されます。エラーが発生しタスクのコンテナが終了した場合、またはバックエンドの EC2 インスタンスが失敗して置き換えられる場合、ECS サービスは失敗したタスクを置き換えます。クラスタを作成して、使用する CPU、メモリ、およびネットワークポートなど、サービスが十分なリソースを利用できるようにします。実行されている限り、どのインスタンスタスクが実行されるかは重要ではありません。サービスコンフィグは、タスク定義を参照します。サービスはタスクの作成を担当します。

  • クラスター: ECS クラスターは、単一のリージョン内にある(コンテナ)インスタンス(または Fargate ではタスク)のグループですが、複数のアベイラビリティーゾーンにまたがる場合もあります。ECS は、これらのインスタンスへのスケーリングリクエストのスケジューリング、管理、および処理のロジックを処理します。また、CPU とメモリのニーズに基づいて各タスクを最適に配置する作業も不要になります。クラスタは多くのサービスを実行できます。製品の一部であるアプリケーションが複数ある場合、それらのいくつかを 1 つのクラスタに配置できます。これにより、利用可能なリソースを効率的に使用し、セットアップの時間を最小限に抑えることができます。

  • コンテナインスタンス: これは、Amazon ECS コンテナエージェントを実行している Amazon Elastic Compute Cloud(EC2)インスタンスです。IAM ポリシーロール が明確に定義されており、クラスタに登録されています。Amazon ECS でタスクを実行すると、EC2 起動タイプを使用して、ユーザーのタスクがアクティブなコンテナインスタンスに配置されます。

  • CircleCI Orbs: Orbs は、プロジェクト間で共有できる CircleCI コンフィグのパッケージです。Orbs を使用すると、ジョブ、コマンド、および Executor から構成される単一のバンドルを作成して、相互に参照したり、CircleCI ビルドコンフィグにインポートして独自のネームスペースで呼び出したりすることができます。

シンプルな Go アプリケーション

プロジェクトのディレクトリ構造は次のとおりです。

.
├── .circleci
│   └── config.yml
├── Dockerfile
├── README.md
├── ecs-service.json
├── main.go
└── task-definition.json

1 directory, 6 files

完全なアプリケーションは、このリポジトリにあります。詳細を確認するには、お使いの端末で次の行を使用して、必要な場所にクローンを作成します。

$ git clone https://github.com/daumie/circleci-ecs.git

Dockerfile のみについて作業する場合は、ここで見つけることができます。Go アプリケーションの main.go ファイルはここにあります。

では、これらをまとめて実行していきましょう。最初に、AWS アカウントを作成してアクティブにします。次に、ローカルマシンに AWS CLI をインストールして設定します。AWS CLI を使用して、コマンドラインインターフェイスで AWS とやり取りします。

次に、AWS アカウントを作成したときに自動的に作成されるデフォルトの Virtual Private Cloud(VPC)を使用します。利用できない場合は、次のコマンドを実行してデフォルトの VPC を作成できます。

$ aws ec2 create-default-vpc

次のコマンドを実行して、利用できる VPC があることを確認します。

$ aws ec2 describe-vpcs

デフォルトの VPC があることを確認したら、後で使用するセキュリティグループを作成しましょう。

$ aws ec2 create-security-group --group-name circleci-demo-sg --description "Circle CI Demo Security Group"

次に、ECS クラスターと関連する EC2 インスタンスを作成します。circleci-demo-cluster クラスタを呼び出します。以前に作成した circleci-demo-sg セキュリティグループを設定する必要があります。

  • クラスタ名: circleci-demo-cluster
  • EC2 インスタンスタイプ: t2.medium
  • ネットワーキング: すべてのサブネットでデフォルト VPC を使用します。
  • セキュリティグループ: (circleci-demo-sg) この ID を使用します。
  • コンテナインスタンス IAM ロール: ecsInstanceRole

数分間待ってから、コンテナインスタンスが circleci-demo-cluster に正常に登録されたことを確認します。 Clusters/my-cluster の下の ECS Instances タブをクリックして、登録されていることを確認できます。

アプリケーションイメージを作成し、AWS ECR にプッシュする

Docker イメージをローカルで作成し、ECR にプッシュします。

$ docker build -t circleci-ecs:v1 .

Step 1/14 : FROM golang:latest as builder
 ---> be63d15101cb
...

次の手順で、ECR にイメージリポジトリを作成します。circleci-demo という名前を付けます。

AWS アカウントには一意の ID が設定されます。次のコマンドの 634223907656 をその ID に変更してください。リポジトリ名を取得したら、イメージを適切にタグ付けできるようになります。

$ docker tag circleci-ecs:v1 634223907656.dkr.ecr.eu-west-2.amazonaws.com/circleci-demo:latest

認証情報ヘルパーを使用して、Docker CLI の AWS ECR リポジトリを認証できます。次のコマンドを使用して認証します(必要に応じてリージョンを変更します)。

$ aws ecr get-login --no-include-email --region eu-west-2 | bash

次に、イメージを ECR リポジトリにプッシュします。

$ docker push 634223907656.dkr.ecr.eu-west-2.amazonaws.com/circleci-demo:latest

ECR レジストリにイメージができましたので、Go アプリケーションを起動するブループリントになるタスク定義が必要です。プロジェクトのルートにある task-definition.json ファイルには、次のコード行があります。

{
    "family": "circleci-demo-service",
    "containerDefinitions": [
        {
            "name": "circleci-demo-service",
            "image": "634223907656.dkr.ecr.eu-west-2.amazonaws.com/circleci-demo:latest",
            "cpu": 128,
            "memoryReservation": 128,
            "portMappings": [
                {
                    "containerPort": 8080,
                    "protocol": "tcp"
                }
            ],
            "command": [
                "./main"
            ],
            "essential": true
        }
    ]
}

: ECR にプッシュしたイメージに変更することを忘れないでください。

次のコマンドを実行して、コマンドラインインターフェイスからタスク定義を登録します。

$ aws ecs register-task-definition --cli-input-json file://task-definition.json

タスク定義が ECS コンソールに正常に登録されたことを確認します。

後で ECS サービスに関連付ける ELB とターゲットグループを作成する

ELB を作成しているのは、最終的に複数のコンテナ間でリクエストをロードバランシングし、Go アプリケーションをテストのためにインターネットに公開するためです。このために、AWS コンソールを使用します。EC2 Console > Load Balancing > Load Balancers に移動し、Create Load Balancer をクリックして、Application Load Balancer を選択します。

ロードバランサーを構成する

  • ロードバランサーに circleci-demo-elb という名前を付けて、[internet-facing] を選択します。
  • listeners で、HTTP プロトコルとポート 80 を使用するデフォルトのリスナーを使用します。
  • Availability Zone で、クラスタを作成したときに使用した VPC を選択し、必要なサブネットを選択します。

セキュリティを構成する

  • SSL を使用しないため、警告をスキップします。

セキュリティグループを構成する

  • circleci-demo-elb-sg という名前の新しいセキュリティグループを作成し、ポート 80 とソース 0.0.0.0/0 を開いて、外部からのすべてがポート 80 で ELB にアクセスできるようにします。

ルーティングを構成する

  • ポート 80 を使用する新しいターゲットグループ名 circleci-demo-target-group を作成します。

ターゲットを登録する

  • ECS インスタンスを選択して、既存のターゲットを登録します。

レビュ

  • ロードバランサーの詳細を確認します。

circleci-demo-elb-sg セキュリティグループは、circleci-demo-elb ロードバランサーのポート 80 を開きます。次に、ECS インスタンスに関連付けられた circleci-demo-sg セキュリティグループがロードバランサーからのトラフィックを許可することを確認する必要があります。すべての ELB トラフィックがコンテナインスタンスにヒットできるようにするには、次を実行します。

$ aws ec2 authorize-security-group-ingress --group-name circleci-demo-sg --protocol tcp --port 1-65535 --source-group circleci-demo-elb-sg

EC 2 コンソールから、セキュリティグループにこれらのルールが追加されたことを確認します。

インバウンドルール

アウトバウンドルール

これらのセキュリティグループルールでは以下が設定されます。

  • ELB のポート 80 のみが外部に公開されます。
  • ELB から circleci-demo-target-group グループのコンテナインスタンスに送信されるトラフィックはすべて許可されます。

サービスを作成する

次のステップは、circleci-demo-service タスク定義(task-definition.json ファイルで定義)を実行するサービスを作成することです。プロジェクトのルートにある ecs-service.json ファイルには、次のコード行があります。

{
    "cluster": "circleci-demo-cluster",
    "serviceName": "circleci-demo-service",
    "taskDefinition": "circleci-demo-service",
    "loadBalancers": [
        {
            "targetGroupArn": "arn:aws:elasticloadbalancing:eu-west-2:634223907656:targetgroup/circleci-demo-target-group/a5a0f047c845fcbb",
            "containerName": "circleci-demo-service",
            "containerPort": 8080
        }
    ],
    "desiredCount": 1,
    "role": "ecsServiceRole"
}

circleci-demo-elb ロードバランサーを作成するときに作成した targetGroupArn を見つけるには EC2 Console > Load Balancing > Target Groups に移動し、circleci-demo-target-group をクリックします。これをコピーして、ecs-service.json ファイルの targetGroupArn にあるものと置き換えます。

次に、circleci-demo-service ECS サービスを作成します。

$ aws ecs create-service --cli-input-json file://ecs-service.json

ECS コンソールから、Clusters > circleci-demo-cluster > circleci-demo-service に移動し、Tasks タブを表示します。コンテナが実行されていることを確認します。


すべてが機能していることをテストする

curl を使用して、ELB で公開されている DNS エンドポイントを確認します。

$ curl circleci-demo-elb-129747675.eu-west-2.elb.amazonaws.com; echo
    
Hello World!


ブラウザからも同じように確認できます。

CircleCI を構成して、ビルド、テスト、およびデプロイする

Go アプリケーションを ECS に正常にデプロイしたら、アップデートごとにアプリを再デプロイします。CircleCi orbs を使用することにより、構成済みのコマンド、ジョブ、および Executor をコンフィグファイルにインポートでき、多くの時間を節約できます。これにより、AWS のデプロイに必要な bash スクリプト作成の多くの労力が軽減され、コンフィグ内のコード行も大幅に削減されます。Orbs キーを使用して、このプロジェクトで次の Orbs を呼び出します。

  • circleci/aws-ecr@6.2.0: Amazon の ECR と連携してイメージをビルド、プッシュ、更新する Orb
  • circleci/aws-ecs@0.0.11: Amazon の ECS と連携して、更新されたイメージを以前に作成したクラスタに展開する Orb

Orbs は次の要素から構成されます。

  • コマンド
  • ジョブ:実行可能なコマンドまたはステップのセット
  • Executor:Executor は、Docker、マシン、macOS やその環境の他のパラメーターなど、ステップが実行される環境を定義します。

CircleCI を使用するには、ビルド、テスト、およびデプロイ操作を命令するために CircleCI が使用するコンフィグファイルが必要です。このプロジェクトの場合、config.yml ファイルには次のコード行が含まれます。

version: 2.1

orbs:
  aws-ecr: circleci/aws-ecr@6.2.0
  aws-ecs: circleci/aws-ecs@0.0.11

workflows:
# Log into AWS, build and push image to Amazon ECR
  build_and_push_image:
    jobs:
      - aws-ecr/build-and-push-image:
          account-url: AWS_ECR_ACCOUNT_URL
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          create-repo: true
          # Name of dockerfile to use. Defaults to Dockerfile.
          dockerfile: Dockerfile
          # AWS_REGION_ENV_VAR_NAME
          region: AWS_DEFAULT_REGION
          # myECRRepository
          repo: '${MY_APP_PREFIX}'
          # myECRRepoTag
          tag: "$CIRCLE_SHA1"
      - aws-ecs/deploy-service-update:
          requires:
            - aws-ecr/build-and-push-image
          aws-region: AWS_DEFAULT_REGION
          family: '${MY_APP_PREFIX}-service'
          cluster-name: '${MY_APP_PREFIX}-cluster'
          container-image-name-updates: 'container=${MY_APP_PREFIX}-service,tag=${CIRCLE_SHA1}'

GitHub と CircleCI を使用します。CircleCI アカウントがない場合は、アカウントを作成します。GitHub にサインアップします。CircleCI ダッシュボードから Add Project をクリックし、表示されたリストからプロジェクトを追加します。

次の環境変数を追加します。

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_DEFAULT_REGION
  • AWS_ECR_ACCOUNT_URL (In this example, “634223907656.dkr.ecr.eu-west-2.amazonaws.com”)
  • MY_APP_PREFIX (In this example, “circleci-demo”)

main.go ファイルで次の行を変更します。

html := "Hello World!" 

html := "Hello World! Now updated with CircleCI"
に変更します。

変更をコミットして GitHub にプッシュします。

次のコマンドを実行することで、変更が端末から適用されたことを確認できます。

$ curl circleci-demo-elb-129747675.eu-west-2.elb.amazonaws.com ; echo
    
Hello World! Now updated with CircleCI

ブラウザからも同じように確認できます。

結論

ここでは、シンプルな GO アプリケーションをビルドし、それを ECR にデプロイしました。これで、テストをアプリケーションに追加して、ECS インスタンスを更新する前にそれらのテストに合格することを確認できます。このチュートリアルでは、基本的なアプリケーションを使用しましたが、これは多くの実際の状況で機能する成熟したデプロイメントパイプラインです。

さらに、CircleCI Orbs を使用すると、CircleCI コンフィグの記述が簡素化されるため、生産性が向上します。Orbs は共有できるため、作成済みのコマンド、ジョブ、および Executor をコンフィグファイルで繰り返し使用でき、時間を節約できます。Orbs の使用は CircleCI と ECS のデプロイに限定されません。Orb レジストリで利用可能な Orbs の詳細なリストを確認し、クラウドプラットフォーム、プログラミング言語などに適合する Orbs を見つけることができます。


Dominic Motuka 氏は Andela 社の DevOps エンジニアであり、コンフィグ管理、CI/CD、DevOps プロセスを活用した、AWS および GCP の本番環境へのデプロイのサポート、自動化、最適化について 4 年以上の実務経験があります。