LoginSignup
4
0

More than 1 year has passed since last update.

Terraformのディレクトリ構成について考えてみた

Last updated at Posted at 2022-01-10

0. はじめに

  • Terraformのディレクトリ構成について改めて考えてみたときのメモです。
  • 今回久しぶりにTerraformを触るに際し、そろそろ『正解のディレクトリ構成』があるのかと思って調べて見ましたが、どうやら全ての状況に当てはまる正解というものはなく、構築するシステム構成に応じてベストなものを模索していかなければならない認識です。
  • 前提として、中規模くらいのシステム・環境ごとの差異は多少ある(特にprod/stgとdev間)、を想定しています。

1. ディレクトリ構成

採用したディレクトリ構成案

最初に結論

ディレクトリ構成
.
├── env
│   ├── prod
│   │   ├── datastore
│   │   ├── network
│   │   │   ├── main.tf
│   │   │   └── output.tf
│   │   ├── opsserver
│   │   ├── routing
│   │   ├── service
│   │   └── storage
│   ├── stg01
│   └── dev01
└── modules
    ├── datastore
    ├── network
    │   ├── main.tf
    │   ├── output.tf
    │   └── variable.tf
    ├── opsserver
    ├── routing
    ├── service
    └── storage
modules/network/main.tf
data "aws_availability_zones" "available" {
  state = "available"
}

#----------
# vpc
#----------
# vpc
resource "aws_vpc" "vpc" {
  cidr_block           = var.vpc_cidr
  instance_tenancy     = "default"
  enable_dns_hostnames = true
  tags = {
    Name = "${var.system}-${var.env}-vpc"
  }
}

# flow_log
resource "aws_flow_log" "flow_log" {
  log_destination = var.flow_log_destination
  log_destination_type = "s3"
  traffic_type = "ALL"
  vpc_id = var.vpc_cidr
}

#----------
# subnet public
#----------
# subnet_public
resource "aws_subnet" "public" {
  count             = length(var.subnet_public_cidr)
  vpc_id            = aws_vpc.vpc.id
  cidr_block        = element(var.subnet_public_cidr, count.index)
  availability_zone = data.aws_availability_zones.available.names[count.index]
  tags = {
    Name = "${var.system}-${var.env}-subnet-public-${count.index + 1}"
  }
}
modules/network/variable.tf
variable "system" {}
variable "env" {}
variable "vpc_cidr" {}
variable "flow_log_destination" {}
variable "subnet_public_cidr" {}
modules/network/output.tf
output "vpc_id" {
  value = aws_vpc.vpc.*.id[0]
}

output "subnet_public_id" {
  value = aws_subnet.public.*.id[0]
}
env/prod/network/main.tf
#----------
# Terraform
#----------
terraform {
  required_version = "0.13.2"
  backend "s3" {
    bucket  = "system-prod-deploy-tf-999999999"
    region  = "ap-northeast-1"
    key     = "tfstate"
    encrypt = true
  }
}


#----------
# Provider
#----------
provider "aws" {
  region = "ap-northeast-1"
}


#----------
# Remote State
#----------
data "terraform_remote_state" "XXX" {
  backend = "s3"

  config = {
    region = "ap-northeast-1"
    bucket = "system-prod-deploy-tf-999999999"
    key    = "tfstate.XXX"
  }
}


#----------
# Resource - Network
#----------
module "network" {
  source = "../../modules/network"

  # common
  system = "systemA"
  env    = "prod"
  # vpc
  vpc_cidr = "192.168.10.0/24"
  # flow_log
  flow_log_destination = data.terraform_remote_state.storage.outputs.s3_log_arn
  # subnet_public
  subnet_public_cidr = ["192.168.10.0/26", "192.168.10.64/26"]
env/prod/network/output.tf
output "vpc_id" {
  value = module.network.vpc_id
}

output "subnet_public_id" {
  value = module.network.subnet_public_id
}

採用した理由

  • 選定基準は、①より安全な改修・デプロイができること・②環境ごとの差異を比較しやすいこと
  • How to Create Terraform Multiple EnvironmentsのSeparated Directoriesパターンを採用
    • モジュール切り出し+環境分離+コンポーネント分割
  • 公式通り、中規模なのでmodulesを利用する・環境の切り替えにWorkSpaceは利用しない
  • 変更頻度・影響範囲・可読性・terraformコマンドの処理時間を考慮してstateファイルを分割するため、env配下もさらにmodulesに合わせてディレクトリを分割する

(参考)ディレクトリ構成案

minimal-module
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
complete-module
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── ...
├── modules/
│   ├── nestedA/
│   │   ├── README.md
│   │   ├── variables.tf
│   │   ├── main.tf
│   │   ├── outputs.tf
│   ├── nestedB/
│   ├── .../
├── examples/
│   ├── exampleA/
│   │   ├── main.tf
│   ├── exampleB/
│   ├── .../

2. 開発規約

  • modules配下は、公式通りmain.tf/variable.tf/output.tfに分ける
  • env配下は、環境ごとのdiffを取るためmain.tfに寄せる。output.tfのみmodulesに合わせて切り出す
  • 変数名などは、 サービス名_役割_項目 、でつける。重複はしないようにしつつ、シンプルにする。
    • ex. subnet_public_cidr
  • リソース名の命名規則は弊社で使っているAWSリソースの命名規則を紹介します参照
    • ex. {sysname}-{env}-{nlayer}-subnetXX
  • コメントの粒度をmodules側とenv側で合わせる
  • 極力各リソースタイプに対応するData Sourceを使って参照する
data "aws_vpc" "vpc" {
  tags = {
    service = var.service
    env     = var.env
  }
}
  • 積極的に使う関数
    • 繰り返し作成: for_each(countよりこちら), count, element
    • 文字列結合: format
  • プロバイダバージョン固定のため、 .terraform.lock.hcl ファイルをリポジトリ管理対象とする
  • コミット前に $terraform fmt -recursiveterraform validate は各自実行する
  • CIで実行するコマンド: terraform plan, terraform validate, tflint, tfsec

参考

4
0
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
4
0