GCPをTerraformで始める

# 作成するもの

- Project: `naka-gcp-training` 
- Service Account: `terraform`
- Bucket: `naka-gcp-training-2020`

予め変数に入れておく (適宜変更)

```
PROJECT_ID=naka-gcp-training
SERVICE_ACCOUNT=terraform
BUCKET=naka-gcp-training-2020
```


# ステップ

## `gcloud`を設定

1. GCPのアカウントを作成
1. `gcloud`をインストール
2. `gcloud auth login` -> リンクが出てくるので、ブラウザで開いてなすがままにする

    ```
    gcloud auth login
    Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?client_id=xxxxx <- これをクリック

    You are now logged in as [test@mail.com].
    Your current project is [xxxxx].  You can change this setting by running:
    $ gcloud config set project PROJECT_ID
    ```

## Projectを設定

リソースはプロジェクト以下にあるのでまず先に操作するプロジェクトを作成する

1. Project作成 `naka-gcp-training`

    ```
    gcloud projects create $PROJECT_ID
    Create in progress for [https://cloudresourcemanager.googleapis.com/v1/projects/naka-gcp-training].
    Waiting for [operations/cp.5442491498066710887] to finish...done.
    Enabling service [cloudapis.googleapis.com] on project [naka-gcp-training]...
    Operation "operations/acf.af0e63bc-93ff-4233-8d0f-11e726c1cd49" finished successfully.
    ```

1. プロジェクト設定


    ```
    gcloud config set project $PROJECT_ID
    ```

2. APIを有効化

    ```
    gcloud services enable compute.googleapis.com
    ```

    ```
    ERROR: (gcloud.services.enable) FAILED_PRECONDITION: Billing account for project '602548642320' is not found. Billing must be enabled for activation of service(s) 'compute.googleapis.com,compute.googleapis.com,compute.googleapis.com' to proceed.
    ```
    上記のエラーが出たらコンソールで「お支払い」から連携すればOK

## サービスアカウントを用意

Terraformでリソースをいじるときの認証

1. サービスアカウントの作成

    ```
    gcloud iam service-accounts create $SERVICE_ACCOUNT 
    Created service account [terraform].
    ```

1. サービスアカウントへ`roles/editor`権限を与える

    ```
    gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:terraform@$PROJECT_ID.iam.gserviceaccount.com --role roles/editor
    Updated IAM policy for project [naka-gcp-training].
    bindings:
    - members:
      - serviceAccount:terraform@naka-gcp-training.iam.gserviceaccount.com
      role: roles/editor
    - members:
      - user:xxxxx@gmail.com
      role: roles/owner
    etag: BwW2PH_3moY=
    version: 1
    ```

1. サービスアカウントのキーを発行する


    ```
    gcloud iam service-accounts keys create terraform-key.json --iam-account terraform@$PROJECT_ID.iam.gserviceaccount.com
    created key [0e4062f4cdc91618fcd590d1c45f699a4057d7f8] of type [json] as [terraform-key.json] for [terraform@naka-gcp-training.iam.gserviceaccount.com]
    ```

1. keyのpathを`GOOGLE_APPLICATION_CREDENTIALS`に入れておく (`~/.bashrc` とかに入れておけば毎回やらなくて住む)

    ```
    export GOOGLE_APPLICATION_CREDENTIALS=$PWD/terraform-key.json
    ```

## Terraformの準備

1. TerraformのBackend用にbucketを作成

    ```
    gsutil mb -p $PROJECT_ID -c multi_regional -l asia gs://$BUCKET
    Creating gs://naka-gcp-training-2020/...
    ```

    チェック

    ```
    gsutil ls -p $PROJECT_ID 
    gs://naka-gcp-training-2020/
    ```

1. `backend.tf`を準備

    ```
    terraform {
      backend "gcs" {
        bucket = "naka-gcp-training-2020"
        prefix = "terraform/test"
      }
    }
    ```

1. `provider.tf`を準備

    ```
    provider "google" {
      project = "naka-gcp-training"
      region  = ""
    }
    ```

1. `terraform init`

    ```
    terraform init                        

    Initializing the backend...

    Initializing provider plugins...
    - Finding latest version of hashicorp/google...
    - Installing hashicorp/google v3.50.0...
    - Installed hashicorp/google v3.50.0 (signed by HashiCorp)
    ...
    ```

## Terraformでリソースの作成と削除

1. 初GCPリソースをTerraformで準備 `main.tf`

    ```
    touch test.txt
    ```

    ```
    resource "google_storage_bucket_object" "test" {
      name   = "test/gcp-training/test.txt"
      source = "test.txt"
      bucket = "naka-gcp-training-2020"
    }
    ```

1. `terraform plan`

    ```bash
    terraform plan
    Refreshing Terraform state in-memory prior to plan...
    The refreshed state will be used to calculate this plan, but will not be
    persisted to local or remote state storage.


    ------------------------------------------------------------------------

    An execution plan has been generated and is shown below.
    Resource actions are indicated with the following symbols:
      + create

    Terraform will perform the following actions:

      # google_storage_bucket_object.test will be created
      + resource "google_storage_bucket_object" "test" {
          + bucket         = "naka-gcp-training-2020"
          + content_type   = (known after apply)
          + crc32c         = (known after apply)
          + detect_md5hash = "different hash"
          + id             = (known after apply)
          + md5hash        = (known after apply)
          + media_link     = (known after apply)
          + name           = "test/gcp-training/test.txt"
          + output_name    = (known after apply)
          + self_link      = (known after apply)
          + source         = "test.txt"
          + storage_class  = (known after apply)
        }

    Plan: 1 to add, 0 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.
    ```

1. `terraform apply`

    ```
    terraform apply

    ...
      Enter a value: yes

    ...

    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
    ```

1. objectができてるのを確認

    ```
    gsutil ls gs://naka-gcp-training-2020/test/gcp-training
    gs://naka-gcp-training-2020/test/gcp-training/test.txt
    ```

1. `terraform destroy`

    ```
    terraform destroy
    ...

      Enter a value: yes

    google_storage_bucket_object.test: Destroying... [id=naka-gcp-training-2020-test/gcp-training/test.txt]
    google_storage_bucket_object.test: Destruction complete after 1s

    Destroy complete! Resources: 1 destroyed.
    ```