🦔

Terraform最初の一歩:tfStateをS3バケットで管理する

2022/11/29に公開

はじめに

チーム開発するためにはtfStateをリモートで管理する必要があります。
ここではtfStateをリモート管理するためのS3バケットと、tfStateの同時編集をロックするDynamoDBを作成します。

ディレクトリ構造

backendディレクトリの中でtfStateをリモート管理するためのS3バケットおよびDynamoDBテーブルを用意します。このS3バケットおよびDynamoDBのtfStateはローカルPCで管理されることになります。
ここで作成したS3バケットでtfStateを管理したいリソースはenvsディレクトリの中に記述します。
backendenvsディレクトリの中に、それぞれstgprodなど別々の環境を用意します。

root
│
├── backend
│   ├── stg
│   │   ├── main.tf
│   │   ├── terraform.tfvars
│   │   └── variable.tf
│   └── prod
│       ├── ...
│
├── envs
│   └── stg
│       ├── main.tf
│       ├── ...
│ 
└── modules
    ├── backend_s3_dynamoDB
    │   ├── main.tf
    │   └── variable.tf
    ├── ...

tfStateを管理するS3バケットとDynamoDBの作成

前述したように、S3バケットとDynamoDBをのtfStateはローカルPCの中で管理されることになります。
事前にAWSのprofileを設定しておきます。

コード

backend/stg/main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }
  required_version = ">= 1.2.0"
}

provider "aws" {
  region                   = "ap-northeast-1"
  shared_credentials_files = ["$HOME/.aws/credentials"]
  profile                  = "default"
}

module "backend_s3_and_dynamoDB" {
  source        = "../../modules/backend_s3_dynamoDB"
  bucket_name   = var.bucket_name
  dynamoDB_name = var.dynamoDB_name
}
backend/stg/variable.tf
variable "bucket_name" {
  type    = string
  default = "tfstate-bucket-xxxx" //全世界でユニークなバケット名である必要があります。
}
variable "dynamoDB_name" {
  type    = string
  default = "terraform_state_lock"
}
modules/backend_s3_dynamoDB/main.tf
resource "aws_s3_bucket" "terraform_state" {
  bucket = var.bucket_name

  lifecycle {
    prevent_destroy = true
  }
}
resource "aws_s3_bucket_acl" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  acl    = "private"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.bucket
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

resource "aws_s3_bucket_versioning" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_dynamodb_table" "terraform_state_lock" {
  name           = var.dynamoDB_name
  hash_key       = "LockID"
  read_capacity  = 20
  write_capacity = 20

  attribute {
    name = "LockID"
    type = "S"
  }
}

実行

$ cd ./backend/stg
$ terraform init
$ terraform plan
$ terraform apply

作成したS3バケットでtfStateを管理する

実際に作成するリソースはenvs/stgフォルダの中に作成します。
先ほど作成したS3バケットとDynamoDBを使ってtfStateを管理します。

envs/stg/main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }
  required_version = ">= 1.2.0"

  backend "s3" {
    bucket                  = "tfstate-bucket-xxxx"
    key                     = "stg/terraform.tfstate"
    region                  = "ap-northeast-1"
    dynamodb_table          = "terraform_state_lock"
    shared_credentials_file = "$HOME/.aws/credentials"
    profile                 = "default"
  }
}

provider "aws" {
  region                   = "ap-northeast-1"
  shared_credentials_files = ["$HOME/.aws/credentials"]
  profile                  = "default"
}

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

実行

$ cd ./envs/stg
$ terraform init
$ terraform plan
$ terraform apply

参考

https://zenn.dev/yutamiona/articles/b457ee3c9934d4

Discussion