🐊

AWS Copilot CLI を使って複数環境で既存の DynamoDB を使う

2021/12/12に公開

はじめに

この記事は AWS Containers Advent Calendar 2021 12 日目の記事です。

皆さんは AWS Copilot CLI をご存知でしょうか? Copilot CLI は Amazon ECS や App Runner 環境の構築や運用、 CI/CD パイプラインの作成を簡単に行える CLI ツールです。この記事では既存の DynamoDB テーブルにアクセスする Service を 2 つの Environment に作成し CI/CD パイプライン経由でデプロイするまでの流れを紹介します。

つくるもの

この記事ではこの Copilot CLI の Workshop の backend Service を作っていきます。ワークショップの流れだと copilot storage init コマンドで新しく DynamoDB テーブルを作成しますが、今回は既存の DynamoDB テーブルを使います。

やってみる

事前準備

まず Copilot CLI をインストールします。インストール方法はドキュメントのこのページに書かれています。コマンドを実行して正しくインストールされたかを確認します。

$ copilot --version
copilot version: v1.13.0

次に認証情報を設定します。認証情報についての推奨事項はドキュメントのこのページに書かれていて、推奨されているように名前付きプロファイルを使用することにします。今回 2 つの Environment を作成する予定なのでリージョンごとに 2 つのプロファイルを作成します。

$ aws configure 
# region は us-east-1 とします
$ aws configure --profile dev
# region は us-east-1 とします
$ aws configure --profile prod
# region は ap-northeast-1 とします

アプリケーションコードは Copilot CLI のワークショップのものを使います。ソースコードをクローンした後で cd code しておきます。

$ git clone https://github.com/aws-samples/copilot-primer-workshop.git
$ cd code

Application, Environment の作成

最初に Copilot CLI のコンセプトを紹介しておきます。ドキュメントのこのページに詳しく書いています。

Copilot CLI ではまず大枠として Application という単位でリソースを管理します。そして Application の中に Environment や Service などを作成していきます。例えば TODO アプリを作る場合は todo という Application を作成し、 development Environment と production Environment (それぞれ開発環境と本番環境をイメージしています。 Environment では VPC や ECS Cluster が作成されます。VPC は新規作成することもできますし既存の VPC を Application にインポートして使うこともできます)を作成し、frontend Service と backend Service (Service は ECS Service とは異なるものです。このドキュメントにあるようにいくつかのアーキテクチャパターンから選択して必要なリソースを作ることができます)を作成すると言う流れになります。

まず Application を作成します。 code ディレクトリにいることを確認した上で以下のコマンドを実行します。

$ copilot app init sample

CloudFormation を使って必要なリソースが作成されます。 Application の作成が終わってから 2 つの Environment を作成します。今回は引数を全て渡してコマンドを実行しますが、 copilot env init --help でヘルプを見ると他にどのような引数が使えるかがわかるのでよければみてください。

--profile で Environment を作成する時に使う名前付きプロファイルを指定できます。今回は同一アカウント別リージョンに Environment を作成しますが別アカウントに対しても同じように Environment を作成できるのが Copilot 便利ポイントの一つです。

$ copilot env init --app sample --name development --default-config --profile dev
$ copilot env init --app sample --name production --default-config --profile prod

DynamoDB テーブルを作成

今回は既存の DynamoDB テーブルを Copilot Service から利用する予定なので AWS CLI で DynamoDB テーブルを作成します。 prodtable , devtable をそれぞれ development Environment と production Environment と同じリージョンに作成します。

$ aws dynamodb create-table \
    --table-name devtable \
    --attribute-definitions AttributeName=TodoId,AttributeType=N \
    --key-schema AttributeName=TodoId,KeyType=HASH \
    --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
    --profile dev
$ aws dynamodb create-table \
    --table-name prodtable \
    --attribute-definitions AttributeName=TodoId,AttributeType=N \
    --key-schema AttributeName=TodoId,KeyType=HASH \
    --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
    --profile prod

backend Service の作成

Backend Service を作成します。DynamoDB に接続して CRUD 操作をする API が動く Service です。

$ copilot svc init -n backend -t "Backend Service" -d backend/Dockerfile --port 10000

Addon の作成

ここがこの記事で一番大事なところです。

Copilot CLI はデフォルトで統合されていない AWS サービスを Addon と言う形で追加できます。こちらのドキュメントに詳しく書いています。

