StatefileをAmazon S3からHCP Terraformに移行してみた(HCP Terraform API利用、VCS Driven Workflow)
TerraformのStatefileをS3から、HCP Terraform Workspace(VCS Driven Workflow)にHCP Terraform APIを使って移行してみます。
やってみた
ざっくりした流れは以下です。
- S3からStatefileをダウンロード
- HCP Terraform Workspaceを作成
- HCP Terraform APIを使って、WorkspaceにStatefileをアップロード
ディレクトリ構成(移行前)
今回は以下のディレクトリ構成を例にします。
環境差異をtfvars
で表現するパターンです。それに伴い、backend設定もterraform.tfbackend
で表現します。
.
├── envs/
│ ├── prod/
│ │ ├── terraform.tfvars
│ │ └── terraform.tfbackend
│ └── dev/
│ ├── terraform.tfvars
│ └── terraform.tfbackend
└── main.tf
backend切り替えや環境ごとのPlan・Applyは以下のように実施します。
terraform init -reconfigure -backend-config="envs/dev/terraform.tfbackend"
terraform plan -var-file envs/dev/terraform.tfvars
terraform apply -var-file envs/dev/terraform.tfvars
Terraformコード(移行前)
VPCを作成するシンプルなコードです。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.90.1"
}
}
backend "s3" {}
}
provider "aws" {
region = "ap-northeast-1"
}
variable "env" {
description = "The environment name"
type = string
}
resource "aws_vpc" "example" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "${var.env}"
}
}
bucket = "<Terraform Stateバケット名>"
region = "ap-northeast-1"
key = "<Statefileファイルパス>" # example: "hoge/terraform.tfstate"
encrypt = true
env = "dev"
HCP Terraformログイン
ローカルからHCP Terraformにログインします。
terraform login
Statefileをダウンロード
Statefileをローカルにダウンロードします。
Statefileの数分作業を繰り返します。
# AWS認証情報をセット
terraform init -reconfigure -backend-config="envs/dev/terraform.tfbackend"
terraform state pull > dev.tfstate
以下のようにファイルが保存されていればOKです。
dev.tfstate
prod.tfstate
HCP Terraform Workspaceの作成
HCP Terraformのコンソールを開きます。
Workspace
-> New
-> Workspace
-> [任意のプロジェクト]
-> Create
の順に選択します。
workflow: Version Control Workflow
VCS Provider: 移行対象のVCS Provider
repository: 移行対象のrepository
Workspace Name: Workspace名 ※
Advanced options > Terraform Working Directory: Terraform実行ディレクトリ
※環境毎にWorkspaceを作成するため環境名(dev,prod)をつけることを推奨します
以下のようにVariableの設定を求められますので、必要な値を設定しています。
terraform.tfvarsの内容を設定するイメージです。
WorkspaceからAWSへアクセスするための、Variables Setも設定しておいてください。
Statefile移行前の操作ミスによるApplyを防止するために、WorkspaceをLock
しておきます。
上記作業をStatefileの数分繰り返します。
例えば、prod.tfstate
とdev.tfstate
がある場合は、それぞれprod workspace
とdev workspace
を作成します。
HCP Terraform Tokenの準備
HCP Terraform APIを使うため、トークンを設定します。
terraform login
実行済みの場合は、デフォルトでは以下にトークンが保存されています。
cat ~/.terraform.d/credentials.tfrc.json
{
"credentials": {
"app.terraform.io": {
"token": "<トークン>"
}
}
}
トークンをシェル変数にセットします。
TOKEN=<トークン>
HCP Terraform APIを使用してStatefileを移行する
作成したWorkspaceにStatefileを移行します。
以下のAPIを利用します。
payload用のjsonファイルを準備します。
{
"data": {
"type":"state-versions",
"attributes": {
"serial": 1,
"md5": "<Statefileのmd5ハッシュ>",
"state": "<Statefileをbase64エンコードした値>"
}
}
}
data.serial
はStatefileのserial
と一致させる必要があります。
data.m5
にセットする値は以下のコマンドで作成します。
md5sum dev.tfstate
690a3f8ae079c629494a52c68757d585 dev.tfstate
data.state
は値は以下のコマンドで作成します。
cat dev.tfstate | base64
dGVycmFmb3JtLnRmc3RhdGUK
WS_ID="<Workspace ID>" # 「ws-」から始まるID、Workspace画面から確認可能
curl \
--header "Authorization: Bearer $TOKEN" \
--header "Content-Type: application/vnd.api+json" \
--request POST \
--data @prod_payload.json \
https://app.terraform.io/api/v2/workspaces/$WS_ID/state-versions
Statefile移行が成功すると、HCP Terraform上からStatefileを確認できます。
この作業も、StatefileとWorkspace IDを変更して、Statefileの数分繰り返します。
動作確認
HCP Terraform上からPlanを実行して、差分が表示されないことを確認します。
Workspace上部のUnlock
を選択しWorkspaceのlockを解除します。
New Run
-> Run Type: Plan only
の順に選択します。
Planが正常に実行されて、No changes
(差分なし)になっていることを確認します。
一応VCSとの接続が正常に行われているか確認するため、適当なPull Requestを作成しました。こちらでもPlanが実行されることを確認できました。(vpcにタグを付けるPRのため、add,1
になっています。)
これでStatefileの移行は完了です。
backendブロックの置き換え
最後に、terraform.backend
の部分をterraform.cloud
に置き換えましょう。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.90.1"
}
}
- backend "s3" {}
+ cloud {}
}
VCSへのコミットも忘れずに行いましょう。
terraform.cloud
の部分は、HCP Terraform上で実行する際は必要ありません。
次に紹介する「Tips: HCP Terraform移行後のローカルからのTerraform CLIの実行」で必要です。
Tips: HCP Terraform移行後のローカルからのTerraform CLIの実行
tfファイルの変更時にローカルからterraform plan
を実行して、変更差分を確認したいことがあると思います。
今までは、-backend-config
と-var-file
を指定して環境を切り替えていました。
terraform init -reconfigure -backend-config="envs/dev/terraform.tfbackend"
terraform plan -var-file envs/dev/terraform.tfvars
移行後は、環境変数で切り替えることができます。
export TF_CLOUD_ORGANIZATION=<HCP Terraform Organizations名>
export TF_WORKSPACE=<ワークスペース名>
terraform plan
CLIで移行する
vars-fileで環境を切り替えるパターンだと、CLIで移行するのは少し手順が煩雑です。
おすすめは、上記で紹介したAPIを使う方法です。
逆に、環境毎ディレクトリを分けるパターン(env/dev/main.tf
, env/prod/main.tf
のような)ならCLIがおすすめです。
参考までに、vars-fileで環境を分けるパターンでCLIで移行する方法に少し触れます。
vars-fileで環境を分けるパターンでCLI手順が煩雑な理由は、terraform.backend
とterraform.cloud
の記述を同時に書けないためです。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.90.1"
}
}
# これはできない
backend "s3" {}
cloud {
organization = "my-org"
workspaces {
name = "my-workspace"
}
}
}
そのため、以下のように1 Statefileの移行毎に各設定を削除・追加が必要です。
- (dev・prod)VCS Driven Workflowを作成
- (dev)reconfigureで環境切り替え
terraform init -reconfigure -backend-config="envs/dev/terraform.tfbackend"
terraform.backend
を削除、terraform.cloud
を追加- StatefileをS3からHCP Terraformに移行
terraform init -migrate-state
terraform.cloud
を削除・terraform.backend
を追加- (prod)reconfigureで環境切り替え
terraform init -reconfigure -backend-config="envs/dev/terraform.tfbackend"
terraform.backend
を削除、terraform.cloud
を追加- StatefileをS3からHCP Terraformに移行
terraform init -migrate-state
個人的には、できないことは無いが環境切り替えが多く「ミスしやすそう」という印象です。
一方、Tokenのセットやbase64エンコードが不要な点は良いと思います。
対象Statefileの数が少ない場合はvars-fileで環境を分けるパターン
でCLIを採用するのは有りだと思います。
おわりに
HCP TerraformへのStatefileの移行についてでした。
WorkspaceのWorkflow TypeはVCS Driven・CLI Drivenどちらでも手順は変わりません。
Workspaceを作成して、Terraform CLI(terraform init
)やHCP Terraform APIを使ってStatefileを移行できます。
APIを使った移行を複数のStatefile移行を自動化するPythonスクリプトを作成する記事もあったので、興味がある方はご確認ください。
tf-migrateも今回の用途では利用できると思います。
こちらも追々試していきたいと思います。
以上、AWS事業本部の佐藤(@chari7311)でした。