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


はじめに

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

やること

今回はcircleciを利用して、terraformでAWS上にLambdaとAPIGatewayをデプロイしたいと思います。
プロジェクトはこちらの記事のものを使います。
やることは、以下の4つです。

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

tfstateファイルをs3で管理する

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

こちらの記事で作成したプロジェクトに以下のtfファイルを追加します。

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 applyterraform planなどの処理が走るようにしたいので、githubとcircleciを連携させます。
1. circleci.comからSign Upを選択
2. Sign Up with GitHubを選択
3. githubのusernameとpasswordを入力してサインイン

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

プロジェクトの設定

次にcircleciでプロジェクトのセットアップをします。
ログイン後の画面で左のメニューからprojectsを選択します。連携したgithubアカウントのリポジトリが表示されますので、設定したいリポジトリの行の青いSet Up Projectを押下します。

↓のような画面になります。何も変更せずに青いAdd Configボタンを押下します。セットアップが終わると自動で画面が遷移します。何かしら動き始めるかもしれませんが、今は成功/失敗は気にしなくてOKです。

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

Project Settingsからプロジェクトの設定画面にいきます。

Environment VariablesAdd Environment Variablesから環境変数を追加します。

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

  • AWS_SECRET_ACCESS_KEY
  • AWS_ACCESS_KEY_ID
  • AWS_DEFAULT_REGION

※環境変数にシークレットキーを設定することについて
ドキュメントに以下のようにあり、仮に第三者がログインできたとしてもキーを盗むことはできないので安心して利用できると思います。

設定された後の変数の値は、アプリで読み取ることも編集することもできません。 環境変数の値を変更するには、現在の変数を削除し、新しい値を設定して再度追加します。

config.ymlでパイプラインの設定

続いてパイプラインの設定を実施していきます。先ほどの.circleci/config.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のルールについて詳細な説明は省きます。詳しくはリファレンスを参照してください。
今回の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が動き出していると思います。

緑のチェックマークがついていればそのステップは正常に完了しています。

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

$ git push origin head:release

今度はapplyが動いているのがわかると思います。
aws上にもしっかりapi gatewayとlambdaがデプロイされています。

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

最後に

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