githubのCIとterraformを使ってGCPにデプロイする
はじめに
業務でよくterraformを使っている。
0から構築する場合、どうしているのかが気になったので、整理しつつ実装した。
流れ
- GithubActionの設定
- tfstate用のバケットを準備
- tfstateファイルの場所の設定
- デプロイとロックについて
ディレクトリ構成は下記のようになる
├── .github
│ └── workflows
│ └── run.yaml
├── .gitignore
├── accounts.tf
└── backend.tf
GithubActionの設定
GCPのIAMからサービスアカウントの作成・サービスアカウントキーの発行を行う。
その後、サービスアカウントのクレデンシャルをgithubのsecretに登録する。
GithubActionの設定を書く。
name: 'Deploy'
on:
push:
branches:
- main
pull_request:
jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
- name: Terraform Init
run: terraform init
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
- name: Terraform Format
run: terraform fmt -check
- name: Terraform Plan
run: terraform plan
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
tfstate用のバケットを準備
tfstateファイルはterraformが管理しているリソースの現在の状態を表すファイルになる。
GCSの情報を設定する。
provider "google" {
project = "PROJECT_ID"
}
terraform の.tfstate用のバケットを作成する。
resource "google_storage_bucket" "RESOURCE_NAME" {
name = "BUCKET-NAME"
location = "us-central1"
storage_class = "REGIONAL"
versioning {
enabled = true
}
lifecycle_rule {
action {
type = "Delete"
}
condition {
num_newer_versions = 5
}
}
}
そして、mainにpushを行うと、CIが走る。
CIによって、バケットが作成されている
tfstateファイルの場所の設定
terraformのstateファイルの保存場所を指定する。
provider "google" {
project = "PROJECT_ID"
}
+ terraform {
+ backend "gcs" {
+ bucket = "BUCKET-NAME"
+ prefix = "terraform/state"
+ }
+ }
terraform importを使って、既存リソースをterraformに取り込むために、githubActionに追記する・
バケットの作成とtfstateファイルの指定は同時にはできず、まずバケットを作成する必要がある。
その際に、作成されたtfstateファイルは破棄されている。terraform importを使わないと、GCSバケットは存在するが、tfstate的には存在しないことになっているので、無理やり作成しようとしてコンフリクトが発生する。そのため、既存のリソースを取り込むための一時的なコマンドを書いておく。
(多分手動でローカルのtfstateファイルをコピーするなど回避方法はありそうなので、一つの方法くらいに思っておいてもらえますと)
- name: Terraform Plan
run: terraform plan
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
+ - name: Terraform Import
+ run: terraform import google_storage_bucket.RESOURCE_NAME BUCKET_NAME
+ env:
+ GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
無事stateファイルが作成されている。
デプロイが終わったら、一時的なimport系の処理は削除しておく
- name: Terraform Plan
run: terraform plan
env:
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
- - name: Terraform Import
- run: terraform import google_storage_bucket.RESOURCE_NAME BUCKET_NAME
- env:
- GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }}
この後、自由にリソース作成ができる。
デプロイとロックについて
どうやら、terraformはGCSと連携させると、自動でロックをとってくれるらしい。
デプロイがされている間は、tf.lockファイルがGCSに存在し、デプロイが終わると自動で削除される。
このファイルが存在する限り、他にCIが走ってもデプロイができないみたい。便利。
Discussion