CircleCI を使って AWS ECR から ECS にデプロイしてみた

こんにちは。

CircleCI カスタマーサクセスチームの Chisato です。
最近個人的に幸せを感じた出来事は、ビリヤニをつくったことです。
本場のハイデラバードでビリヤニを食べることが目標の１つに加わりました。
<br>

今回は、CircleCI を使用して、Amazon Elastic Container Registry (ECR) から Amazon Elastic Container Service (ECS) にデプロイします。

CircleCI のドキュメンテーション 「[AWS ECR/ECS へのデプロイ](https://circleci.com/docs/ja/ecs-ecr/) 」を参考に進めます。
<br>

# 準備するもの
- CircleCI アカウント
- AWSアカウント
- Terraform
- サンプルプロジェクト（クローンしておく） ― "[CircleCI-Public/circleci-demo-aws-ecs-ecr](https://github.com/CircleCI-Public/circleci-demo-aws-ecs-ecr)"



# Terraform のインストール

Terraform は、HashiCorp社 が提供する IaC (Infrastructure as Code)のツールで、構築、変更、バージョン管理といったインフラの構成管理を安全かつ効率的に実行可能にします。

[こちらのページ](https://www.terraform.io/) にアクセスして、Terraform をインストールします。

今回は macOS のオープンソース版をインストールしました。

```
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
```

<br>

# CircleCI 環境変数の設定

CircleCI のサンプルプロジェクト をクローンして、CircleCI の [Project Settings] ページに移動します。
![Screenshot 2023-02-01 at 11.40.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/f4398b94-42e2-a3cb-581f-eae700950eda.png)

[Environment Variables] タブをクリックして、[Add Environment Variables] をクリックします。
下記テーブルの環境変数を設定していきます。
環境変数の値の確認方法は後述します。
![Screenshot 2023-02-01 at 11.43.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/64aa38a8-e9b4-8acd-1dbf-cde58fd279c7.png)

![Screenshot 2023-02-01 at 11.46.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/64b6eebc-4bd2-0810-2a28-79948cf58207.png)


#### 設定する環境変数一覧

| 変数 | 説明 |
|:-:|:-:|
| `AWS_ACCESS_KEY_ID`  | AWS のセキュリティ認証情報です。  |
| `AWS_SECRET_ACCESS_KEY`  | AWS のセキュリティ認証情報です。  |
| `AWS_DEFAULT_REGION`  | AWS CLI によって使用されます。 |
| `AWS_ACCOUNT_ID`  | デプロイに必要です。 AWS アカウント ID は[こちら](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/console_account-alias.html#FindingYourAWSId)で確認してください。  |![Screenshot 2023-02-01 at 11.39.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/3d0ce220-16a7-f668-757d-74ee57c45129.png)
| `AWS_RESOURCE_NAME_PREFIX`  | 必須の AWS リソースのプレフィックスです。 `terraform_setup/terraform.tfvars` の `aws_resource_prefix` の値に対応する必要があります。  |
|  `AWS_ECR_REGISTRY_ID` |  ECR アカウントに関連づけられた 12 桁の AWS ID です。 |


上記のうち `AWS_DEFAULT_REGION`について、「[CircleCI 環境変数を設定する](https://circleci.com/docs/ja/ecs-ecr/#configure-circleci-environment-variables)」のページでは `AWS_REGION` という表記ですが、今回は Config.yml ファイル内の記述に合わせて `AWS_DEFAULT_REGION`としています。

# 環境変数の値の確認方法
1\. `AWS_ACCESS_KEY_ID` と `AWS_SECRET_ACCESS_KEY`は、AWS のコンソールから [IAM]、[Users]、対象のユーザーのページに移動して、[Security Credentials]タブをクリックします。
![Screenshot 2023-02-01 at 12.11.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/4e2c9cc4-3bf4-d764-f082-cf00e855d03f.png)
スクロールダウンすると、`Access Keys`の項目があります。
アクセスキーは、`Create Access Key`をクリックして作成できます。
`Access key`, `Secret Access Key`をそれぞれコピーして環境変数として登録します。
![Screenshot 2023-02-01 at 12.16.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/fe97fef1-af2b-25de-9aa3-163def0fbc59.png)


2\. `AWS_ACCOUNT_ID`は[こちら](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/console_account-alias.html#FindingYourAWSId)に確認方法が記載されています。
コンソールから確認するには、[サポート]、[サポートセンター]と進み、ナビゲーションペインをチェックします。
![Screenshot 2023-02-01 at 11.55.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/1102f924-1fed-2609-5df5-e94606978a28.png)

# Terraform ファイルの設定
`~/terraform_setup/terraform.tfvars` のファイルを開き、各項目に実際の値を入力します。環境変数名ではなく、実際の値であることに注意してください。

![Screenshot 2023-02-03 at 13.24.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/fb6ec70e-122f-d567-fcd5-015c9aab9d97.png)


# AWS のリソースの作成
Terraform を下記手順で実行します。

```
cd terraform_setup
terraform init
terraform plan  # プランをレビューします
terraform apply  # プランを適用して AWS リソースを作成します
```
<br>
私は最初、ECR の Repository を手動で作成してしまったことによりエラーが出ました。
上記コマンドで、 ECR の Repository まで自動生成してくれます。

最後まで進むと下記メッセージが表示されます。

![Screenshot 2023-02-03 at 14.30.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/9ea16228-6634-2791-70c7-f101f74164eb.png)



AWSのコンソールを見てみると、ばっちり作成されています。


ECS のクラスター
![Screenshot 2023-02-03 at 14.10.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/6457e197-0022-7c22-8248-e1a92122112a.png)

ECR のレポジトリー
![Screenshot 2023-02-03 at 14.10.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/e974b874-e32d-2e70-bb68-f425cfab7828.png)



<br>

# Config.yml ファイルの編集

今回、このプロジェクトで幾度となくエラーに苦しみ、しばらく田舎に帰ろうかなと思い始めたとき、目の前にひと筋の光が差し込みました。
CircleCIが誇る素晴らしいエンジニアの方々、Jasurさん、Kelvinさん、Jenningsさんです。

彼らにご指導いただきながら、一緒にConfig.yml ファイルを見ていくなかで、一部の記述を変えることになりました。

このため、サンプルプロジェクトのものを下記のように変更しています。
変更箇所にコメントを追記しています。
<br>



```
version: 2.1
orbs:
  aws-ecr: circleci/aws-ecr@8.2.1  # orbのバージョン変更
  aws-ecs: circleci/aws-ecs@3.2.0  # orbのバージョン変更
workflows:
  build-and-deploy:
    jobs:
      - aws-ecr/build-and-push-image:  # build_and_push_image を build-and-push-imageに変更
          repo: "${AWS_RESOURCE_NAME_PREFIX}"  #account_url, regionの記述を削除
          tag: "${CIRCLE_SHA1}"
      - aws-ecs/deploy-service-update:
          requires:
            - aws-ecr/build-and-push-image  # build_and_push_image を build-and-push-imageに変更
          aws-region: AWS_DEFAULT_REGION  # ${AWS_DEFAULT_REGION} を AWS_DEFAULT_REGIONに変更
          family: "${AWS_RESOURCE_NAME_PREFIX}-service"
          cluster: "${AWS_RESOURCE_NAME_PREFIX}-cluster"  #cluster_name をclusterに変更
          container-image-name-updates: "container=${AWS_RESOURCE_NAME_PREFIX}-service,image-and-tag=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${AWS_RESOURCE_NAME_PREFIX}:${CIRCLE_SHA1}"
          verify-revision-is-deployed: true
          post-steps:
            - run:
                name: Test the deployment
                command: |
                  TARGET_GROUP_ARN=$(aws ecs describe-services --cluster ${AWS_RESOURCE_NAME_PREFIX}-cluster --services ${AWS_RESOURCE_NAME_PREFIX}-service | jq -r '.services[0].loadBalancers[0].targetGroupArn')
                  ELB_ARN=$(aws elbv2 describe-target-groups --target-group-arns $TARGET_GROUP_ARN | jq -r '.TargetGroups[0].LoadBalancerArns[0]')
                  ELB_DNS_NAME=$(aws elbv2 describe-load-balancers --load-balancer-arns $ELB_ARN | jq -r '.LoadBalancers[0].DNSName')
                  curl -s --retry 10 http://$ELB_DNS_NAME | grep "Welcome to nginx!"
```

<br>

ちなみに、下記は途中出てきたエラーの一部です。
<br>


1\. 環境変数の値ではなく環境変数名を入れてね、というメッセージ。`${}`部分を取り除きました。
```
Type error for argument region: expected type: env_var_name, actual value: "${AWS_DEFAULT_REGION}" (type string)
```

2\. Cluster という引数が見つからないよ、というメッセージ。`cluster_name`を`cluster`
に変えました。

```
Error calling job: 'aws-ecs/deploy-service-update'
Missing required argument(s): cluster
```
<br>


<br>
こうして、ビルド37回目にしてようやく成功しました。
こんなに Success の文字が美しく見えたことはありません。
背景の洗練されたグリーンがいい仕事してます。

![Screenshot 2023-02-03 at 14.01.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101915/081f68e2-a595-532d-fbcc-8e08336bcb25.png)



<br>

# まとめ
今回初めて、 CircleCI と AWS、そして Terraform を組み合わせたプロジェクトにトライしてみました。
ビルド37回目にしてようやく成功した背景には、CircleCIの素晴らしいエンジニアたち、Jasurさん、Kelvinさん、Jenningsさんのご指導があります。
ほんとうにありがとうございました。

次回以降もぜひ、CircleCI と AWS、Terraform を使用したプロジェクトに挑戦してみたいと思います。

CircleCIへのご質問がありましたら、[サポートセンター](https://support.circleci.com/hc/ja)までお気軽にお問い合わせください。