LoginSignup
19
16

More than 3 years have passed since last update.

既存のGCPプロジェクトをterraformで管理できるようにする

Last updated at Posted at 2018-10-29

経緯

  • 共有VPCの機能検証のためにとりあえずコンソールからプロジェクト作って設定とかしてた
  • ただ、今後考えるとコードで管理してCIで反映とかしたくなったので、手で作った分をコードとして管理できるようにしたかった

注意

2019/05/07追記

GCP版Terraformingが来たのでもうこんなめんどくさいことやらんでもいいんやで

前提条件

  • 以下のような環境がコンソールを用いて作成されている(細かい設定は省略)
    • VPC
      • name: wordpress
      • mode: カスタム
      • subnet:
        • wordpress-asia-northeast1
          • region: asia-northeast1
          • range: 10.0.0.0/9
    • Firewall rule
      • wordpress-allow-icmp
        • icmpでの通信を許可
      • wordpress-allow-ssh
        • tcp:22での通信を許可
      • wordpress-allow-https
        • tcp:443での通信を許可
        • target tag: wordpress
    • GCE
      • name: wordpress
      • region: asia-northeast1
      • zone: asia-northeast1-b
      • machine type: micro
      • network: wordpress
      • subnetwork: wordpress-asia-northeast1
      • network tags: wordpress

事前準備

  • terraformの設定ファイル格納用のGCSバケット作成(権限あればなんでもいい)
  • 対象プロジェクトからcloud shellを起動(作業環境)
  • 作業用ディレクトリ切ってterraform実行用のスクリプト配置
terraform.sh
#!/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。
  • 書き方がわからない場合は公式ドキュメントを探すと吉。
wordpress.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"]
}

# 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しないといけないかも。
import.sh
$ ./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ファイルも載せます。

wordpress.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っぽいことしやすくなるので、めんどくさいだけのメリットもあるかも。

19
16
1

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
19
16