Terraformで管理しているインフラのデプロイを自動化する


はじめに

こんにちわ。Wano株式会社エンジニアのnariです。
今回は、GitFlowを利用して、CodeBuildで実行するCI上でterraformリソースをチェック/デプロイする仕組みをつくったのでその備忘録を残しておこうと思います。

システム全体像

何故作ろうと思ったか

  • オペレーションの履歴をslack上に残しておきたかった
  • 本番環境は、レビューチェック後そのままdeployされるようにしたかった
  • 運用は他のチームに引き継ぐことになっているので、オペレーションはなるべく簡素にしたかった

懸念点

  • 以前の記事のように、コンポーネント(tfstate)を分割して管理しているので、全部いちいちplanやapplyしていたら通知も煩雑になり、実行時間も長くなりそう
    • CI(テスト)時に使っていたbuild imageがあるのでそれさえ解決できればすぐに構築できそう

どう懸念点を改善したか

  • 以下の記事をかなり参考にし、コードの差分のあるディレクトリのみでplan/applyを実行するようにした
    Terraform どこで実行していますか? - mixi developers - Medium
  • 上記の記事と違うのは、buildフェイズで走らせるrun.shでのplanとapplyの分岐を、branchの名前で実現したところ
    • ブランチ名がplanで始まる場合plan そうではない場合はapplyを実行する
run.sh

#!/bin/sh -xe
if echo $USER_BRANCH | grep -q 'plan/'; then
  /bin/sh script/tf_ci/plan.sh
else
  /bin/sh script/tf_ci/apply.sh
fi
  • コマンド操作とuserを結びつけたかったのでmessageにuserの項目を追加 projectURLも追加
  • ディレクトリで各環境を管理しているため、stage環境ならprodディレクトリを無視、prod環境ならstageディレクトリを無視する形でコマンドを実行する
  • lambda系のリソースはeventsディレクトリ以下にてapexで管理しているため、eventsディレクトリではapexコマンドを打つように変更
plan.sh

#!/bin/sh -xe
if [ $ENV = "stage" ]; then
    export EXCLUDE_ENV="prod"
elif [ $ENV = "prod" ]; then
    export EXCLUDE_ENV="stage"
fi

export EXCLUDE_DIRS='^\.|script|server_src|resources|playground|env|dockerfiles|modules|fluentd|nginx|test_ci_conf|tf_ci_conf|events|'$EXCLUDE_ENV
echo $EXCLUDE_DIRS
DIRS=$(git --no-pager diff origin/master..HEAD --name-only | xargs -I {} dirname {} | egrep -v "$EXCLUDE_DIRS" | uniq)
if [ -z "$DIRS" ]; then
  echo "No directories for plan."
  exit 0
fi

BUILD_URL="https://ap-northeast-1.console.aws.amazon.com/codesuite/codebuild/projects/${USER_CODEBUILD_PROJECT_NAME}/build/${CODEBUILD_BUILD_ID}"
for dir in $DIRS
do
  if [[ "`echo $dir | grep events`" ]] ;then
    echo "events"
    (cd $dir && cd ../ && apex deploy)
    (cd $dir && cd ../ && apex infra init -input=false -no-color)
    (cd $dir && cd ../ && apex infra plan -input=false -no-color | tfnotify --config ${REPOSITORY_ROOT}/${ENV}_tfnotify.yaml plan --message "dir : $dir  user : $USER_AUTHOR console : $BUILD_URL")
  else
    (cd $dir && terragrunt init -input=false -no-color)
    (cd $dir && terragrunt plan -input=false -no-color | tfnotify --config ${REPOSITORY_ROOT}/${ENV}_tfnotify.yaml plan --message "dir : $dir  user : $USER_AUTHOR console : $BUILD_URL")
  fi
done



今後の展望

  • slack上でCI kickから結果確認まで完結させたい
  • 差分のみplanといえど、バラバラにコンポーネントそれぞれの通知がきてしまうので、そこを統合したい

参考文献