6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

チュートリアル「Terraform、Cloud Build、GitOps を使用してインフラストラクチャをコードとして管理」の実施

Posted at

お題

以下の記事をトレースするだけ。
https://cloud.google.com/solutions/managing-infrastructure-as-code?hl=ja

前提

以下の記事でのセットアップが完了していること。
https://qiita.com/sky0621/items/c488e8adb2a51870ad22

以下については知識があるものとしてやり方や概念など説明しない。

開発環境

# OS - Linux(Ubuntu)

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"

# Git

$ git version
git version 2.26.2

# Terraform

$ terraform version
Terraform v0.12.25

# gcloud

$ gcloud version
Google Cloud SDK 294.0.0

実践

■ アーキテクチャ

以下に記載の通り、「dev」と「prod」という(実際の開発現場ならもうひとつ「stg」もあるかも)構成。
https://cloud.google.com/solutions/managing-infrastructure-as-code?hl=ja#architecture

■ 使用リポジトリ

以下をフォーク。
https://github.com/GoogleCloudPlatform/solutions-terraform-cloudbuild-gitops

で、ローカル(作業端末)にクローンしておく。
ディレクトリ構成は以下の通り。

$ tree
.
├── cloudbuild.yaml
├── environments
│   ├── dev
│   │   ├── backend.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   ├── terraform.tfvars
│   │   ├── variables.tf
│   │   └── versions.tf
│   └── prod
│       ├── backend.tf
│       ├── main.tf
│       ├── outputs.tf
│       ├── terraform.tfvars
│       ├── variables.tf
│       └── versions.tf
└── modules
    ├── firewall
    │   ├── main.tf
    │   ├── outputs.tf
    │   ├── variables.tf
    │   └── versions.tf
    ├── http_server
    │   ├── main.tf
    │   ├── outputs.tf
    │   ├── variables.tf
    │   └── versions.tf
    └── vpc
        ├── main.tf
        ├── outputs.tf
        ├── variables.tf
        └── versions.tf

以降、上記のディレクトリ構造であることを前提とする。

■ 状態の保存先をGCSバケットに変更

terraform.tfstate(インフラ構築状態が保存されているファイル)の格納先をローカルからGCSバケット内に変更。

GCSバケット作成

GCPプロジェクトIDを名前の一部に含むバケット名を作るとバケット名の重複が防げる。

$ env | grep GOOGLE
GOOGLE_CREDENTIALS=/home/sky0621/.config/gcloud/my-gcp-prj-01-terraform-credential.json
GOOGLE_PROJECT=my-gcp-prj-01
$
$ gsutil mb -l asia-northeast1 gs://${GOOGLE_PROJECT}-tfstate
Creating gs://my-gcp-prj-01-tfstate/...

あと、デプロイ履歴を保持できるようにしておく。

$ gsutil versioning set on gs://${GOOGLE_PROJECT}-tfstate
Enabling versioning for gs://my-gcp-prj-01-tfstate/...

screenshot-console.cloud.google.com-2020.05.30-17_38_19.png

backend.tf ファイルの修正

terraform.tfstateの格納先の指定はbackend.tfファイルで行っているので、dev と prod それぞれの環境別に置いてある当該ファイルを修正。
修正後は以下のようになる。

environments/dev/backend.tf
terraform {
  backend "gcs" {
    bucket = "${GOOGLE_PROJECT}-tfstate"
    prefix = "env/dev"
  }
}

environments/prod/backend.tf の方も同様に修正。

terraform.tfvars ファイルの修正

dev と prod それぞれの環境において、定義時にGCPプロジェクトIDの指定が必要になる箇所が複数ある。
そのため、変数として定義しておいて、必要になる箇所ではその変数を参照する記述にしてある。
変数が定義されているのは、terraform.tfvars ファイル。
この中も以下のように環境変数からGCPプロジェクトIDを参照するように修正する。

environments/dev/terraform.tfvars
project="${GOOGLE_PROJECT}"

ここまでの状況をGitHub上のリポジトリにPush

$ git status
ブランチ dev
Your branch is up to date with 'origin/dev'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   environments/dev/backend.tf
	modified:   environments/dev/terraform.tfvars
	modified:   environments/prod/backend.tf
	modified:   environments/prod/terraform.tfvars
$ git add -A
$ git status
ブランチ dev
Your branch is up to date with 'origin/dev'.

コミット予定の変更点:
  (use "git restore --staged <file>..." to unstage)
	modified:   environments/dev/backend.tf
	modified:   environments/dev/terraform.tfvars
	modified:   environments/prod/backend.tf
	modified:   environments/prod/terraform.tfvars
$ git commit -m "Update project IDs and buckets"
[dev 6c54e5f] Update project IDs and buckets
 5 files changed, 8 insertions(+), 5 deletions(-)
$ git status
ブランチ dev
このブランチは 'origin/dev' よりも1コミット進んでいます。
  (use "git push" to publish your local commits)

