上一篇提到我們如何設定IAM service account讓terraform來access GCP的雲端, 這一篇我們要來討論如何設定GCS做為terraform backend相關的參考文件可以看這邊的官方文件terraform backend configuration裡面可以點選available backend裡面有詳細的各大雲或是local-onpremise的選擇。因為我們是用GCP 因此這次我們就拿GCS來當我們的backend吧!
話不多說,接下來我們就先寫個gcs的code來設定我們的terraform吧
gcs.tf
resource "google_storage_bucket" "terraform_backend" {
name = "terraform-backend"
location = var.location
storage_class = "MULTI_REGIONAL"
versioning {
enabled = "true"
}
labels = {
infra = "terraform_backend"
}
}
variable.tf 增加
variable "location" {
type = string
description = "GCP location"
}
terraform.tfvars 增加
location = US
這邊我們的location選擇US, 因為我們的instance在us-west-1
storage class 選擇MULTI_REGIONAL則是為了高可靠性, 並且打開versioning的功能, 最後下個labels結尾。這個labels是為了之後可以方便我們在找尋infra以及billing的時候可以方便又快速的找到我們要的資料。
之後我們就可以下terraform apply
但是卻得到了以下的錯誤訊息
Terraform will perform the following actions:
# google_storage_bucket.terraform_backend will be created
+ resource "google_storage_bucket" "terraform_backend" {
+ force_destroy = false
+ id = (known after apply)
+ labels = {
+ "infra" = "terraform_backend"
}
+ location = "US"
+ name = "terraform-backend"
+ project = (known after apply)
+ self_link = (known after apply)
+ storage_class = "MULTI_REGIONAL"
+ uniform_bucket_level_access = (known after apply)
+ url = (known after apply)
+ versioning {
+ enabled = true
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
google_storage_bucket.terraform_backend: Creating...
╷
│ Error: googleapi: Error 403: terraform@playground-355402.iam.gserviceaccount.com does not have storage.buckets.create access to the Google Cloud project., forbidden
│
│ with google_storage_bucket.terraform_backend,
│ on gcs.tf line 1, in resource "google_storage_bucket" "terraform_backend":
│ 1: resource "google_storage_bucket" "terraform_backend" {
│
經過查詢, 原來我們的terraform service account還需要加入Storage Object Admin的role。這邊剛好我們可以藉此練習terraform import的技巧。還記得我們之前提到的雞生蛋、蛋生雞的問題,那因為我們已經在之前手動的建立了IAM service account現在我們則需要把這個service account的資料拉回到我們的terraform.tfstate中。如何做到這件事呢?我們繼續往下看下去。
這邊找到了一個GCP的工具可以幫助我們import GCP的整個infra。因此如果我們有已經存在的infra想要導入terraform 也可以藉由這個工具來幫我們產生
Import your Google Cloud resources into Terraform state
中間我們需要打開cloudassets api並且執行
gcloud beta resource-config bulk-export \
--path=entire-tf-output \
--project=playground-355402 \
--resource-format=terraform
執行完畢後會得到一個entire-tf-output的目錄,裡面有所有infra的結構,
我們可以看一下projects/<projectname>/IAMServiceAccount會有個terraform.tf
resource "google_service_account" "terraform" {
account_id = "terraform"
description = "terraform service account"
display_name = "terraform"
project = "playground-355402"
}
# terraform import google_service_account.terraform projects/playground-355402/serviceAccounts/terraform@playground-355402.iam.gserviceaccount.com
拷貝這個檔案到terraform-iam.tf並執行
terraform import google_service_account.terraform projects/playground-355402/serviceAccounts/terraform@playground-355402.iam.gserviceaccount.com
但是執行terraform import又遇到error
│ Error: Error when reading or editing Service Account "projects/playground-355402/serviceAccounts/terraform@playground-355402.iam.gserviceaccount.com": googleapi: Error 403: Permission iam.serviceAccounts.get is required to perform this operation on service account projects/playground-355402/serviceAccounts/terraform@playground-355402.iam.gserviceaccount.com., forbidden
經過查詢我們需要service account admin 和project iam admin因此我們可以到IAM頁面加入
再次執行就可以了
terraform import google_service_account.terraform projects/playground-355402/serviceAccounts/terraform@playground-355402.iam.gserviceaccount.com
google_service_account.terraform: Importing from ID "projects/playground-355402/serviceAccounts/terraform@playground-355402.iam.gserviceaccount.com"...
google_service_account.terraform: Import prepared!
Prepared google_service_account for import
google_service_account.terraform: Refreshing state... [id=projects/playground-355402/serviceAccounts/terraform@playground-355402.iam.gserviceaccount.com]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
接下來我們可以寫iam binding 加入到terraform-iam.tf
module "projects_iam_bindings" {
source = "terraform-google-modules/iam/google//modules/projects_iam"
version = "~> 6.4"
projects = [ "playground-355402" ]
bindings = {
"roles/compute.admin" = [
"serviceAccount:terraform@playground-355402.iam.gserviceaccount.com"
]
"roles/compute.storageAdmin" = [
"serviceAccount:terraform@playground-355402.iam.gserviceaccount.com"
]
"roles/container.admin" = [
"serviceAccount:terraform@playground-355402.iam.gserviceaccount.com"
]
"roles/iam.serviceAccountAdmin" = [
"serviceAccount:terraform@playground-355402.iam.gserviceaccount.com"
]
"roles/resourcemanager.projectIamAdmin" = [
"serviceAccount:terraform@playground-355402.iam.gserviceaccount.com"
]
"roles/storage.admin" = [
"serviceAccount:terraform@playground-355402.iam.gserviceaccount.com"
]
}
}
接下來執行terraform apply
最後我們就可以看到 IAM 該有的role都有了,GCS也成功的create bucket
最後我們在寫我們的backend進去
backend.tf
terraform {
backend "gcs" {
bucket = "terraform-playground-backend"
prefix = "terraform/state"
}
}
接下來執行terraform init
最後就可以看到我們的tfstate儲存在GCS啦
這邊我們完成了terraform gcs的設定, terraform import的過程 和最後設定IAM roles然後成功的將我們local 的tfstate上傳到gcs上。
下一篇我們會討論如何利用terraform來創建一個GKE kubernetes cluster