[GitHub Actions] Terraform実行基盤の共通化
今更ながらPS4版ドラゴンクエスト11sクリアしました。
想像以上に面白かったですね。
ファミコン版ドラゴンクエスト3からプレイしている私としては
技術の進歩を感じます。
本題
弊社ではTerraformの実行をGitHubActionsで行っています。
PullRequestを作成したらDryRunが行われ、変更内容をPullRequestのコメントに追記、
マージされたら反映するようにしています。
Terraformでの各環境の管理はディレクトリで分けています。
- 構成イメージ
terraform/
├── README.md
├── environments
│ ├── common
│ ├── development
│ ├── production
│ └── staging
├── modules
└── vpc
課題
上記構成でそれぞれ専用のymlを準備して運用していましたが、
変数やPullRequestの作成時のブランチの違いのみで
Version情報などを更新するときに複数ファイルに対し同じ変更を
行うといった冗長な作業が発生していました。
そのため共通部分は別のymlに切り出して運用するようにしました。
ymlの作成
まずは共通部分のymlを作成します。
実行するための前提条件として
OIDC用のIAM Roleの作成とSlack通知を行うためIncoming Webhook URLが必要ですが、
本記事では割愛します。
runs-onの箇所でubuntu-latest
を指定していますが、
ARM版で実行する場合はwgetで取得しているURLを以下に変更する必要があります。
https://github.com/suzuki-shunsuke/tfcmt/releases/download/${TFCMT_VERSION}/tfcmt_linux_arm64.tar.gz
前提条件
-
AWSのGitHubActions用のIAM Roleの作成済であること
-
作成したIAM RoleをGitHubActionsのGitHubのSecretsに
AWS_ROLE_ARN
として登録していること -
SlackのIncoming Webhook URLをGitHubのSecretsに
SLACK_WEBHOOK_URL
として登録していること -
terraform_shared.yml
name: "Terraform(Shared)"
on:
workflow_call:
inputs:
MY_ENV_DIRCTORY:
description: "環境ディレクトリ"
required: true
default: "default"
type: string
secrets:
AWS_ROLE_ARN:
description: 'AWS IAM ROLE ARN'
required: true
SLACK_WEBHOOK_URL:
description: 'Slack Webhook URL'
required: true
env:
SLACK_USERNAME: GitHubActions
SLACK_CHANNEL: slack-channel-name
SLACK_ICON: https://octodex.github.com/images/Robotocat.png
ENV_DIRCTORY: ${{ inputs.MY_ENV_DIRCTORY }}
permissions:
id-token: write
contents: read
pull-requests: write
jobs:
terraform_share:
name: "TerraformCI(Shared)"
runs-on: ubuntu-latest
# Use the Bash shell regardless whether the GitHub Actions runner is ubuntu-latest, macos-latest, or windows-latest
defaults:
run:
shell: bash
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- name: setup tfcmt
env:
TFCMT_VERSION: v4.10.0
run: |
wget "https://github.com/suzuki-shunsuke/tfcmt/releases/download/${TFCMT_VERSION}/tfcmt_linux_amd64.tar.gz" -O /tmp/tfcmt.tar.gz
tar xzf /tmp/tfcmt.tar.gz -C /tmp
mv /tmp/tfcmt /usr/local/bin
tfcmt --version
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.9.1
# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
- name: Terraform Init
run: terraform -chdir=terraform/environments/$ENV_DIRCTORY init -upgrade
# Checks that all Terraform configuration files adhere to a canonical format
- name: Terraform Format
run: terraform -chdir=terraform/environments/$ENV_DIRCTORY fmt -check
# Generates an execution plan for Terraform
- name: Terraform Plan
run: |
tfcmt plan -patch=false -- terraform -chdir=terraform/environments/$ENV_DIRCTORY plan -no-color -input=false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.number }}
- name: Terraform Apply
if: (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/main') && github.event.pull_request.merged == true
run: |
tfcmt plan -patch=false -- terraform -chdir=terraform/environments/$ENV_DIRCTORY apply -auto-approve -no-color -input=false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.number }}
#-- Slack通知 --#
# 成功
- name: Slack Notification on Success
if: ${{ success() }}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_TITLE: Deploy Success
SLACK_COLOR: good
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
# 失敗
- name: Slack Notification on Failure
if: ${{ failure() }}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_TITLE: Deploy Failure
SLACK_COLOR: danger
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
続いて共有ymlを呼び出すymlを作成します。
- terraform_development.yml
name: "Terraform(Deployment)"
on:
pull_request:
branches:
- develop
types: [opened, synchronize, reopened, closed]
paths:
- "terraform/environments/development/*.tf"
- ".github/workflows/terraform_shared.yml"
- ".github/workflows/terraform_development.yml"
workflow_dispatch:
jobs:
deploy-tf:
uses: ./.github/workflows/terraform_shared.yml
with:
MY_ENV_DIRCTORY: development
secrets:
AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
仕様解説
- develop or main branchにマージされたときのみApply(反映)を行う
- 本ケースはdevelopブランチにマージされたときのみにトリガーしてほしいのでdevelopブランチのみ。
- developmentディレクトリのtfファイルが変更されたときにもトリガーする。
- 合わせてterraform_shared.ymlとterraform_development.ymlが変更されたときにもトリガーする。
- 成功/失敗時にSlack通知を行う。
まとめ
最初のほうはymlの数も少なく運用コストは低かったのですが、
GitHubActions化を進めていくにあたり、
ymlの数が増えてきて運用負荷が増加傾向にあったため、
少しでも運用コストが下げれればという思いから本施策を実施しています。
terraformのバージョンを上げるとなった場合でも一つの箇所の修正だけで
良くなったため、運用効率は上がったと感じています。
現状は全環境のインフラに対しCI/CDへの取り組みは道半ばでもあり、
引き続き運用効率化に取り組んでいきたいと思います。
Discussion