nothing to commit, working tree clean
$ git push origin dev
Enumerating objects: 17, done.
Counting objects: 100% (17/17), done.
Delta compression using up to 4 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (9/9), 750 bytes | 375.00 KiB/s, done.
Total 9 (delta 5), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (5/5), completed with 4 local objects.
To github.com:sky0621/solutions-terraform-cloudbuild-gitops.git
   bf83e89..6c54e5f  dev -> dev

■ Cloud Build 関連の設定

API使えるようにしておく

$ gcloud services enable cloudbuild.googleapis.com
Operation "operations/xxx.99999999-xxxx-999-xxxx-99999999" finished successfully.

Cloud Build サービスアカウントに権限を付与

元記事でも記載があるけど、「とりあえず roles/editor をつけているものの本来なら必要最小限なロールを付与すべき」とあるので実際の開発現場では留意すべき。

サービスアカウントの情報を得る

プロジェクト自体の情報

$ gcloud projects describe ${GOOGLE_PROJECT}
createTime: '2020-05-27T15:19:59.167Z'
lifecycleState: ACTIVE
name: My Project 19162
projectId: my-gcp-prj-01
projectNumber: '999999999999'

プロジェクトナンバー部分を抜粋

$ gcloud projects describe ${GOOGLE_PROJECT} --format 'value(projectNumber)'
999999999999

上記ナンバーを含むCloud Build サービスアカウントのメアドを環境変数にセット

$ export CLOUDBUILD_SA="$(gcloud projects describe ${GOOGLE_PROJECT} --format 'value(projectNumber)')@cloudbuild.gserviceaccount.com"
$
$ env | grep CLOUDBUILD_SA
CLOUDBUILD_SA=999999999999@cloudbuild.gserviceaccount.com

ロール付与

$ gcloud projects add-iam-policy-binding ${GOOGLE_PROJECT} --member serviceAccount:${CLOUDBUILD_SA} --role roles/editor
Updated IAM policy for project [my-gcp-prj-01].
bindings:
   〜〜〜
  - serviceAccount:999999999999@cloudbuild.gserviceaccount.com
  role: roles/editor
   〜〜〜

screenshot-console.cloud.google.com-2020.05.30-22_55_20.png

Cloud Build を GitHub リポジトリに接続

以下を参照しながら。
https://cloud.google.com/solutions/managing-infrastructure-as-code?hl=ja#directly_connecting_cloud_build_to_your_github_repository

Cloud Build アプリの GitHub Marketplace ページにアクセス

screenshot-github.com-2020.05.30-23_05_35.png
screenshot-github.com-2020.05.30-23_08_13.png

ちなみに、下記とのこと。

Cloud Buildは、無料枠を超えるビルド1分あたりの料金です。
1日120分の無料ビルド分。その後$ 0.003 /分。
最大10の同時ビルドが含まれます。
ビルドされたイメージをGoogle Container Registryに自動的にプッシュします(ストレージコストがかかる場合があります)。
詳細については、Cloud Buildの料金ページをご覧ください。
https://cloud.google.com/cloud-build/pricing

screenshot-github.com-2020.05.30-23_09_52.png

screenshot-github.com-2020.05.30-23_11_51.png

screenshot-accounts.google.com-2020.05.30-23_12_23.png

screenshot-github.com-2020.05.30-23_13_38.png

screenshot-console.cloud.google.com-2020.05.30-23_15_30.png

screenshot-console.cloud.google.com-2020.05.30-23_16_10.png

screenshot-console.cloud.google.com-2020.05.30-23_17_23.png

screenshot-console.cloud.google.com-2020.05.30-23_19_14.png

screenshot-github.com-2020.05.30-23_20_06.png

終わった様子。

screenshot-github.com-2020.05.30-23_20_57.png

■ ソースの変更によるCloud Build発動を確認

ローカルでソース修正しリモートにPush

$ pwd
/home/sky0621/work/src/github.com/sky0621/solutions-terraform-cloudbuild-gitops
$
$ git branch
* dev
$

フォーク元リポジトリで(学習用に)タイプミスされていたファイルを修正。

$ git diff
diff --git a/modules/firewall/main.tf b/modules/firewall/main.tf
index 5e40f70..1d2e549 100644
--- a/modules/firewall/main.tf
+++ b/modules/firewall/main.tf
@@ -27,6 +27,6 @@ resource "google_compute_firewall" "allow-http" {
     ports    = ["80"]
   }
 
-  target_tags   = ["http-server2"]
+  target_tags   = ["http-server"]
   source_ranges = ["0.0.0.0/0"]
 }

上記バグ修正のコミット用にブランチを切って、上記の内容を反映。

$ git checkout -b bugfix origin/dev
M	modules/firewall/main.tf
Branch 'bugfix' set up to track remote branch 'dev' from 'origin'.
Switched to a new branch 'bugfix'
$
$ git branch
* bugfix
  dev
$
$ git add .
$
$ git status
ブランチ bugfix
Your branch is up to date with 'origin/dev'.

コミット予定の変更点:
  (use "git restore --staged <file>..." to unstage)
	modified:   modules/firewall/main.tf
