🎄

terraform-google-modules で構築したリソースを半年後に再管理する準備

2023/12/17に公開

本記事は terraform Advent Calendar 2023 の17日目のエントリです。[1]

今年、3月くらいに諸事情でとあるプロジェクトがストップしてたのですが、それが10月くらいに再始動することとなりました。
となると、インフラ管理も動かせるようにしとかないとな、になって terraform plan したら差分地獄で、これじゃメンテできないな。。。になってしまったので、v1.5 から追加となった import block の駆使を中心に引き継ぎも兼ねた再整備をした、という話です。何事も、やればできる。

https://developer.hashicorp.com/terraform/language/import

Google Cloud で terraform どうやるんだっけ? から

再始動にあたり、1点、「極力クレデンシャルをやりとりしない」がプロジェクトの基本方針として確認されたので、それを踏まえて開発者がどう日々の運用を行うか、を確認しました。

そこで、大きな助けになったのが以下の記事。

https://zenn.dev/waddy/articles/terraform-google-cloud

こちら↑をベースに、Google Cloud のプロジェクトに invite してもらってあって、以下を設定しておけば、ファイルのクレデンシャルを持つことなく terraform を動かせました。

terraform を利用する準備

(自分が作成したガイドの一部)

Authenticate

refs: https://cloud.google.com/docs/authentication/gcloud?hl=ja#gcloud-credentials

gcloud auth login

and

gcloud auth application-default login

Confirmation of Authentication

gcloud config list account

and

gcloud auth application-default print-access-token

エラーなく妥当なレスポンスが返って来ていればOK

Create/Update

cd /path/to/target_resource_dir
terraform init
terraform plan
terraform apply

import することに決めた経緯と管理単位

「3月くらい」は環境ごとのディレクトリで一発ズドンと terraform apply するという想定で組んでありました。それから半年以上経過した10月くらいには構築時の terraform-google-modules 配下の各モジュールもだいぶバージョンが上がっており(様変わりしており)、バージョン固定など思い出しにTryしましたが結局 diff が大きく、なかなか Error を解消しきれなかったので、「一発ズドン」を解体する決意をして、以下のレベルに分けました。[2]

解体後のディレクトリ構成
_ 付きは既存リソースを import したものです

infra-manage
.
├── gcp
│   └── environments
│       ├── across
│       │   ├── _artifact-registry
│       │   ├── _cloud-dns
│       │   ├── _upload-gcs
│       │   ├── iam
│       │   │   ├── service-account
│       │   │   │   └── tfp-sa
│       │   │   └── workload-identity
│       │   │       └── tfp-gha-oidc
│       │   ├── sops-kms
│       │   └── tf-manage-gcs
│       └── staging
│           ├── iam
│           ├── manage
│           │   ├── _gce
│           │   └── _scheduler
│           ├── network
│           │   ├── _connector
│           │   ├── _firewall
│           │   ├── _router
│           │   └── _vpc
│           ├── service
│           │   ├── _cloud-run
│           │   ├── _load-balancer
│           │   └── _secrets
│           └── storage
│               ├── _cloud-sql
│               ├── _memorystore-for-redis
│               └── _private-service-access
│
├── github
│   └── actions-secrets
│
├── tf-modules
│
└── .terraform-version

最上位ディレクトリを infra-manage としたのは、すでに使用していた infrastructures との棲み分けのためです。こうしないと、既存のものが容易に壊せてしまうので。

import の順序

次節から、import していった順に、実行したコマンドを可能な範囲でご紹介します。

import 後に plan して no change になるかチェックするのですが、調整が必要だったケースはもちろんあったものの、どう対処したか詳細を思い出せないので割愛します(というか、控えてなかったので書けません..)。

(New)は新規作成、(Import)を上から順に
infra-manage/gcp

(New)

- across/tf-manage-gcs
- across/iam/service-account/tfp-sa
- across/iam/workload-identity/tfp-gha-oidc
- across/sops-kms


(Import)
- across/_upload-gcs
- staging/network/_vpc
- staging/network/_router
- staging/network/_firewall
- staging/storage/_cloud-sql
- staging/storage/_memorystore-for-redis
- staging/storage/_private-service-access
- across/_artifact-registry
- staging/service/_secrets
- across/_cloud-dns
- staging/network/_connector
- staging/service/_cloud-run
- staging/service/_load-balancer
- staging/manage/_scheduler
- staging/manage/_gce # TBD

network の import

network/_vpc import

vpc


❯ terraform import google_compute_network.staging_vpc projects/${gcp_project_id}/global/networks/staging-${project_id}-vpc
google_compute_network.staging_vpc: Importing from ID "projects/${gcp_project_id}/global/networks/staging-${project_id}-vpc"...
google_compute_network.staging_vpc: Import prepared!
  Prepared google_compute_network for import
google_compute_network.staging_vpc: Refreshing state... [id=projects/${gcp_project_id}/global/networks/staging-${project_id}-vpc]

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.


