Terraform の状態を Cloud Storage バケットに保存する


このチュートリアルでは、Terraform の状態を Cloud Storage バケットに保存する方法について説明します。

デフォルトでは、Terraform はローカルの terraform.tfstate という名前のファイルに状態を保存します。複数のユーザーが Terraform を同時に実行していて、各マシンが現在のインフラストラクチャを独自に認識している場合は、このデフォルト構成が原因でチームでの Terraform の使用が難しくなる場合があります。

このページでは、このような問題を回避するために、Cloud Storage バケットを参照するリモート状態を構成する方法について説明します。リモート状態は Terraform バックエンドの機能です。

目標

このチュートリアルでは、次の方法について説明します。

  • Terraform を使用して、Terraform の状態を保存する Cloud Storage バケットをプロビジョニングする。
  • Terraform 構成ファイルにテンプレートを追加して、ローカル バックエンドから Cloud Storage バケットに状態を移行する。

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

Cloud Storage では、ストレージ、読み取り / 書き込みオペレーション、下り(外向き)ネットワーク、レプリケーションで費用が発生します。

このチュートリアルの Cloud Storage バケットでは、オブジェクトのバージョニングを有効にして、デプロイの履歴を保持しています。オブジェクトのバージョニングを有効にすると、ストレージ費用が増加します。これは、古い状態のバージョンを削除するようにオブジェクトのライフサイクル管理を構成することで軽減できます。

始める前に

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    Cloud Shell には Terraform がプリインストールされています。

  2. ローカルシェルを使用している場合は、次の操作を行います。

  3. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  4. Make sure that billing is enabled for your Google Cloud project.

  5. Enable the Cloud Storage API:

    gcloud services enable storage.googleapis.com
  6. Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/storage.admin

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

    別の方法として、次の権限を含むカスタム IAM ロールを作成することもできます。

    • storage.buckets.create
    • storage.buckets.list
    • storage.objects.get
    • storage.objects.create
    • storage.objects.delete
    • storage.objects.update

    バケットとバケットに保存されている状態ファイルへのアクセスを制御することをおすすめします。バケットに対する管理者権限は、少数のユーザー(メインのクラウド管理者と、代替またはバックアップ管理者として機能するユーザーなど)にのみ付与してください。それ以外のデベロッパーには、バケット内のオブジェクトへの書き込みと読み取りのみを許可する権限を付与してください。

環境を準備する

  1. Terraform サンプルを含む GitHub リポジトリのクローンを作成します。

    git clone https://github.com/terraform-google-modules/terraform-docs-samples.git --single-branch
    
  2. 作業ディレクトリを変更します。

    cd terraform-docs-samples/storage/remote_terraform_backend_template
    

Terraform ファイルを確認する

  1. main.tf ファイルを確認してみましょう。

    cat main.tf
    

    出力は次のようになります。

    resource "random_id" "default" {
      byte_length = 8
    }
    
    resource "google_storage_bucket" "default" {
      name     = "${random_id.default.hex}-terraform-remote-backend"
      location = "US"
    
      force_destroy               = false
      public_access_prevention    = "enforced"
      uniform_bucket_level_access = true
    
      versioning {
        enabled = true
      }
    }
    
    resource "local_file" "default" {
      file_permission = "0644"
      filename        = "${path.module}/backend.tf"
    
      # You can store the template in a file and use the templatefile function for
      # more modularity, if you prefer, instead of storing the template inline as
      # we do here.
      content = <<-EOT
      terraform {
        backend "gcs" {
          bucket = "${google_storage_bucket.default.name}"
        }
      }
      EOT
    }

    このファイルでは、次のリソースを記述しています。

    • random_id: Cloud Storage バケットの名前を一意にするために、Cloud Storage バケット名に追加されます。
    • google_storage_bucket: 状態ファイルを保存する Cloud Storage バケット。このバケットの構成では、次のプロパティが使用されています。
      • バケット内にオブジェクトが存在する場合にバケットが削除されないように、force_destroyfalse に設定されています。この設定により、バケット内の状態情報が誤って削除されることはありません。
      • バケットの内容が誤って一般公開されないように、public_access_preventionenforced に設定されています。
      • アクセス制御リストではなく IAM 権限を使用して、バケットとそのコンテンツへのアクセスを制御できるように、uniform_bucket_level_accesstrue に設定されています。
      • 以前のバージョンの状態がバケットに保持されるように、versioning は有効に設定されています。
    • local_file: ローカル ファイル。このファイルの内容に従って、Terraform はバケット作成後に Cloud Storage バケットをリモート バックエンドとして使用します。

Cloud Storage バケットをプロビジョニングする

  1. Terraform を初期化します。

    terraform init
    

    terraform init を初めて実行する場合、main.tf ファイルで指定した Cloud Storage バケットはまだ存在していません。そのため、Terraform は、状態をローカル ファイル システムに保存するために、ローカル バックエンドを初期化します。

  2. 構成を適用して、main.tf ファイルに記述されているリソースをプロビジョニングします。

    terraform apply
    

    プロンプトが表示されたら、「yes」と入力します。

    terraform apply を初めて実行する場合、Terraform は状態を保存する Cloud Storage バケットをプロビジョニングします。また、ローカル ファイルも作成します。Terraform はこのファイルの内容に従って Cloud Storage バケットをリモート バックエンドとして使用し、状態を保存します。

状態を Cloud Storage バケットに移行する

  1. Terraform の状態をリモートの Cloud Storage バックエンドに移行します。

    terraform init -migrate-state
    

    Terraform は状態ファイルがすでにローカルに存在することを検出し、状態を新しい Cloud Storage バケットに移行するように求めます。プロンプトが表示されたら、「yes」と入力します。

このコマンドを実行すると、Terraform の状態が Cloud Storage バケットに保存されます。Terraform は、コマンドを実行する前にこのバケットから最新の状態を pull し、コマンドを実行した後に最新の状態をバケットに push します。

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

プロジェクトを削除する

このページで使用したリソースに対して Google Cloud アカウントで課金されないようにするには、次の操作を行います。

  1. main.tf ファイルを開きます。

  2. google_storage_bucket.default リソースで、force_destroy の値を true に更新します。

  3. 更新した構成を適用します。

    terraform apply
    

    プロンプトが表示されたら、「yes」と入力します。

  4. 状態ファイルを削除します。

    rm backend.tf
    
  5. バックエンドをローカルとして再構成します。

    terraform init -migrate-state
    

    プロンプトが表示されたら、「yes」と入力します。

  6. 次のコマンドを実行して、Terraform リソースを削除します。

    terraform destroy
    

    プロンプトが表示されたら、「yes」と入力します。

次のステップ