$
$ git commit -m "http ファイアウォール ターゲットの修正"
[bugfix 82e283a] http ファイアウォール ターゲットの修正
 1 file changed, 1 insertion(+), 1 deletion(-)
$
$ git status
ブランチ bugfix
このブランチは 'origin/dev' よりも1コミット進んでいます。
  (use "git push" to publish your local commits)

nothing to commit, working tree clean
$
$ git push -u origin bugfix
Enumerating objects: 9, done.
  〜〜〜
To github.com:sky0621/solutions-terraform-cloudbuild-gitops.git
 * [new branch]      bugfix -> bugfix
Branch 'bugfix' set up to track remote branch 'bugfix' from 'origin'.

作成したバグ修正ブランチを dev ブランチにマージ

screenshot-github.com-2020.05.30-23_33_47.png

screenshot-github.com-2020.05.30-23_36_37.png

screenshot-github.com-2020.05.30-23_39_00.png

あれっ、Cloud Buildのとこで失敗してる?
というわけで、詳細を見に行く。

screenshot-github.com-2020.05.30-23_41_21.png

これでもよくわからないので、Cloud Build側のページへ飛ぶ。

screenshot-console.cloud.google.com-2020.05.30-23_42_53.png

terraform init で失敗してるのかな。
「生データを表示」してみると、

Step #1 - "tf init": [0m[1mInitializing the backend...[0m
Step #1 - "tf init": [31mError loading backend config: 1 error occurred:
Step #1 - "tf init": 	* terraform.backend: configuration cannot contain interpolations
Step #1 - "tf init": 
Step #1 - "tf init": The backend configuration is loaded by Terraform extremely early, before
Step #1 - "tf init": the core of Terraform can be initialized. This is necessary because the backend
Step #1 - "tf init": dictates the behavior of that core. The core is what handles interpolation
Step #1 - "tf init": processing. Because of this, interpolations cannot be used in backend
Step #1 - "tf init": configuration.
Step #1 - "tf init": 
Step #1 - "tf init": If you'd like to parameterize backend configuration, we recommend using
Step #1 - "tf init": partial configuration with the "-backend-config" flag to "terraform init".
Step #1 - "tf init": 
Step #1 - "tf init": [0m[0m
Finished Step #1 - "tf init"
ERROR
ERROR: build step 1 "hashicorp/terraform:0.11.14" failed: step exited with non-zero status: 1

terraform.backend: configuration cannot contain interpolations」とのこと。
ググる。
https://qiita.com/aoshimash/items/f0be7dd81c856d335460
backend.tfで変数使えない様子。。。
しょうがないので変数使わず、再度Push。

screenshot-github.com-2020.05.30-23_58_29.png

お、先ほどはすぐに失敗したけど、しばらく継続してる様子。

screenshot-github.com-2020.05.31-00_01_19.png

成功した。
詳細を見てみる。

screenshot-github.com-2020.05.31-00_04_22.png
screenshot-console.cloud.google.com-2020.05.31-00_05_05.png

失敗時にも出ていたけど、以下に記載の4つのステップが実行されたログとなっている。
https://github.com/GoogleCloudPlatform/solutions-terraform-cloudbuild-gitops/blob/master/cloudbuild.yaml
つまり、terraform apply までされているので、うまくいっているなら、適用対象のGCPプロジェクトにTerraformの定義が反映されているはず。

なのだけど、よくよくログを見ると、
screenshot-console.cloud.google.com-2020.05.31-00_21_02.png

そう、今回、bugfix ブランチから dev ブランチへのプルリクは作ったけど、まだマージしてない。
このCloud Buildログは、あくまで bugfix ブランチが出来たから流されたもので、設定としては devprod 以外は terraform apply はしないものとなっているので、実際にGCP環境には適用されていない。

では、プルリクをマージして、dev ブランチを更新してみる。
screenshot-github.com-2020.05.31-00_24_35.png
screenshot-github.com-2020.05.31-00_25_24.png

はい、マージ完了。
Cloud Build側でビルド状況を確認してみる。
screenshot-console.cloud.google.com-2020.05.31-00_26_31.png
すると、devブランチに更新がかかったゆえの実行中ビルドが増えている。

完了後のログ詳細を見てみると、
screenshot-console.cloud.google.com-2020.05.31-00_28_42.png
今度は、スキップされずに terraform apply が実行されている。

■ 反映結果の確認

まずは、Terraform実行による状態管理をCloud Storage上で行う設定にしたので、その確認。
screenshot-console.cloud.google.com-2020.05.31-00_17_58.png

うん、tfstate ファイルが格納されている。

うまくいっているなら、以下が出来ているはず。

  • VPC
  • Firewall
  • Compute Engine

screenshot-console.cloud.google.com-2020.05.31-00_30_49.png
screenshot-console.cloud.google.com-2020.05.31-00_31_24.png
screenshot-console.cloud.google.com-2020.05.31-00_31_47.png

それぞれ出来ておる。

まとめ

参考記事では、このあと、「Cloud Build の実行が成功した場合にのみマージを適用できるようにする」対応や本番環境の方への適用などもやっているけど、ちょっと力尽きたので今回はこのへんでおしまい。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?