経緯
- 共有VPCの機能検証のためにとりあえずコンソールからプロジェクト作って設定とかしてた
- ただ、今後考えるとコードで管理してCIで反映とかしたくなったので、手で作った分をコードとして管理できるようにしたかった
注意
- Terraformの設定ファイルの記述の細かい説明等はしません
- 適宜公式ドキュメントを参照ください(Provider: Google Cloud Platform - Terraform by HashiCorp)
2019/05/07追記
GCP版Terraformingが来たのでもうこんなめんどくさいことやらんでもいいんやで
前提条件
- 以下のような環境がコンソールを用いて作成されている(細かい設定は省略)
- VPC
- name: wordpress
- mode: カスタム
- subnet:
- wordpress-asia-northeast1
- region: asia-northeast1
- range: 10.0.0.0/9
- wordpress-asia-northeast1
- Firewall rule
- wordpress-allow-icmp
- icmpでの通信を許可
- wordpress-allow-ssh
- tcp:22での通信を許可
- wordpress-allow-https
- tcp:443での通信を許可
- target tag: wordpress
- wordpress-allow-icmp
- GCE
- name: wordpress
- region: asia-northeast1
- zone: asia-northeast1-b
- machine type: micro
- network: wordpress
- subnetwork: wordpress-asia-northeast1
- network tags: wordpress
- VPC
事前準備
- terraformの設定ファイル格納用のGCSバケット作成(権限あればなんでもいい)
- 対象プロジェクトからcloud shellを起動(作業環境)
- 作業用ディレクトリ切ってterraform実行用のスクリプト配置
#!/bin/bash
docker run -it --rm -v $(pwd):/workspace -v ~/.config/gcloud:/root/.config/gcloud --workdir /workspace hashicorp/terraform:light $@
実作業
1. コード書く
- まずはコードかしたい部分のterraformのコードを書きます。
- ちなみにこの時点ではコードと実態が完全一致しなくても大丈夫です。
-
./terraform.sh validate
で何も表示されなければOK。
-
- 書き方がわからない場合は公式ドキュメントを探すと吉。
# 基本設定
provider "google" {
project = "terraform-practice-220905"
region = "asia-northeast1"
version = "~> 1.19"
}
terraform {
backend "gcs" {
bucket = "terraform-practice-220905"
path = "terraform.tfstate"
project = "terraform-practice"
}
}
# VPC設定
resource "google_compute_network" "wordpress-vpc" {
name = "wordpress" # 実際のvpcネットワーク名に合わせる
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "wordpress-subnet" {
name = "wordpress-asia-northeast1"
ip_cidr_range = "10.0.0.0/9"
network = "${google_compute_network.wordpress-vpc.self_link}"
enable_flow_logs = "false"
private_ip_google_access = "false"
}
# Firewall Rule設定
resource "google_compute_firewall" "icmp" {
name = "wordpress-allow-icmp"
network = "${google_compute_network.wordpress-vpc.self_link}"
allow {
protocol = "icmp"
}
}
resource "google_compute_firewall" "ssh" {
name = "wordpress-allow-ssh"
network = "${google_compute_network.wordpress-vpc.self_link}"
allow {
protocol = "tcp"
ports = ["22"]
}
}
resource "google_compute_firewall" "https" {
name = "wordpress-allow-https"
network = "${google_compute_network.wordpress-vpc.self_link}"
allow {
protocol = "tcp"
ports = ["443"]
}
target_tags = ["wordpress"]
}
# GCE設定
resource "google_compute_instance" "wordpress" {
name = "wordpress"
machine_type = "f1-micro"
zone = "asia-northeast1"
boot_disk {
initialize_params {
image = "debian-cloud/debian-9"
}
}
network_interface {
network = "${google_compute_network.wordpress-vpc.self_link}"
subnetwork = "${google_compute_subnetwork.wordpress-subnet.self_link}"
access_config {
// Ephemeral IP
}
}
}
2. 既存の設定内容をimportする
- terraformには既存の設定内容をimportするためのコマンドが用意されています。
-
terraform import #{データソース名}.#{設定ファイル上の名前} #{インポート対象のリソースの名前}
- インポート対象のリソース名の指定の仕方が一部特殊なものもあります。
- 公式ドキュメントの各データソースごとの説明ページにインポートに関する記載もありますので、うまくいかない場合はそちらを参照ください。
- もしかしたら先に
terraform init
しないといけないかも。
$ ./terraform.sh import google_compute_network.wordpress-vpc wordpress
$ ./terraform.sh import google_compute_subnetwork.wordpress-subnet wordpress-asia-northeast1
$ ./terraform.sh import google_compute_firewall.icmp wordpress-allow-icmp
$ ./terraform.sh import google_compute_firewall.ssh wordpress-allow-ssh
$ ./terraform.sh import google_compute_firewall.https wordpress-allow-https
$ ./terraform.sh import google_compute_instance.wordpress terraform-practice-220905/asia-northeast1-b/wordpress
importにミスったら
例えば、ssh用のfirewallの設定をインポートするつもりが、icmp用のfirewallの設定をインポートしてしまった場合、一度stateを削除してインポートし直せばOKです。
# ミスってインポート
$ ./terraform.sh import google_compute_firewall.ssh wordpress-allow-icmp
$ ./terraform.sh state list
google_compute_firewall.ssh # 間違ってインポートしたものを確認
google_compute_network.wordpress-vpc
google_compute_subnetwork.wordpress-subnet
# 削除
./terraform.sh state rm google_compute_firewall.ssh
# 再インポート
$ ./terraform.sh import google_compute_firewall.ssh wordpress-allow-ssh
3. コードと実態の差分確認・修正
terraform plan
を実行するとコードと実態の差分が確認できるので、差分に合わせてコードを修正していく。
$ ./terraform.sh plan
-------------- 省略 --------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
-/+ google_compute_instance.wordpress (new resource required)
id: "wordpress" => <computed> (forces new resource)
boot_disk.#: "1" => "1"
boot_disk.0.auto_delete: "true" => "true"
boot_disk.0.device_name: "wordpress" => <computed>
-------------- 省略 --------------
tags.#: "1" => "0"
tags.678694731: "wordpress" => ""
tags_fingerprint: "AG-OvsszYew=" => <computed>
zone: "asia-northeast1-b" => "asia-northeast1" (forces new resource)
Plan: 1 to add, 0 to change, 1 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
zone: "asia-northeast1-b" => "asia-northeast1" (forces new resource)
とりあえずzoneが違うので強制再作成しようとしているので、コードを直します。
$ diff wordpress.tf.org wordpress.tf
65c65
< zone = "asia-northeast1"
---
> zone = "asia-northeast1-b"
修正後、再度差分を確認します。
$ ./terraform.sh plan
-------------- 省略 --------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
~ google_compute_instance.wordpress
create_timeout: "" => "4"
service_account.#: "1" => "0"
service_account.0.scopes.#: "6" => "0"
service_account.0.scopes.1632638332: "https://www.googleapis.com/auth/devstorage.read_only" => ""
service_account.0.scopes.172152165: "https://www.googleapis.com/auth/logging.write" => ""
service_account.0.scopes.316356861: "https://www.googleapis.com/auth/service.management.readonly" => ""
service_account.0.scopes.3663490875: "https://www.googleapis.com/auth/servicecontrol" => ""
service_account.0.scopes.3859019814: "https://www.googleapis.com/auth/trace.append" => ""
service_account.0.scopes.4177124133: "https://www.googleapis.com/auth/monitoring.write" => ""
tags.#: "1" => "0"
tags.678694731: "wordpress" => ""
Plan: 0 to add, 1 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
今度はcreate_timeout,scopeとtagsに差分があるので修正します。(create_timeoutはどうでもいいので、差分あっても無視するように設定することで対処)
65a66
> tags = ["wordpress"]
79a81,97
> }
>
> service_account {
> scopes = [
> "https://www.googleapis.com/auth/devstorage.read_only",
> "https://www.googleapis.com/auth/logging.write",
> "https://www.googleapis.com/auth/service.management.readonly",
> "https://www.googleapis.com/auth/servicecontrol",
> "https://www.googleapis.com/auth/trace.append",
> "https://www.googleapis.com/auth/monitoring.write",
> ]
> }
>
> lifecycle {
> ignore_changes = [
> "create_timeout"
> ]
最後にもう一度差分確認。
$ ./terraform.sh plan
-------------- 省略 --------------
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
No changes.
って出れば修正完了です。お疲れ様でした。
おまけで修正後のTFファイルも載せます。
# 基本設定
provider "google" {
project = "terraform-practice-220905"
region = "asia-northeast1"
version = "~> 1.19"
}
terraform {
backend "gcs" {
bucket = "terraform-practice-220905"
path = "terraform.tfstate"
project = "terraform-practice"
}
}
# VPC設定
resource "google_compute_network" "wordpress-vpc" {
name = "wordpress" # 実際のvpcネットワーク名に合わせる
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "wordpress-subnet" {
name = "wordpress-asia-northeast1"
ip_cidr_range = "10.0.0.0/9"
network = "${google_compute_network.wordpress-vpc.self_link}"
enable_flow_logs = "false"
private_ip_google_access = "false"
}
# Firewall Rule設定
resource "google_compute_firewall" "icmp" {
name = "wordpress-allow-icmp"
network = "${google_compute_network.wordpress-vpc.self_link}"
allow {
protocol = "icmp"
}
}
resource "google_compute_firewall" "ssh" {
name = "wordpress-allow-ssh"
network = "${google_compute_network.wordpress-vpc.self_link}"
allow {
protocol = "tcp"
ports = ["22"]
}
}
resource "google_compute_firewall" "https" {
name = "wordpress-allow-https"
network = "${google_compute_network.wordpress-vpc.self_link}"
allow {
protocol = "tcp"
ports = ["443"]
}
target_tags = ["wordpress"]
}
resource "google_compute_instance" "wordpress" {
name = "wordpress"
machine_type = "f1-micro"
zone = "asia-northeast1-b"
tags = ["wordpress"]
boot_disk {
initialize_params {
image = "debian-cloud/debian-9"
}
}
network_interface {
network = "${google_compute_network.wordpress-vpc.self_link}"
subnetwork = "${google_compute_subnetwork.wordpress-subnet.self_link}"
access_config {
// Ephemeral IP
}
}
service_account {
scopes = [
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/trace.append",
"https://www.googleapis.com/auth/monitoring.write",
]
}
lifecycle {
ignore_changes = [
"create_timeout"
]
}
}
あとがき
以前からimportコマンドの存在は知ってたのですが、昔はインポートできるリソースが限られてて使えなかったですが、最近だと割とインポートできる項目が増えてて実用的になったかなーと思ってます。
正直インポートするのがめんどくさい感じもしますが、一度コード化してgit運用すれば、変更履歴が追いやすくなったり、変更依頼をプルリクで出してもらったり、プルリク承認したら自動反映したりなど、DevOpsっぽいことしやすくなるので、めんどくさいだけのメリットもあるかも。