tfaction導入のお話
※この記事は、Luup Advent Calendar の18日目の記事です。
最初に
こんにちは、Luup SREチームの中西(@sonic883b)です。
今回は Github Action 上で terraform Workflow を行う tfactionを導入したお話となります。
背景
LUUP でのインフラはAWS、GCPを利用しています。
SREチームの設立以来からインフラのコード化(IaC)を目標として掲げており
各メンバーが terraform による新規リソースの構築と既存リソースのインポートを実施しています。
この時、複数人が terraform による操作、変更する場合は以下の懸念点があります。
- 各個人環境で
terraform plan / apply
を実行する必要がある- 作業タイミングによっては terraform の state と実際のリソース設定の乖離
Configuration Drift
が発生する
- 作業タイミングによっては terraform の state と実際のリソース設定の乖離
- AWS、GCPの認証情報もメンバの作業端末で設定する必要がある(認証情報の漏れ等のリスク)
チーム内での相談の結果、解決策として CI/CDでのワークフローの導入をすることとなりました。
DesignDoc の作成
まずは要件や運用方針をまとめた DesignDoc を作成しチーム内に共有しました。
以下は一部抜粋となります。
要件
- CI/CDワークフローを導入して手動デプロイによるヒューマンエラーを防止する
- terrform の変更履歴の記録や参照ができている
- 以下のような Gitops でのworkflow を実行する
運用方針
- terrform の remote state ファイルは各クラウドベンダのストレージで保管する
- s3 またはGCSに設定するバケット名や prefix は以下とする
- Bucket:terraform-backend-<AWS_account_number,GCP_project>
- prefix(保存ファイル名): state/{dev,prod}/<project-name>/terraform.tfstate
tfaction について
suzuki-shunsukeさんが作成なさった OSS となります。
以前から terraform での CI/CD実行ができるツールについて調査は行っていて
個人的にも利用してみたいこともあり、SREチームに提案、相談を行って導入させて頂く事となりました。
導入、選定の理由としては tfaction の要件が Luup での terraform workflow の要件(Monorepo,Github Actions)に最適であった為です
tfaction の要件
- GitHub Flow
- branch は default branch と feature branch だけ
default branch から feature branch を作成し、 feature branch から default branch に PR を作成
Pull Request の CI で terraform plan などを実行
Pull Request を default branch にマージしたら terraform apply が実行される- Monorepo
- 一つのリポジトリで複数の Terraform Working Directory (State) を管理
- GitHub Actions
- GitHub Actions で Terraform を実行する
- AWS Account
- S3 に plan file や tfmigrate の history を保存
- 依存するツールは aqua で管理
- tfaction は tflint や tfsec, Conftest など様々なツールに依存しているが、それらは aqua でバージョン管理する
Renovate による継続的 update
導入前の検証
大変ありがたいことに tfaction-getting-started というチュートリアルを用意されてます。
また、tfaction-example というサンプルレポジトリに導入ガイド、ドキュメントもあります。
上記の資料を元に検証環境(GitHubレポジトリ、AWS、GCP)で設定方法の理解や動作確認ができました。
LUUPでのtfactionの構成
基本的に tfaction-getting-started のディレクトリー構成を参考にしています。
- 各環境のtfファイルは terraform 配下に配置
- AWS、GCP と分けてProduction 、Devのプロダクトのステージ毎に分ける
- tfmigrate は各環境毎に配置
- tfaction-root.yaml で環境ごとの設定を記入
- template に関しては設定したが現状は機能しておらず今後確認をしていく予定
.
├── aqua
├── aqua.yaml
├── templates
│ ├── aws
│ │ ├── dev
│ │ └── prod
│ └── gcp
│ ├── dev
│ └── prod
├── terraform
│ ├── aws
│ │ |── dev
│ │ | ├── project-A
│ │ | └── project-B
│ │ └── prod
│ │ ├── project-A
│ │ └── project-B
| │ └── tfmigrate
│ └── gcp
│ |── dev
│ | ├── project-A
│ | └── project-B
│ └── prod
│ ├── project-A
│ └── project-B
| └── tfmigrate
└── tfaction-root.yaml
tfmigrate について
minamijoyoさんが作成したOSSになります。
terraform の state 操作の作業が楽になるのとgithub 上でのコミットの管理ができます。
tfaction は tfmigrate の実行に対応してるので各環境で tfmigrate のファイルを保存して
ドキュメントの通り Pull Request で Label を設定すれば
workflow 上で tfmigrate の plan/apply が実行されるようになります。
- tfmigrate.hcl のサンプル
migration "state" "mv_gcs_test01_to_02" {
dir = "../gcs-test"
actions = [
"mv google_storage_bucket.test07 google_storage_bucket.test02"
]
}
導入で苦労した点
AWSに関してはドキュメント等にも設定事例があり特に躓いた点はありませんでした。
GCP に関しては自分の設定の不備や workflow でのエラーが発生していたので調査、対応しました。
GCPの 認証周りについて
現状は Service Account の設定を Github secret に設定しています。
導入当初からworkload identity の設定はしたのですが state ファイルがGCSにアップロードできない
エラーが発生していて一旦 Service Account を設定する方針としました。
gsutil authentication
If you configure gcs_bucket_name_plan_file, tfaction stores Terraform Plan files at Google Cloud Storage with gsutil. gsutil doesn't support Workload Identity Federation yet, so you have to use traditional service account key authentication.
https://cloud.google.com/storage/docs/authentication
https://github.com/google-github-actions/auth#authenticating-via-workload-identity-federation
The bq and gsutil tools do no currently support Workload Identity Federation! You will need to use traditional service account key authentication for now.
原因は導入当初 tfactionv0.5.7
を使用しており gsutil が workload identity
をサポートしていないことでした。
v0.5.15
以降だと gcloud sdk の最新版をインストールするとの事で
tfaction のバージョンアップと workload identity の設定の対応する予定です。
tfmigrate での設定追加
以下の内容で対応しました。
- aqua で tfmigrate v0.3.7以上をインストール
v0.3.7 から Support GCS as a history storage
となったので v0.3.9
をインストールする様に aqua の設定ファイルに追加しました。
aqua/tfmigrate.yaml
packages:
- name: minamijoyo/tfmigrate@v0.3.9
- tfmigrate-plan / apply に GCP認証の step を追加
tfaction での Github Actions の設定でGCP の認証設定が必要でしたので追加しました。
※別途対応方法があるかもしれませんが現状は以下の設定で行ってます
.gitnub/workflows/test.yaml
tfmigrate-plan:
(**snip**)
- uses: suzuki-shunsuke/tfaction/test@v0.5.18
with:
github_app_token: ${{ steps.generate_token.outputs.token }}
### 追加
- name: Authenticate to google cloud platform
if: ${{ env.GOOGLE_CREDENTIALS != '' }}
uses: google-github-actions/auth@v0
with:
credentials_json: ${{ env.GOOGLE_CREDENTIALS }}
create_credentials_file: 'true'
### 追加
- uses: suzuki-shunsuke/tfaction/tfmigrate-plan@v0.5.18
with:
github_app_token: ${{ steps.generate_token.outputs.token }}
最後に
tfaction を導入することによってterraform workflow の構築ができました。
また tfmigrate によって terraform import や state の作業が無事にできるようになりました。
お陰様で開発効率が上がり、今後のインフラリソース追加や既存リソースのimport作業がスムーズに行えそうです。
素晴らしいツールを作成して頂いた作者の皆様にお礼申し上げます。
最後までお読み頂き、ありがとうございました。
Discussion
どうも。 tfaction の作者です。 tfaction を導入・ご紹介いただきありがとうございます。
開発効率が上がったとのことで何よりです。
tfaction に関してなにかわからない点などありましたら気軽に聞いてください。
これは何でしょうね?調べてもわからなかったら聞いてください。
最新の tfaction であれば内部で
google-github-actions/auth
を実行しているので不要な気がします。コメントありがとうございます。
お陰様でメンバ間での terraform のやりとりが楽になりました。
template に関しては自分の設定の不備な気がするので確認していきますね
ありがとうございます。template の件も併せて tfaction を最新にしてから修正していこうと思います