過去にコンソール操作や CLI によって手動で作成された 既存 AWS リソースを Terraform(v1.5以上)の管理下に移行する際の手順をまとめました。
単に import ブロックで state を取り込むだけでなく、terraform plan -generate-config-out で生成されたコードをベースに、リファクタリングしながら移行するワークフローです。
ネット上で同様の具体的な手順が見当たらなかったため、自作した手順となります。備忘録を兼ねて共有します。
手順
ここでは一例として、CloudWatch ロググループを Terraform 管理下へ移行していきます。
他リソースでも同様の手順で対応可能です。
1、 import ブロック定義
imports.tf(命名任意)にて、import ブロックを定義します。
to に記載するアドレスは任意でOKです(どのみち手順6で修正するため)
import {
to = aws_cloudwatch_log_group.error
id = "stg-error"
}
2、 HCL 叩き台生成
import ブロックを定義したディレクトリにて、下記コマンドを実行します。
# generated.tf の命名は任意
terraform plan -generate-config-out=_generated/generated.tf
ポイント
- 生成されるHCL叩き台に「定義として不正な箇所」があった場合にエラーが出るのを防ぐため、サブディレクトリ配下に出力します
- 生成されたHCL叩き台は、どのみち後続でリファクタリングするので、一旦エラーは無視して問題ありません
コマンドを実行すると下記が起こる想定
- 差分として下記が出力される(n は import 対象リソース数)
- n import
- generated.tf に HCL 叩き台が生成される
# 生成された HCL 叩き台
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.
# __generated__ by Terraform from "stg-error"
resource "aws_cloudwatch_log_group" "error" {
kms_key_id = null
log_group_class = "STANDARD"
name = "stg-error"
name_prefix = null
retention_in_days = 0
skip_destroy = false
tags = {}
tags_all = {}
}
3、 リファクタリング
生成された HCL 叩き台をリファクタリングします。
ここでは例として、locals変数 + for_each + モジュール呼び出し構成へリファクタリングを行います。
3-1、 叩き台 HCL を最小限の定義に削る
デフォルト値は省略するなど、最小限の定義に変える。
# 例:CloudWatchロググループ「stg-error」の叩き台を最小限の定義に削った結果
resource "aws_cloudwatch_log_group" "error" {
name = "stg-error"
}
3-2、 locals変数 + for_each + モジュール呼び出し構成へ
# environments/staging/cw_log_groups.tf
locals {
cw_log_groups = {
stg_error = {
name = "stg-error"
}
}
}
module "cw_logs" {
source = "../../modules/cw-log-group"
for_each = local.cw_log_groups
name = each.value.name
}
# modules/cw-log-group/variables.tf
variable "name" {
type = string
}
# modules/cw-log-group/main.tf
resource "aws_cloudwatch_log_group" "this" {
name = var.name
}
4、 叩き台 HCL 削除
「2、HCL 叩き台生成」で生成した叩き台 HCL は、あくまで「3、リファクタリング」で 最適な設計へリファクタリングするための参考情報として使うことが目的。そのため、以降は不要になるので削除します(全ての手順が終わってから削除してもOK)
5、 import ブロックの to を適切なアドレスに書き換える
本来はモジュール構成で import したいため、書き換える。
import {
to = module.cw_logs["stg_error"].aws_cloudwatch_log_group.this
id = "stg-error"
}
6、 terraform plan 実行して差分確認
下記コマンドを実行することで、HCL 定義と実環境の対象リソースの状態を比較する。
terraform plan
実行結果が「Plan: n to import, 0 to add, 0 to change, 0 to destroy.」であれば、HCL 定義が実環境の対象リソースの状態と一致しているためOK。差分が出ている場合は、HCL 定義が実環境リソース状態と一致していないため、必要に応じて修正を行う。
7、 terraform apply 実行。Terraform管理下へ取り込む
下記コマンドを実行し「 import ブロックの id で指定したリソース」を「 to で指定したアドレス」で Terraform 管理下 に取り込む。
terraform apply
8、 (任意) import ブロックをコメントアウト、または削除
Terraform 管理下への移行が完了したため、必要に応じて import ブロックをコメントアウトまたは削除する(任意)
# import {
# to = module.cw_logs["stg_error"].aws_cloudwatch_log_group.this
# id = "stg-error"
# }
9、 再度 terraform plan で差分確認
念の為、再度下記コマンドを実行する。
terraform plan
下記のように差分 0 であれば、Terraform 管理下への移行が完了。
module.cw_logs["stg_error"].aws_cloudwatch_log_group.this: Refreshing state... [id=stg-error]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
10、 取り込み確認
下記コマンドを実行し、正常に Terraform 管理下へ取り込まれているか確認する。
terraform state list
(参考)必要に応じて、grep などして確認する。
terraform state list | grep -E 'aws_s3_bucket.logs|aws_cloudwatch_log_group.app'
terraform state list | grep aws_s3_bucket.logs
まとめ
既存リソースを Terraform 管理下へ移行する手順は以上です。
これから移行作業を行う方の参考になれば幸いです。