【初心者向け】CircleCIからAWSにデプロイしてみる

## はじめに
最近、会社の同期にcircleciを使ったCI/CDのやり方を教える機会があったので、初心者向けのはじめの一歩のための記事として残そうと思います。

## やること
今回はcircleciを利用して、terraformでAWS上にLambdaとAPIGatewayをデプロイしたいと思います。
プロジェクトは[こちらの記事](https://qiita.com/odayushin/items/1b13cc51df1482f64bfc)のものを使います。
やることは、以下の4つです。

- tfstateファイルをs3管理にするよう変更
- circleciとgithubの連携
- プロジェクトの設定
- config.ymlファイルでパイプラインの設定

## tfstateファイルをs3で管理する
チームでの開発や、circleciなどでterraformで書いたインフラをデプロイする際には、tfstateファイルをどこかプロジェクトとは別の場所に保存しておく必要があります。今回はS3を利用します。AWSコンソールからtfstateファイルを管理するバケットを作成しておいてください。私は`manage-terraform-state-oda`として作成していますので適宜読み替えてください。

[こちらの記事](https://qiita.com/odayushin/items/1b13cc51df1482f64bfc)で作成したプロジェクトに以下のtfファイルを追加します。

```terraform:terraform.tf
terraform {
  required_version = ">= 0.12.0"
  backend "s3" {
    bucket = "manage-terraform-state-oda"
    region = "ap-northeast-1"
    key = "serverless-express-app.tfstate"
    encrypt = true
  }
  required_providers {
    aws = "~> 3.0"
  }
}
```

`backend "s3"`のブロック内がtfstateの管理設定の部分です。tfstateファイルを置くS3バケットとリージョン、暗号化の設定、tfstateのファイル名を記載します。keyで指定するファイル名は他のtfstateファイルと被らないようにしておくとよいと思います。
これで、S3でtfstateファイルを管理できるようになりました。

## circleciとgithubの連携
githubのリポジトリにpushされたら、`terraform apply`や`terraform plan`などの処理が走るようにしたいので、githubとcircleciを連携させます。
1. [circleci.com](https://circleci.com/)から`Sign Up`を選択
2. `Sign Up with GitHub`を選択
3. githubのusernameとpasswordを入力してサインイン

これでgithubとcircleciの連携が完了しました。



## プロジェクトの設定
次にcircleciでプロジェクトのセットアップをします。
ログイン後の画面で左のメニューから`projects`を選択します。連携したgithubアカウントのリポジトリが表示されますので、設定したいリポジトリの行の青い`Set Up Project`を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360735/79884625-6f97-a569-db93-c67b5ec79577.png)

↓のような画面になります。何も変更せずに青い`Add Config`ボタンを押下します。セットアップが終わると自動で画面が遷移します。何かしら動き始めるかもしれませんが、今は成功/失敗は気にしなくてOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360735/09d88c91-3bef-6393-cf04-a8c87d44b638.png)

gitリポジトリを確認してみると、`circleci-project-setup`というブランチが自動で生成されています。このブランチでは`.circleci/config.yml`というファイルが生成されています。ファイルの中身は↑の画面で設定したyml形式のファイルです。このファイルでテストやデプロイの設定を行いますが、編集は後ほど実施します。
次にcircleciがterraform planやapplyする時にawsのアクセスキーが必要となるので設定しておきます。

`Project Settings`からプロジェクトの設定画面にいきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360735/a52c384f-f56e-9292-e566-5ab2ffc3e197.png)

`Environment Variables`の`Add Environment Variables`から環境変数を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360735/6bc28f60-4340-7d29-8c32-529db1c93573.png)

以下の3つの環境変数を追加します。値は自身のAWSのキーを設定してください。

- AWS_SECRET_ACCESS_KEY
- AWS_ACCESS_KEY_ID
- AWS_DEFAULT_REGION

※環境変数にシークレットキーを設定することについて
ドキュメントに以下のようにあり、仮に第三者がログインできたとしてもキーを盗むことはできないので安心して利用できると思います。
> 設定された後の変数の値は、アプリで読み取ることも編集することもできません。 環境変数の値を変更するには、現在の変数を削除し、新しい値を設定して再度追加します。

## config.ymlでパイプラインの設定
続いてパイプラインの設定を実施していきます。先ほどの`.circleci/config.yml`ファイルを編集します。

```yml:config.yml
version: 2.1
jobs:
  plan:
    working_directory: ~/work
    docker:
      - image: yushinoda/terraform_npm:latest
    steps:
      - checkout
      - run:
          name: npm install
          command: cd lambda && npm install && cd ..
      - run:
          name: Init terraform
          command: terraform init
      - run:
          name: Validate terraform
          command: terraform validate
      - run:
          name: Plan terraform
          command: terraform plan
  deploy:
    working_directory: ~/work
    docker:
      - image: yushinoda/terraform_npm:latest
    steps:
      - checkout
      - run:
          name: npm install
          command: cd lambda && npm install && cd ..
      - run:
          name: Init terraform
          command: terraform init
      - run:
          name: Apply terraform
          command: terraform apply -auto-approve
workflows:
  version: 2.1
  plan:
    jobs:
      - plan:
          filters:
            branches:
              ignore: release
  deploy:
    jobs:
      - deploy:
          filters:
            branches:
              only: release
```

今回はconfig.ymlのルールについて詳細な説明は省きます。詳しくは[リファレンス](https://circleci.com/docs/ja/2.0/configuration-reference/)を参照してください。
今回のconfig.ymlでは、jobs以下で`terraform plan`を確認するplanという名前のjobと、`terraform apply`するためのdeployという名前のjobを設定し、workflows以下で、releaseブランチにpushされた時にdeployを実行し、それ以外のブランチの時はplanを実行する設定にしています。
jobの実行環境はdockerを選択し、hashicorp/terraformイメージをベースにnpmを追加したイメージを利用してコマンドを実行しています。

編集して適当なブランチでコミットしてpushしてください。circleciのDashboardを見ると、planが動き出していると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360735/5e86985d-cbcc-708c-ebf2-cb261a27fe87.png)
緑のチェックマークがついていればそのステップは正常に完了しています。

続いて、デプロイしてみます。先ほどのブランチをreleaseブランチにpushすると動き出します。プルリクでもOKです。

```shell
$ git push origin head:release
```
今度はapplyが動いているのがわかると思います。
aws上にもしっかりapi gatewayとlambdaがデプロイされています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360735/e284f9ef-ef18-ebe0-58c9-7657f694239f.png)

以降は、`開発 -> commit&push -> plan確認 -> releaseブランチにpush -> deploy`
の流れです。必要に応じて、jobsやworkflowsに追加していけば良いと思います。

## 最後に
githubとcircleciを連携して、terraformで書いたプロジェクトをawsにデプロイしてみました。
こんなに簡単にセットアップできるのは嬉しいですね。
github actionsも興味あるので勉強したら書きたいと思います。