0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Terraform】remote state使ってみた

0
Posted at

はじめに

今回は、以下の記事で作成した「単一の.tfファイル」のTerraformプロジェクトを、「remote state」を使用して、クロススタック化してみました。
少しでも参考になれば幸いです。

remote stateとは

remote stateとは、別のTerraformプロジェクト(スタック)の状態ファイル(.tfstate)を参照する仕組みのことです。
通常Terraformは「自分のstateしか知らない」ですが、remote stateを使うと別スタックのoutput値を取得できるようになります。

特徴

・取得(参照)できるのはoutputだけ
・読み取り専用で書き換え不可
・backendが一致している必要あり

メリット

・スタック(デプロイ単位)を分割できる
・VPCなどを共通化することで再利用性が高まる

デメリット

・強い依存(結合)になるため、更新/バージョン管理時に注意が必要です

本番環境では、remote stateの使用は最小限にし、モジュールやParameter Store / Secrets Manager等を使用した、外部stateに依存しない構成が推奨されています。

さっそく実装してみた

今回のプロジェクト構成

.
├── envs/
│   └── dev/
│       ├── network/
│       │   ├── main.tf
│       │   ├── outputs.tf
│       │   ├── backend.tf
│       │   └── providers.tf
│       │
│       └── compute/
│           ├── main.tf
│           ├── data_remote_state.tf
│           ├── backend.tf
│           └── providers.tf

① networkディレクトリの作成

Terraformプロジェクト用のディレクトリを作成し、配下にenvs/dev/ディレクトリを作成します(実務での環境分離を想定しています)

envs/dev/配下にnetwork/ディレクトリを作成し、配下に以下の
backend.tf
provider.tf
main.tf
outputs.tf
を作成します。

envs/dev/network/backend.tf
terraform {
  required_version = ">= 1.11.0"

  backend "s3" {
    bucket       = "my-terraform-state-bucket"
    key          = "dev/network/terraform.tfstate"
    profile      = "project-a-dev"
    region       = "ap-northeast-1"
    encrypt      = true
    use_lockfile = true
  }
}
envs/dev/network/provider.tf
provider "aws" {
  profile = "project-a-dev"
  region  = "ap-northeast-1"
}
envs/dev/network/main.tf
# VPC
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "test-vpc"
  }
}

# Internet Gateway
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "test-igw"
  }
}

# Subnet(Public)
resource "aws_subnet" "public_a" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "ap-northeast-1a"
  map_public_ip_on_launch = true

  tags = {
    Name = "public-subnet-a"
  }
}

# Route Table
resource "aws_route_table" "public_rt" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "public-rt-a"
  }
}

# Route(Internet向け)
resource "aws_route" "public_route" {
  route_table_id         = aws_route_table.public_rt.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.igw.id
}

# SubnetとRouteTableの関連付け
resource "aws_route_table_association" "public_assoc" {
  subnet_id      = aws_subnet.public_a.id
  route_table_id = aws_route_table.public_rt.id
}
envs/dev/network/outputs.tf
output "vpc_id" {
  value = aws_vpc.main.id
}

output "subnet_id" {
  value = aws_subnet.public_a.id
}

② computeディレクトリの作成

envs/dev/配下にcompute/ディレクトリを作成し、配下に以下の
backend.tf
provider.tf
main.tf
data_remote_state.tf
を作成します。

envs/dev/compute/backend.tf
terraform {
  required_version = ">= 1.11.0"

  backend "s3" {
    bucket       = "my-terraform-state-bucket"
    key          = "dev/compute/terraform.tfstate"
    profile      = "project-a-dev"
    region       = "ap-northeast-1"
    encrypt      = true
    use_lockfile = true
  }
}
envs/dev/compute/provider.tf
provider "aws" {
  profile = "project-a-dev"
  region  = "ap-northeast-1"
}
envs/dev/compute/main.tf
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

# SG
resource "aws_security_group" "public_sg" {
  name   = "public-sg"
  vpc_id = data.terraform_remote_state.network.outputs.vpc_id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# EC2
resource "aws_instance" "ec2_instance" {
  ami           = data.aws_ami.amazon_linux.id
  instance_type = "t3.micro"

  subnet_id = data.terraform_remote_state.network.outputs.subnet_id

  vpc_security_group_ids = [aws_security_group.public_sg.id]

  user_data = <<-EOF
              #!/bin/bash
              dnf update -y
              dnf install -y httpd
              systemctl start httpd
              systemctl enable httpd
              echo "<h1>Hello from EC2!!!!!</h1>" > /var/www/html/index.html
              EOF
}
envs/dev/compute/data_remote_state.tf
data "terraform_remote_state" "network" {
  backend = "s3"

  config = {
    bucket  = "my-terraform-state-bucket"
    key     = "dev/network/terraform.tfstate"
    profile = "project-a-dev"
    region  = "ap-northeast-1"
  }
}

③ S3作成

以下のコマンドを順に実行し、各スタックの状態ファイル保存用のS3をデプロイします。
(必要に応じて暗号化/バージョニング設定等を行います)

zsh
aws s3api create-bucket \
  --bucket my-terraform-state-bucket \
  --create-bucket-configuration LocationConstraint=ap-northeast-1 \
  --profile project-a-dev

④ networkをデプロイ

依存関係を意識し、networkを先にデプロイします。
以下のコマンドを順に実行します。

zsh
cd network

# 初期化
terraform init

# コード整形
terraform fmt

# 構文チェック
terraform validate

# 差分チェック
terraform plan

# 適用(デプロイ)
terraform apply

⑤ computeをデプロイ

同様の手順でcomputeをデプロイすれば完了です。

削除手順

削除は「依存関係の逆順」で行っていきます。

① computeの削除

以下のコマンドを順に実行し、まずはcomputeのリソースを削除します。

zsh
cd compute

terraform destroy

② networkの削除

次に、networkのリソースを削除します。

zsh
cd network

terraform destroy

③ S3の削除

最後に、S3バケットも削除します。
terraform管理外で作成したリソースのため、手動で削除します。

zsh
# バケット自体は削除されず、配下の全オブジェクトを一括削除(事前確認)
aws s3 rm s3://your-bucket-name --recursive --dryrun --profile project-a-dev

# 実行(バージョニングが有効になっている場合過去バージョンは残る)
aws s3 rm s3://your-bucket-name --recursive --profile project-a-dev

# 中身が空のバケット自体を削除(バージョニングが有効になっている場合エラー)
aws s3api delete-bucket --bucket your-bucket-name --profile project-a-dev

今回は以上になります!

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?