インフラの状態ファイルを、クラウドに保存する理由と実装方法を紹介します。
はじめに
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" } }
- hash_key, name
ロック目的で使用する場合、”LockID”とする必要がある
Backend Type: s3 | Terraform | HashiCorp DeveloperTerraform can store state remotely in S3 and lock that state with DynamoDB.
作成
terraform planにて作成されるリソースの確認、
$ terraform plan
terraform applyにて作成の実行。
$ terraform apply
...
Enter a value: yes
...
作成されていたら、完了です。
ちなみに、このtfstateファイルはローカルに保存されます。
使用方法
実際に作成したバケットに保存するには、初期化コマンドで設定を読み込ませることと、backendでs3を使用する記述が必要です。
設定ファイル作成と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か何かに以下の記述を追加して、backendにS3使用の有無を記載します。
terraform { backend "s3" {} }
初期化コマンド (terraform init)
あとは、terraformの初期化時に設定ファイルを読み込ませます。
$ terraform init -backend-config=backend.config
これの後にインフラを更新してみて、s3にtfstateが生成と、dynamoDBのLockIDが更新されていれば完了です。
お疲れさまでした!
また、既存のインフラプロジェットのtfstateを保存したい場合は、
$ terraform init -backend-config=env/backend.config -upgrade
上記のコマンド叩いて更新すればOKです。
おわりに
最後までご覧いただきありがとうございます!
何かわからいことがあったら、気軽コメントでもしてください。
実際に、terraformでAWS環境構築する記事も作成しているので、そちらの記事も参考になると思います。
コメント