個人のTerraform開発環境とやらを作ってみたんだけどめっちゃいいじゃん。
— adachin👾SRE (@adachin0817) October 13, 2021
私のMacは以下よりBitBarを使ってbrew update/upgradeがあった場合、ステータスバーに表示させてワンクリックでバージョンアップをしています。そこでよくTerraformもバージョンアップしてそのまま気づかずterraform applyなどを実行してしまっているので、開発環境があればバージョンも固定されるし、デバッグもできるし、管理としてはベストなんじゃないかと思い今回構築をしてみました。
[BitBar][Homebrew]brew updateが来た時に自動でMacのステータスバーで表示したいからのupgradeもしたい
構成
開発環境
- docker
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ tree docker docker └── dev ├── README.md ├── docker-compose.yml └── terraform ├── Dockerfile └── homedir $ tree terraform terraform ├── README.md ├── env │ └── prd │ ├── do_backend.tf │ ├── do_db.tf │ ├── do_dns.tf │ ├── do_droplets.tf │ ├── do_firewall.tf │ ├── do_kubernetes.tf │ ├── do_spaces.tf │ └── variables.tf └── terraform-apply.sh |
- docker-compose.yml
1 2 3 4 5 6 7 8 9 |
version: '3' services: app: container_name: adachin-terraform-dev build: ./terraform/ image: adachin-terraform-dev volumes: - ~/git/github/hogee:/var/www/hogeeee:delegated tty: true |
- Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
FROM hashicorp/terraform:1.0.5 ENV APP_ROOT /var/www/xxxxxxx WORKDIR $APP_ROOT # Setup UTC+9 RUN apk --update add tzdata && \ cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ apk del tzdata && \ rm -rf /var/cache/apk/* # install packages RUN apk update && \ apk upgrade && \ apk add --update --no-cache \ bash \ vim # copy token COPY homedir/.terraformrc /root/.terraformrc ENTRYPOINT ["/bin/bash"] |
まずは開発環境から説明してきましょう。TerraformはDocker hub公式でコンテナが用意されているので現状のバージョンと同じ1.0.5を利用しました。またTerraformはAPI経由での実行なので特にPortも開ける必要がありません。(ちなみにTerraformのImageはAlpine Linuxでした)
Terraform Cloudを利用しているので、利用するAPI Keyはgitignoreしてコンテナ内コピーするようにしました。ここらへんAWSだとKMS使って暗号化するべきですね。あとはdocker execでログインしてterraform initとplanやらapplyできれば完了です。物凄くシンプル。開発環境はこんなところです。次はCircleCIでのTerraform CI/CDに課題があったので、少し変更してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
$ docker exec -it adachin-terraform-dev bash bash-5.1# cat /etc/os-release NAME="Alpine Linux" ID=alpine VERSION_ID=3.14.1 PRETTY_NAME="Alpine Linux v3.14" HOME_URL="https://alpinelinux.org/" BUG_REPORT_URL="https://bugs.alpinelinux.org/" bash-5.1# terraform init Initializing the backend... Initializing provider plugins... - Reusing previous version of digitalocean/digitalocean from the dependency lock file - Reusing previous version of hashicorp/kubernetes from the dependency lock file - Using previously-installed digitalocean/digitalocean v2.11.1 - Using previously-installed hashicorp/kubernetes v2.4.1 Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. |
Terraform CI/CD
例えば設定ファイルに差分があった場合にmasterマージでapplyでいいじゃんと思いきや、こちら側でterraformデバッグして元に戻るというのがあるからやっぱ自動化するのやめましょう。
— adachin👾SRE (@adachin0817) October 13, 2021
以前CircleCIでTerraformのCI/CD環境を実装しました。(上記ブログにて)TerraformのCI(validateやplan)は物凄く重宝しているのですが、Ansible等修正で毎回masterマージでterraform applyされてしまうので非常にリスクもありますし事故ります。まあapplyなんてローカルや開発環境で実行すればいいじゃん〜と思いますが、なるべく他の人でも修正してCircleCIで任意のタイミングでapplyできるような環境を作りたかったというのが目的です。(自分ひとりですがね..草)
なのでどうすればいいのか考えたところ!CircleCIのManual Approvalで承認してからapplyすればいいじゃんというのもありましたが、結局その過程と承認するのがめんどくさかったのと特に運用は変わらないので不採用になりました。なので!
そうか。circleciのapi経由でapply実行すればいいんだ。そうすれば適用したいときに誰でも実行可能だし。
— adachin👾SRE (@adachin0817) October 13, 2021
以前ブログでも書きましたが、CircleCIのAPIを利用してシェルでapplyできるようにすれば任意のタイミングで実行できるし良さそうとのことで実装してみました。
- terraform-apply.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#!/bin/bash BRANCHNAME=$1 url="https://hooks.slack.com/services/xxxxxxxxxx" username='Prd-terraform' to="ci_cd" subject='Prd terraform applyを開始しました:hammer_and_wrench:' color="#0000FF" message="https://app.circleci.com/pipelines/github/RVIRUS0817/xxxxxxxxx" help() { echo " 下記のようにブランチを指定して実行してください。 (例) ~/git/github/xxxxxxxxx/terraform/terraform-apply.sh ブランチ名 " } if [ $# -ne 1 ];then help exit fi curl -u xxxxxxxxxxxxxxxx: -X POST --header "Content-Type: application/json" -d '{ "branch": "'"${BRANCHNAME}"'", "parameters": { "terraform_apply": true } }' https://circleci.com/api/v2/project/github/RVIRUS0817/xxxxxxxxxxx/pipeline echo " ブランチ名/ "${BRANCHNAME}" のPrd terraform applyを開始しました。 #ci_cdにて確認しましょう。 " payload="payload={ \"channel\": \"${to}\", \"username\": \"${username}\", \"text\": \"${subject}\", \"attachments\": [ { \"color\" : \"${color}\", \"text\" : \"${message}\", } ] }" curl -m 5 --data-urlencode "${payload}" ${url} |
- .circleci/config.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
version: 2.1 orbs: slack: circleci/slack@3.4.2 parameters: terraform_apply: type: boolean default: false references: default_config: &default_config docker: - image: hashicorp/terraform:1.0.5 working_directory: ~/project environment: TERRAFORM_ENV: ~/project/ ~省略~ terraform_apply: <<: *default_config steps: - *restore_repo - *set_terraform_environment - *terraform_init - run: name: terraform apply command: | apk add bash curl jq cd ~/project/terraform/env/prd terraform apply -auto-approve - slack/status: fail_only: true mentions: 'here' failure_message: 'Error terraform apply 🚨 \n :innocent: ${CIRCLE_USERNAME} :branch: ${CIRCLE_BRANCH}' webhook: ${SLACK_WEBHOOK} - slack/notify: title: 👍 color: '#42f486' message: 'terraform apply OK ✨ \n :grin: ${CIRCLE_USERNAME} :branch: ${CIRCLE_BRANCH}' webhook: ${SLACK_WEBHOOK} workflows: version: 2.1 terraform_ci: jobs: - terraform_fmt_validate - terraform_plan: requires: - terraform_fmt_validate terraform_apply: when: << pipeline.parameters.terraform_apply >> jobs: - terraform_apply |
- 実行
1 2 3 4 5 6 7 8 9 10 11 |
$ ./terraform-apply.sh fix_circleci-terraformapply { "number" : 115, "state" : "pending", "id" : "79b8e027-207f-4560-8b4e-245bb24137c0", "created_at" : "2021-10-14T07:12:23.849Z" } ブランチ名/ fix_circleci-terraformapply のPrd terraform applyを開始しました。 #ci_cdにて確認しましょう。 ok |
これでmasterマージはterraform validateとplanしか実行されず、シェルでブランチ名の指定、もしくはmasterを引数で指定して実行することによって好きなタイミングでterraform applyを実行することができました。
まとめ
開発環境を作ることでわざわざローカルにTerraformをインストールしなくても済みますし、WIndowsでDockerを利用している方も複数でも簡単に開発ができる環境が整いました。またapplyも実行する環境にとらわれず適用できる環境も整ったので満足です。
次回はAWSでの場合を実装してみたいと思います!むしろもっと他にいい運用方法あれば教えて下さい!!
※追記
GitHub ActionsでAnsibleとTerraform用にそれぞれファイルをわけてpathsでディレクトリ名を書いてあげれば、Ansibleが変更あった時はTerraformは適用されないとかできるよー。
— Inamuu🏕 (@kzm0211) October 14, 2021
CircleCI path-filteringを利用して差分があればapplyみたいなこともできるみたいです。ここは後で試してみよう。しかもOrbsでTerraform CI/CD対応しているのも知らなかったのでこっちに移行したほうが良さそうですね。
https://circleci.com/developer/orbs/orb/circleci/terraform
https://t.co/8axN60m3mn
terraformのorbsあったのか!
知らなかった…こっちに移行してみよう。— adachin👾SRE (@adachin0817) October 14, 2021
※追記
APIだと誰でもapply出来てしまうのでpath-filteringを利用しましょう!
[CircleCI][Orbs][path-filtering]特定ディレクトリに差分が出たらterraform applyを適用するように実装してみた
0件のコメント