BitbucketにはBitbucket Pipelinesというパイプラインツールが付属しており、CI/CDなど処理の自動化に利用できます。
無料プランでも、ビルド実行時間にして月間500分までは使うことができます。1
本稿では、Bitbucket PipelinesでTerraformを実行し、Google Cloud Platformの構成管理を行う方法を紹介します。
また、GitOpsによるインフラCI/CDの作業フローも紹介します。
更新履歴
- 2020-05-03 Bitbucketのリポジトリ変数設定を変更し、bitbucket-pipelines.ymlを簡素化
- 2020-05-02 初稿投稿
動作確認環境
- terraform v0.12.24
- terraform-provider-google v3.19.0
準備するもの
- Bitbucketアカウント
- Bitbucket上のリポジトリ ... Terraformのコードとbitbucket-pipelines.ymlを入れる
- GCPプロジェクト
- Service Account
- Bitbucke Pipelines内で実行するTerraformで利用する
- Terraformで行う操作に必要なCloud IAMの権限をつける
- 今回の構成では、少なくともGCSへの読み書き権限が必要
- GCSバケット ... TerraformのBackendとして利用し、tfstateを保存する
- 必要なAPIを有効化する
- 例)GCEインスタンスの操作には、Compute Engine APIの有効化が必要
- Service Account
推奨開発環境
ローカルで terraform
コマンドを実行して動作確認を行うため、以下のツールを使えるようにしておくことをお薦めします:
セットアップ手順
- Terraform用のService AccoutのService Account KeyをJSON形式で生成し、保存する
-
- をBitbucketのリポジトリ変数に設定する
- 「Repository Settings > PIPELINES > Repository variables」
- キー名は
GOOGLE_CREDENTIALS
とする(※5/3GOOGLE_CREDENTIALS_DATA
から変更) - 値のBase64化は不要
- ※「Secured」にチェックを入れる
- リポジトリのルート直下に、下のようなbitbucket-pipelines.ymlを用意する
bitbucket-pipelines.yml の設定
bitbucket-pipelines.ymlはBitbucket Pipelinesのビルド構成ファイルです。
下は、TerraformでインフラCI/CDを行うための、サンプル設定です。
image: hashicorp/terraform:0.12.24
# パイプライン設定で重複するステップの記述をまとめるため、YAMLアンカーを定義
definitions:
steps:
- step: &terraform-plan
name: terraform plan
script:
- terraform init -input=false
- terraform plan -input=false
- step: &terraform-apply
name: terraform apply
script:
- terraform init -input=false
- terraform apply -input=false --auto-approve
# パイプライン設定
pipelines:
# プルリクエストによって実行されるパイプライン
pull-requests:
'**': # 任意のブランチからのPRが対象
- step: *terraform-plan
# ブランチの更新によって実行されるパイプライン
branches:
master:
- step: *terraform-plan
- step:
<<: *terraform-apply
# terraform applyは手動で実行する
trigger: manual
※2020-05-03 追記: 環境変数をファイルに書き出す処理を削除しました。(後述)
あまり解説の必要もないかもしれませんが、上のパイプライン設定により、以下が実現できます:
- プルリクエストによってトリガーされるパイプラインによって、
terraform plan
を実行する- マージ元ブランチの更新によってもトリガーされる
- masterブランチの更新によってトリガーされるパイプラインによって、
terraform plan
及びterraform apply
を順番に実行する-
terraform apply
のステップにはtrigger: manual
を指定しているので、パイプラインの画面から手動で「Run」ボタンを押して実行します
-
これにより、インフラコードをGitで管理し、プルリクエストで変更をレビューしてCI/CDで適用する、といった流れのGitOpsが実現できます。
実際にどのような挙動になるかは、作業フローと合わせて後述の「デモ」の節で見ていきます。
GCPへの認証設定について(5/3編集)
作成したService Account Keyを次の2つの認証で用います:
- BackendのGCSに対する認証
- terraform-provider-googleによる認証
それぞれの仕様では、Service Account Keyファイルのパスを指定する環境変数が微妙に違いますが、共通して GOOGLE_CREDENTIALS
を使うことができます。
(5/3追記)
Backendの方のリファレンスを見て、パス名しか指定できないと思い込んでいましたが、試したところ、Providerでの設定と同様に、JSONファイルの内容そのものを値に設定しても問題ありませんでした。
従って、上のリポジトリ変数設定を変更し、bitbucket-pipelines.ymlのパイプライン設定を簡素化することができました。
参考:
- https://www.terraform.io/docs/backends/types/gcs.html#configuration-variables
- https://www.terraform.io/docs/providers/google/guides/provider_reference.html#full-reference
任意のブランチの更新でterraform planを実行する場合
例えば、上記のYAMLで pipelines:
以下の行を次のように書き換えると、master以外のブランチで terraform plan
を実行することができます。
# :
#(ここまでは上のYAMLと同じ)
# パイプライン設定
pipelines:
branches:
'**':
- step: *terraform-plan
master:
- step: *terraform-plan
- step:
<<: *terraform-apply
trigger: manual
masterブランチ更新時の挙動は、先ほどと同様です。
ブランチ運用のスタイルによっては、この方式も便利だと思います。
参考ドキュメント
- Pipelines を使用したビルド、テスト、およびデプロイ
- bitbucket-pipelines.yml の設定 - アトラシアン製品ドキュメント
- YAML アンカー - アトラシアン製品ドキュメント
デモ: GitOpsによるインフラCI/CD
上で示したbitbucket-pipelines.ymlの最初の例(プルリクエスト駆動)を設定した状態で、インフラCI/CDのワークフローがどのようになるかを見ていきます。
0. 下準備
先に示した事前準備とセットアップ手順に加えて、以下を行っています:
- Terraformでテスト用のService Accountを作成するため、GCPプロジェクトでCloud Resource Manager APIを有効化しています
- リポジトリの「CHAT NOTIFICATIONS」設定により、Slack通知を有効にしています
5/3追記: デモでのパイプライン設定の差異について
流れは変わりませんが、念のために注記しておきます。
5/3にリポジトリ変数を変更してbitbucket-pipelines.ymlを簡素化しました。
以下のデモでは、次の2点が異なっています:
- リポジトリ変数に設定したService Account Keyのキー名が
GOOGLE_CREDENTIALS
ではなく、GOOGLE_CREDENTIALS_DATA
となっている
-bitbucket-pipelines.ymlのアンカー&terraform-plan
,&terraform-apply
それぞれで定義したscriptの先頭に以下の2行がある
script:
+ - echo "${GOOGLE_CREDENTIALS_DATA}" > service-account-key.json
+ - export GOOGLE_APPLICATION_CREDENTIALS=service-account-key.json
- terraform init -input=false
:
1. topicブランチを作成し、コード変更をプッシュ
-
topic/add-test-sa
というブランチを作成します - .tfファイルに
google_service_account
リソースを定義します
- 実はこのコードには誤りがあるので、この後のパイプラインは失敗します
- Bitbucketにブランチをプッシュします。
% git checkout -b topic/add-test-sa
% $EDITOR main.tf
% git diff
diff --git a/main.tf b/main.tf
index b6bb61a..d5c0613 100644
--- a/main.tf
+++ b/main.tf
@@ -31,3 +31,7 @@ resource "google_project_iam_member" "sa_terraform" {
role = "roles/owner"
member = "serviceAccount:${google_service_account.terraform.email}"
}
+
+resource "google_service_account" "test" {
+ account_id = "test"
+}
% git add .
% git commit -m "Add test service account"
% git push origin topic/add-test-sa
master以外のブランチにはトリガーを設定していないので、ここではパイプラインは実行されません。
2. プルリクエストの作成
Bitbucket画面上でプルリクエストを作成します。
bitbucket-pipelines.ymlの pull-requests
で設定したトリガーにより、 terraform plan
のパイプラインが実行されます。
3. ビルド結果(失敗)の確認
Slackにビルド結果が通知されました。
「Pipeline #37」のリンクをクリックして、ビルドログを確認します。
google_service_account.test.account_id
のバリデーションでエラーになっていることがわかりました。
4. コードを修正して再プッシュ
google_service_account.test.account_id
を修正して、ブランチを再プッシュします。
% $EDITOR main.tf
% git diff
diff --git a/main.tf b/main.tf
index d5c0613..fd9a3ec 100644
--- a/main.tf
+++ b/main.tf
@@ -33,5 +33,5 @@ resource "google_project_iam_member" "sa_terraform" {
}
resource "google_service_account" "test" {
- account_id = "test"
+ account_id = "test01"
}
% git add .
% git commit -m "Fix test service account id"
% git push origin topic/add-test-sa
先ほどと同様に、bitbucket-pipelines.ymlの pull-requests
で設定したトリガーにより、 terraform plan
のパイプラインが実行されます。
5. ビルド結果(成功)の確認
Slackにビルド結果が通知されました。
「fixed」となっており、成功したようです。
パイプラインのログも確認しておきましょう。
terraform plan
の出力結果が意図通りになっていることが確認できました。
6. PR画面の確認とマージ
プルリクエストの「活動履歴」タブで、ビルドを含む履歴を確認することができます。
問題ないので、マージします。
7. masterブランチ上でのパイプライン実行
bitbucket-pipelines.ymlの branches.master
で設定したトリガーにより、 terraform plan
+ terraform apply
のパイプラインが実行されます。
Slack通知によってmasterブランチでパイプラインが実行されたことがわかります。
「Pipeline #41」のリンクをクリックして、パイプライン画面に遷移します。2
今回のパイプライン設定では、ここでもう一度 terraform plan
の結果を確認することができます。
terraform apply
のステップには trigger: manual
を設定しているので、人間が手動で確認して実行します。
問題がなければ、「Run」ボタンを押して、 terraform apply
を実行します。
terraform apply
も問題なく成功しました
まとめと所感
Bitbucket PipelinesでTerraformを実行し、GCP環境のインフラCI/CDを行う方法と、GitOpsによる作業フローのイメージを紹介しました。
今回、Bitbucket Pipelinesについて全く知らない状態から色々と調べて構築してみたのですが、普通に使えるCIサービスだなと思いました。
最初、なかなか求める情報が見つけられず、「機能が乏しいのではないか」などと思ったりしてしまったのですが、振り返ってみれば、必要十分な機能は揃っているように思います。また、必要な情報はだいたい公式ドキュメントにまとまっていました。
ここ1〜2年で、GitHubでもプライベートリポジトリの作成が無料化されたり、GitHub Actionsというパイプラインツールが登場したので、敢えてBitbucketを使う理由は減っていると思いますが、Bitbucketでも特に困ることはないなと思いました。
脚注
-
※別のパイプライン実行が間に挟まったので、直前から番号が飛んでいます。 ↩