既存の DynamoDB テーブルを使うためにはコンテナの中のアプリケーションから DynamoDB テーブルにアクセスする必要があるので、タスクロールのポリシーの中で既存の DynamoDB テーブルへのアクセスを許可する必要があります。なので Addon の中の CloudFormation テンプレートで IAM ポリシーを定義します。

まずは addons ディレクトリを作成して空のテンプレートファイルを作成します。

$ mkdir copilot/backend/addons
$ touch copilot/backend/addons/template.yml

ではこのテンプレートはどのように書けばいいでしょうか? Copilot CLI では Service の定義を複数の Environment にデプロイし Environment ごとの差分は Manifest ファイルの中でオーバーライドして実現します(Backend Service の場合はこの Manifest の environments セクションで定義します)。今回 Environment ごとに DynamoDB テーブルの名前が違うので CloudFormation テンプレートの中で Environment ごとにアクセスを許可する DynamoDB テーブルを出し分ける必要があります。

Addon テンプレートの構造に CloudFormation テンプレートの構造が詳しく書かれています。 Parameters に Environment 名がパラメータで渡されるのでこれを使って Mappings セクションを作ります。テンプレートはこんな感じで Mappings と FindInMap 関数を組み合わせます。

Parameters:
  App:
    Type: String
    Description: Your application's name.
  Env:
    Type: String
    Description: The environment name your service, job, or workflow is being deployed to.
  Name:
    Type: String
    Description: The name of the service, job, or workflow being deployed.

Mappings:
  TableNameMap:
    development:
      "TableName": "devtable"
    production:
      "TableName": "prodtable"

Resources:
  TableAccessPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: DDBActions
            Effect: Allow
            Action:
              - dynamodb:BatchGet*
              - dynamodb:DescribeStream
              - dynamodb:DescribeTable
              - dynamodb:Get*
              - dynamodb:Query
              - dynamodb:Scan
              - dynamodb:BatchWrite*
              - dynamodb:Create*
              - dynamodb:Delete*
              - dynamodb:Update*
              - dynamodb:PutItem
            Resource: !Sub
              - arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${Name}
              - { Name: !FindInMap [TableNameMap, !Ref Env, TableName] }

Outputs:
  TableAccessPolicyArn:
    Description: "The ARN of the ManagedPolicy to attach to the task role."
    Value: !Ref TableAccessPolicy

  TodotableName:
    Description: "The name of prod DynamoDB."
    Value: !FindInMap
      - TableNameMap
      - !Ref Env
      - TableName

Pipeline の作成

このまま copilot svc deploy コマンドでデプロイしてもいいですがせっかくなので CI/CD パイプライン経由でデプロイしましょう。Copilot CLI なら copilot pipeline init コマンドで CI/CD パイプラインを簡単に構築できます。

まずソースのコードリポジトリ を作成します。今回は CodeCommit を使いますが Copilot CLI は GitHub にも対応しています。

$ aws codecommit create-repository --repository-name sampleapp --repository-description "My sampleapp repository"

そしてローカル環境の git の設定をします。

$ git init
$ git switch -c main
$ git remote add origin https://git-codecommit.us-east-1.amazonaws.com/v1/repos/sampleapp
$ git config --global credential.helper '!aws codecommit --profile dev credential-helper $@'
$ git config --global credential.UseHttpPath true

以下の二つのコマンドを実行します。 copilot pipeline init コマンドでパイプラインの構造を定義した pipeline.yml ファイルと CodeBuild の中で実行するコマンドを定義した buildspec.yml ファイルが作成され、 copilot pipeline update コマンドで実際にクラウド上に CI/CD パイプラインが作成されます。

$ copilot pipeline init --app sample --environments "development,production" --url https://git-codecommit.us-east-1.amazonaws.com/v1/repos/sampleapp
$ copilot pipeline update

パイプラインの実行

git push するとパイプラインの実行が始まります。

$ git add -A
$ git commit -m 'initial commit'
$ git push origin main

CodePipeline の画面を見ると無事パイプラインの実行が完了します。

おわりに

今回は既存の DynamoDB にアクセスするというストーリーにしましたが、 copilot storage init コマンドなら DynamoDB テーブルを対話的に作成することも可能です。Copilot CLI を使うと簡単に ECS 環境を作れる・別アカウントに対しても簡単に Environment を作成できる・CI/CD パイプラインを簡単に作成できる、など簡単に AWS でコンテナワークロードを始めることができます。ぜひ試してみてください。

Discussion