背景
- そこまで大きな案件でもなく、
- 環境間の差分もあまりなさそうだったため
- 何より使ったことないから試してみようっていう好奇心
ある案件にて上記の理由から、Terraform workspaceを採用しました。
今回は、その際に実際に使ってみて感じたことや注意すべきポイントを簡潔に説明したいと思います。
Terraform workspaceについて
Terraform workspace とは、“面”をworkspaceとして管理し、同じコードベースで複数面を管理できるような仕組みです。 バックエンド(この場合S3バケット)に複数の面のtfstateファイルが作成されます。
terraform workspace -h
Usage: terraform [global options] workspace
new, list, show, select and delete Terraform workspaces.
Subcommands:
delete Delete a workspace
list List Workspaces
new Create a new workspace
select Select a workspace
show Show the name of the current workspace
まずはworkspaceを作りましょう。
terraform workspace new prd
terraform workspace new stg
terraform workspace new dev
terraform workspace list
default
dev
prd
stg
workspaceを切り替えます。
bucket = "sample-bucket-tf"
region = "ap-northeast-1"
key = "inf.tfstate"
encrypt = true
shared_credentials_file = "[$HOME/.aws/credentials]"
profile = "stg"
workspaceをセレクトして、initします。
terraform workspace select stg
terraform init -reconfigure -backend-config=backends/stg.tfbackend
で、どうだった?
辛かった。
Q: 何が辛かった?
A: ユースケースにあっていなかった
当初聞いたところでは環境差分はあまりなく、1回作って複製していこうという話でした。
しかし、そもそも環境ごとにインフラが管理するスコープが違ったり、シンプルに「この環境にはこれが必要」ということが発生しました。
公式では以下のような注釈があります。
In particular, organizations commonly want to create a strong separation between multiple deployments of the same infrastructure serving different development stages or different internal teams. In this case, the backend for each deployment often has different credentials and access controls. CLI workspaces within a working directory use the same backend, so they are not a suitable isolation mechanism for this scenario.
平たく言うと dev / stg / prd のような開発段階の違う環境を管理する場合には不向きとのこと。
逆に一般的なユースケースとして以下が挙げられていました。
A common use for multiple workspaces is to create a parallel, distinct copy of a set of infrastructure to test a set of changes before modifying production infrastructure.
つまり、同じ環境を複数個作成する、本番を変更する前のテストとしてコピーを作成する みたいなこと。
ここからは上記に合わないアンチパターンをどストライクで踏んだ私が、どういう点が不向きなのかを体験をもとに話します。
コーディングが煩雑になる
workspace名を変数にしてリソースの有無を表現することになるので、このような記述があります。
resource "aws_lb" "alb" {
name = "${var.name}"
load_balancer_type = "application"
internal = var.enable_internal
idle_timeout = 60
enable_deletion_protection = (
terraform.workspace == "add-dev" ? false :
terraform.workspace == "dev" ? false : true
)
コスト最適化で環境ごとにインスタンスサイズや数、スポットインスタンスで起動するようにするなどやりますよね? そのたびに環境差分が多くなると、こういった記法が乱立し、その結果コーディングが煩雑になります。
バージョンアップをdev→stg→prdのように環境を追って順繰りに行えない
Core, Providerともにバージョンアップ作業しますよね?
基本的には上記のように環境を追って実施していくと思います。
以下のようなterraformブロックのrequired_versionを書き換えて、
再init → 必要に応じて修正 → 差分解消・apply が基本的な流れだと思います。
terraform {
required_version = "1.3.5"
backend "s3" {
}
required_providers {
aws = "4.39.0"
kubernetes = {
source = "hashicorp/kubernetes"
version = ">=2.16.0"
}
tls = {
source = "hashicorp/tls"
version = ">= 3.0"
}
}
}
しかし、terraformブロック自体もlockファイルも環境ごとに用意できません。
先ほどの一般的なユースケースを鑑みるとそりゃそうだよなと思いますので、確かに納得感はあります。
まとめ
- dev / stg / prdのように環境差分を吸収するような一般的な目的で使うものではない
- 初手はワーキングディレクトリの切り替えで対応することを考えるでよいと思う
- 逆に複数人に全く同じ開発環境を払い出したり、本番前のテストapplyなどでは有用に感じる