July 29, 2020
CircleCIで $ terraform [fmt or plan or apply or destroy]
を自動化したのでまとめていきたいと思います。
目次
1.Terraformが実行できるDockerイメージを作成する。
2.【CircleCI】プロジェクトを作成する。
3.【CircleCI】AWS認証情報を環境変数に設定する。
4.【CircleCI】Slack通知を設定する。
5.【CircleCI】Terraformが実行できるように設定ファイルを編集する。
6.【CircleCI】実行結果を確認する。
7.まとめ
今回、TerraformはDokcerイメージから実行します。そのイメージを作成するのに必要な Dockerfile
と docker-compose.yml
を解説していきます。
ファイル構成
.circleci
Dockerfile
docker-compose.yml
src/
|-- terraform/ # ⇐ここにTerraformコードを入れていく。
|-- iam/
|-- env/dev/main.tf
|-- modules/main.tf
Dockerfile
FROM ubuntu:latest
# AWS認証情報を環境変数。(docker-compose.yml経由で渡す。)
ARG REGION
ARG AWS_ACCESS_KEY_ID
ARG AWS_SECRET_ACCESS_KEY
# 作業用ディレクトリ
WORKDIR /var/tmp
# 各種ツールをインストール。
RUN apt-get update && \
apt-get install -y wget \
unzip \
less \
jq \
ssh &&\
# Terraformのセットアップ
wget "https://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_linux_amd64.zip" && \
unzip terraform_0.12.24_linux_amd64.zip && \
mv terraform /usr/local/bin/ && \
# AWS CLIのセットアップ。
wget "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" && \
unzip awscli-exe-linux-x86_64.zip && \
./aws/install && \
# 不要なZIPファイルを削除。
rm -f terraform_0.12.24_linux_amd64.zip \
awscli-exe-linux-x86_64.zip
# AWS認証ファイルの準備。
COPY config /root/.aws/config
COPY credentials /root/.aws/credentials
# AWS認証ファイルの値を正式なキーに変換。
RUN sed -i "s/REGION/${REGION}/g" /root/.aws/config && \
sed -i "s/AWS_ACCESS_KEY_ID/${AWS_ACCESS_KEY_ID}/g" /root/.aws/credentials && \
sed -i "s/AWS_SECRET_ACCESS_KEY/${AWS_SECRET_ACCESS_KEY}/g" /root/.aws/credentials
docker-compose.yml
version: '2'
services:
app:
build:
context: .
args:
# AWS認証情報をCircleCIに設定した環境変数から設定する。
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
- REGION=${REGION}
# 作成されるイメージ名を設定する。
image: terraform_for_aws
volumes:
- ./src:/infra
それでは、CircleCIの設定を行っていきます。まずは、Terraformを実行するためのプロジェクトを作成からです。
※CircleCI にログインして下記を行う。
① 実行するリポジトリの「Set Up Project」をクリックして、プロジェクトを作成する。
② 「Add Config」をクリックして、CircleCIの設定ファイルを自動で作成する。
③ パイプラインが自動実行される。(特に気にしなくて大丈夫です。)
以上でプロジェクトの作成は完了です。
TerraformでAWSリソースを作成するために、AWS認証情報をDockerイメージに埋め込む必要があります。
今回は、CircleCIの環境変数から設定するため、認証情報を登録していきます。
② AWS認証情報を環境変数に設定する。
設定する変数は全部で3つ。
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- REGION
以上環境変数の設定が完了です。ここで設定した値が、Dockerイメージのビルド時に自動的に組み込まれるようになります。
以下が実行する一連の処理になります。
それではコードを解説していきます。
.circleci/config.yml
version: 2.1
orbs:
# ジョブの結果をSlackに通知したいため。
slack: circleci/slack@3.4.2
jobs:
# Dockerイメージをビルドするジョブ。
build:
# CircleCIのデフォルトイメージを使用するため、「true」に設定する。
# 今回は、デフォルトイメージの中でDockerイメージを作成していく。
machine: true
steps:
# ソースのチェックアウト。
- checkout
# Dockerイメージをキャッシュからリストアする。
- restore_cache:
# キャッシュは、「docker-compose.yml」、「Dockerfile」のそれぞれのチェックサム値で保存されている。そのため、もしそれぞれのファイルが変更されているとチェックサム値も変更されてしまい、リストアされず後続のビルド処理が走ることになる。
key: docker-{{checksum "docker-compose.yml"}}-{{checksum "Dockerfile"}}
paths: ~/images.tar
# キャッシュからリストアされていない場合に、Dockerのイメージファイルを作成する。
- run:
name: docker image build & save
# 1.AWS認証情報をイメージ内で使用できる環境変数に設定する。
# 2.イメージファイルがキャッシュからリストアチェックされていないか確認する。存在していない場合はイメージを作成して、それをファイルに保存する。
command: |
echo "export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}" >> $BASH_ENV
echo "export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}" >> $BASH_ENV
if [ ! -f ~/images.tar ];then
docker-compose build
docker save terraform_for_aws -o ~/images.tar terraform_for_aws:latest
fi
# DockerのイメージファイルをCircleCIにキャッシュする。
- save_cache:
key: docker-{{checksum "docker-compose.yml"}}-{{checksum "Dockerfile"}}
paths: ~/images.tar
# terraform fmt & plan を実行するジョブ。
test:
machine: true
steps:
- checkout
- restore_cache:
key: docker-{{checksum "docker-compose.yml"}}-{{checksum "Dockerfile"}}
paths: ~/images.tar
# Dockerイメージファイルからイメージをロードする。
- run: docker load -i ~/images.tar
# AWS認証情報を環境変数に設定する。
- run:
name: set aws credential to BASH_ENV
command: |
echo "export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}" >> $BASH_ENV
echo "export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}" >> $BASH_ENV
- run:
name: terraform fmt
command: docker-compose run --rm app /bin/bash -c "terraform fmt -recursive /infra"
- run:
name: terraform init
command: |
docker-compose run --rm app /bin/bash -c "cd /infra/terraform/iam/env/dev && terraform init"
- run:
name: terraform plan iam
command: docker-compose run --rm app /bin/bash -c "cd /infra/terraform/iam/env/dev && terraform plan"
# Slackへの通知。
- slack/status:
success_message: "[SUCCESS]: ${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BRANCH} terraform plan が成功しました。"
failure_message: "[ERROR]: ${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BRANCH} terraform plan が失敗しました。"
# SlackのWebHookのURLを環境変数から設定する。
webhook: ${SLACK_WEBHOOK}
# terraform apply を実行するジョブ。
apply:
machine: true
steps:
- checkout
- restore_cache:
key: docker-{{checksum "docker-compose.yml"}}-{{checksum "Dockerfile"}}
paths: ~/images.tar
- run: docker load -i ~/images.tar
- run:
name: set aws credential to BASH_ENV
command: |
echo "export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}" >> $BASH_ENV
echo "export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}" >> $BASH_ENV
- run:
name: terraform init
command: |
docker-compose run --rm app /bin/bash -c "cd /infra/terraform/iam/env/dev && terraform init"
- run:
name: terraform apply
command: docker-compose run --rm app /bin/bash -c "cd /infra/terraform/iam/env/dev && terraform apply -auto-approve"
- slack/status:
success_message: "[SUCCESS]: ${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BRANCH} terraform apply が成功しました。"
failure_message: "[ERROR]: ${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BRANCH} terraform apply が失敗しました。"
webhook: ${SLACK_WEBHOOK}
# terraform apply を実行するジョブ。
destroy:
machine: true
steps:
- checkout
- restore_cache:
key: docker-{{checksum "docker-compose.yml"}}-{{checksum "Dockerfile"}}
paths: ~/images.tar
- run: docker load -i ~/images.tar
- run:
name: set aws credential to BASH_ENV
command: |
echo "export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}" >> $BASH_ENV
echo "export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}" >> $BASH_ENV
- run:
name: terraform init
command: |
docker-compose run --rm app /bin/bash -c "cd /infra/terraform/iam/env/dev && terraform init"
- run:
name: terraform destroy
command: docker-compose run --rm app /bin/bash -c "cd /infra/terraform/iam/env/dev && terraform destroy -auto-approve"
- slack/status:
success_message: "[SUCCESS]: ${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BRANCH} terraform destroy が成功しました。"
failure_message: "[ERROR]: ${CIRCLE_PROJECT_REPONAME}/${CIRCLE_BRANCH} terraform destroy が失敗しました。"
webhook: ${SLACK_WEBHOOK}
# 上記で設定してきたジョブの順番を設定していく。
workflows:
terraform:
jobs:
- build
- test:
requires:
- build
- apply:
requires:
- test
# masterブランチのみで実行する。
filters:
branches:
only:
- master
# destroyジョブは承認された場合のみ実行するための設定。(※1)
- hold:
type: approval
requires:
- apply
# masterブランチのみで実行する。
filters:
branches:
only:
- master
- destroy:
requires:
- hold
# masterブランチのみで実行する。
filters:
branches:
only:
- master
※1 一時的にジョブを停止する方法をちょっと解説
下記がブランチ(画像はmasterブランチ)にpushされ、CircleCIのジョブが実行された時の画像です。
まだまだ改善できますが、最低限の実装はできたかなーと思います。これをベースに色々カスタマイズしていきたいと思います。