terraform tfstateファイルを管理する

Terraform

インフラの状態ファイルを、クラウドに保存する理由と実装方法を紹介します。

はじめに

terraformでインフラを作成した際、tfstateファイルが生成されます。

このファイルには、AWS等のインフラ状態が保存されます。

{
  "version": 4,
  "terraform_version": "0.14.4",
  "serial": 5,
  "lineage": "46cbcc47-f96f-6d57-8e49-b403f5c91f05",
  "outputs": {},
  "resources": [   # <---- 作成されたリソースのリスト
    {
      "mode": "managed",
      "type": "aws_dynamodb_table", # <---- 作成したリソース
       ...
    }
}

クラウドに保存する理由

デフォルトでは、tfstateはローカル上に保存されます。GitでいうとRemoteにコミットされていないローカルChangesのようなものの状態です。

ローカル保存しておくと複数人で開発する場合、Single source of truthでなくなってしまうので、tfstateをクラウド上に保存することで同じステートを元にインフラを構築できるようになります。(gitでローカルコミットをリモートにPushする)

また、同時にtfstateを変更しようとした場合の衝突をさけるために、DynamoDBを使ってLockを取得してから、terraform applyを実行できるようにも設定が可能です。

クラウド上に保存しなければ、ファイルを削除してしまったら、ローカルコミットでもないのでgitのようにトラッキングできずリカバリーできない状態に陥る可能性があります。

まとめると、

  • クラウド上に保存することで、同時にインフラの構築が可能
  • ファイルをクラウド上に保存することで、保存性を高める
  • 更新のロックも可能なので、競合状態も避けれる

以上のことで、tfstateはクラウド上に保存して安全にインフラ構築しましょう!

実装方法

ここから、実装方法を紹介します。

S3バケット・DynamoDB作成

クラウドとしてS3バケットDynamoDBを作成します。

事前準備

S3バケット・DynamoDB用のインフラ構成ファイルを用意して、そちらで構築していきます。

ファイル構成は以下です。

$ tree
.
├── backend.tf
├── provider.tf
└── variable.tf

variable.tf

variable "aws_region" {
  default = "ap-northeast-1"
}

variable "aws_profile" {
  type    = string
  default = "<profile_name>"
}

variable "s3_bucket_name" {
  type    = string
  default = "<bucket_name>"
}

variable "dynamodb_name" {
  type    = string
  default = "<dynamodb_name>"
}
  • aws_profile
    s3・DynamoDB作成の権限が与えられたアカウントを指定します。
    事前にAWS CLIにてaws configを実行してAccess Keyなど入力しておいてください。
  • s3_bucket_name
    s3
    バケット名は全世界でユニークでないといけないので注意が必要です。
  • dynamodb_name
    DynamoDB
    のテーブル名を指定します。

provider.tf

provider "aws" {
  region  = var.aws_region
  profile = var.aws_profile
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.27"
    }
  }
}

S3バケット作成

backend.tf

resource "aws_s3_bucket" "terraform-state" {
  bucket = var.s3_bucket_name

  # terraform destroyによって削除されないよう設定
  lifecycle {
    prevent_destroy = true
  }

  # AES256でファイルを暗号化
  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm = "AES256"
      }
    }
  }

  tags = {
    Terraform = "true"
    Name      = "terraform"
  }
}
  • lifecycle
    terraform destroyによって削除されないよう設定できます。
  • server_side_encryption_configuration
    ファイルの暗号化を設定できます。

DynamoDB作成

backend.tf

resource "aws_dynamodb_table" "terraform-and-rails-state-lock" {
  name         = var.dynamodb_name
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID" # 値はLockIDである必要がある

  attribute {
    name = "LockID" # 値はLockIDである必要がある
    type = "S"
  }

  tags = {
    Terraform = "true"
    Name      = "terraform"
  }
}

作成

terraform planにて作成されるリソースの確認、

$ terraform plan

terraform applyにて作成の実行。

$ terraform apply
...
Enter a value: yes
...

作成されていたら、完了です。

ちなみに、このtfstateファイルローカルに保存されます。

使用方法

実際に作成したバケットに保存するには、初期化コマンドで設定を読み込ませることと、backends3を使用する記述が必要です。

設定ファイル作成とbackend対応

backend.configとでも設定ファイルを作成しましょう。

# S3バケット名
bucket         = "<bucket_name>"
# S3 tfstate保存ファイルパス
key            = "state/terraform.tfstate"
region         = "ap-northeast-1"
# dynamoDB テーブル名
dynamodb_table = "<dynameDB_name>"
encrypt        = true

S3バケット名とファイルパス、dynamoDB table名を先程作成したものを設定しておきます。

さらに、main.tfか何かに以下の記述を追加して、backendS3使用の有無を記載します。

terraform {
  backend "s3" {}
}

初期化コマンド (terraform init)

あとは、terraformの初期化時に設定ファイルを読み込ませます。

$ terraform init -backend-config=backend.config

これの後にインフラを更新してみて、s3tfstateが生成と、dynamoDBのLockIDが更新されていれば完了です。

お疲れさまでした!

また、既存のインフラプロジェットのtfstateを保存したい場合は、

$ terraform init -backend-config=env/backend.config -upgrade

上記のコマンド叩いて更新すればOKです。

おわりに

最後までご覧いただきありがとうございます!

何かわからいことがあったら、気軽コメントでもしてください。

実際に、terraformAWS環境構築する記事も作成しているので、そちらの記事も参考になると思います。

コメント

タイトルとURLをコピーしました