~/src/XXXX/github.com/${org}/${project}/infra-manage/gcp/environments/staging/network/_vpc

subnetwork


❯ terraform import google_compute_subnetwork.staging_subnet_private_1 projects/${gcp_project_id}/regions/asia-northeast1/subnetworks/staging-${project_id}-private-subnet-1
google_compute_subnetwork.staging_subnet_private_1: Importing from ID "projects/${gcp_project_id}/regions/asia-northeast1/subnetworks/staging-${project_id}-private-subnet-1"...
google_compute_subnetwork.staging_subnet_private_1: Import prepared!
  Prepared google_compute_subnetwork for import
google_compute_subnetwork.staging_subnet_private_1: Refreshing state... [id=projects/${gcp_project_id}/regions/asia-northeast1/subnetworks/staging-${project_id}-private-subnet-1]

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.


~/src/XXXX/github.com/${org}/${project}/infra-manage/gcp/environments/staging/network/_vpc

❯ terraform import google_compute_subnetwork.staging_subnet_serverless_connector projects/${gcp_project_id}/regions/asia-northeast1/subnetworks/staging-${project_id}-vpc-serverless-connector-subnet
google_compute_subnetwork.staging_subnet_serverless_connector: Importing from ID "projects/${gcp_project_id}/regions/asia-northeast1/subnetworks/staging-${project_id}-vpc-serverless-connector-subnet"...
google_compute_subnetwork.staging_subnet_serverless_connector: Import prepared!
  Prepared google_compute_subnetwork for import
google_compute_subnetwork.staging_subnet_serverless_connector: Refreshing state... [id=projects/${gcp_project_id}/regions/asia-northeast1/subnetworks/staging-${project_id}-vpc-serverless-connector-subnet]

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.


~/src/XXXX/github.com/${org}/${project}/infra-manage/gcp/environments/staging/network/_vpc
network/_router import

router


❯ terraform import google_compute_router.staging_router projects/${gcp_project_id}/regions/asia-northeast1/routers/staging-${project_id}-router
google_compute_router.staging_router: Importing from ID "projects/${gcp_project_id}/regions/asia-northeast1/routers/staging-${project_id}-router"...
google_compute_router.staging_router: Import prepared!
  Prepared google_compute_router for import
google_compute_router.staging_router: Refreshing state... [id=projects/${gcp_project_id}/regions/asia-northeast1/routers/staging-${project_id}-router]

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.


~/src/XXXX/github.com/${org}/${project}/infra-manage/gcp/environments/staging/network/_router

nat

❯ terraform import google_compute_router_nat.staging_nat_gateway projects/${gcp_project_id}/regions/asia-northeast1/routers/staging-${project_id}-router/staging-${project_id}-nat
google_compute_router_nat.staging_nat_gateway: Importing from ID "projects/${gcp_project_id}/regions/asia-northeast1/routers/staging-${project_id}-router/staging-${project_id}-nat"...
google_compute_router_nat.staging_nat_gateway: Import prepared!
  Prepared google_compute_router_nat for import
google_compute_router_nat.staging_nat_gateway: Refreshing state... [id=${project_id}/asia-northeast1/staging-${project_id}-router/staging-${project_id}-nat]

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.


~/src/XXXX/github.com/${org}/${project}/infra-manage/gcp/environments/staging/network/_router
network/_firewall import

firewall

❯ terraform import google_compute_firewall.db_${dbms} projects/${gcp_project_id}/global/firewalls/allow-db-ingress-stg                  
data.terraform_remote_state.network_vpc: Reading...
data.terraform_remote_state.network_vpc: Read complete after 1s
google_compute_firewall.db_${dbms}: Importing from ID "projects/${gcp_project_id}/global/firewalls/allow-db-ingress-stg"...
google_compute_firewall.db_${dbms}: Import prepared!
  Prepared google_compute_firewall for import
google_compute_firewall.db_${dbms}: Refreshing state... [id=projects/${gcp_project_id}/global/firewalls/allow-db-ingress-stg]

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.


~/src/XXXX/github.com/${org}/${project}/infra-manage/gcp/environments/staging/network/_firewall

(その他の rule も同様の方法)


ここから先は後で書きます・・・

storage の import

storage/_cloud-sql import
storage/_memorystore-for-redis import

service (Web Application) の import

_artifact-registry import
service/_secrets import
_cloud-dns import
service/_secrets import
network/_connector import
service/_cloud-run import

残り、と今後に寄せ思うこと

  • サービスアカウントと、CI/CD(GitHub Actions・CircleCI併用) の secrets、GCE resource の import がまだなのでやったら書く

  • 今後に思うことは、terraform の パッチバージョンが上がるたびくらいの頻度で terraform plan をかけて差分確認してないと、あっという間に再構築困難な状態になるので、インフラのCIこそ重要、と思うようになりました。

脚注
  1. 16日目は @chaspy さんの terraform おもしろ build-in function でした。 ↩︎

  2. 24日目に「管理単位を小さくして運用する terraform (仮)」という記事を書く予定 ↩︎

Discussion