NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

CloudFormation管理からTerraform管理へ移行する

本記事は  マイグレーションウィーク  1日目の記事です。
💻🖥  告知記事  ▶▶ 本記事 ▶▶  2日目  🖥💻

こんにちは、後藤です。
マイグレーションWeekということで普段、業務で触れている技術であるIaCツールの移行について書きたいと思います。

有名なIaCツールにはTerraformやCloudFormation、Pulumiなどがあり、それぞれに一長一短の特徴があります。使っていくうちに「やっぱり変えたい」と思うこともあるかもしれません。例えば「現状AWSのみ管理しているがGCPも扱うことになったので管理方法を合わせたい」といったシチュエーションです。
そういったシチュエーションのために、AWSリソースをCloudFormation管理からTerraform管理へと移行する手順を紹介します。

手順①:リソース削除ポリシーの変更

まずはCloudFormationテンプレートを確認し、修正する作業があります。
IaCで二重管理をすると予期せぬリソース更新が発生する可能性もあるため、後ほどCloudFormationスタックを削除するのですが、CloudFormationによって作成されたリソースのDeletionポリシーはデフォルト設定で「Delete」になっており、スタックを削除するとリソースも一緒に削除されてしまいます。RDSなどの一部のデータ格納系サービスもデフォルト設定は「Snapshot」になっています。
そこで各リソースの記述にDeletionPolicy: Retainを明記します。そうすることによって、スタックが削除されてもリソース自体はAWS上に残るようになります。

手順②:Terraform管理にする

続いて、Terraformに取り込む作業です。

方法としてはterraform importを使っていきます。 terraform importの使い方はコマンドで実行するか、ファイルに記載しておくかの2通りあります

コマンドでterraform importを実行する方法
コンソール上でコマンドを実行してTerraform管理下にする作業です。形式はterraform import <リソースタイプ> <リソース名> <取り込みたいリソースのID>となります。以下はセキュリティグループの例です。

terraform import aws_security_group.sg_example sg-00000000

また、セキュリティグループルールのような細かい設定に関してはリソースのIDの後ろに情報を付け足していくことになります。公式リファレンスの各ページのimport項目にて正しい形式が記載があるので、記述の際は確認してください。

terraform import aws_security_group_rule.ingress sg-00000000_ingress_tcp_80_80_10.0.0.0/24

コマンド実行後に、取り込み先リソースに実機と同じ設定値を記載しておけば完了です。

resource "aws_security_group" "SG-import" {
  name     = "sg-example"
  vpc_id   = "vpc-00000000"

}

resource "aws_security_group_rule" "SG-import-rule" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["10.0.0.0/24"]
  security_group_id = aws_security_group.SG-import.id
}


このようにコマンド実行だけで済ませると簡単です。一般的に、移行作業は何度も行う作業ではないのでコマンドでも十分かもしれません。しかしAWS環境にリソース数が多いのであれば、リソースの数だけコマンドを実行しないといけないので実行漏れやコマンドミスがありえるのでこの方法はあまりオススメしません。

ファイルにimportブロックを記載する方法 ※Terraformバージョン1.5.0以降が対応
tfファイルにimportブロックを書く方法もあります。
importブロックの書き方は非常にシンプルで、toには取り込み先となるリソース名を、idには取り込みたいリソースIDを記載するだけです。こちらも公式リファレンスの各ページのimport項目にて正しい形式を確認してください。

import {
  to = aws_security_group.SG-import
  id = "sg-99999999"
 }

 import {
   to = aws_security_group_rule.SG-import-rule
   id = "sg-99999999_egress_all_0_0_0.0.0.0/0"
 }

あとは取り込み先リソースに実機と同じ設定値を記載しておき、terraform applyを実行すれば完了です。terraform apply実行後はimportブロックを削除しても良いですし、コメントアウトして初期値として残しておくのも良いです。

resource "aws_security_group" "SG-import" {
  name     = "sg-example"
  vpc_id   = "vpc-00000000"

}

resource "aws_security_group_rule" "SG-import-rule" {
  type              = "egress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.SG-import.id
}

ちなみに

取り込み先リソースについても実機と同じ設定値を記載しておき

とありましたが、リファレンスを読みながら記法を確認しつつ、実機を見て設定値を埋める作業はかなりの手間になってきます。 そこでterraform plan -generate-config-out=generated.tfを使ってみましょう。ファイル名であるgenerated.tfは特に決まりないので適宜、変更してください。
importブロックだけ書いてterraform plan -generate-config-out=generated.tfを実行すれば、差分が検出され、書くべきリソース部分をファイルに出力してくれます。つまり、リファレンス確認と実機の設定値確認の工程が減らせます。

このようにimport作業までもコード化することができます。GitHubなどを使ってチームレビューがしやすくなり、IaCの恩恵を受けられるのでこちらがおススメです。

手順③:CloudFormationスタックを削除する

上記手順で準備は整ったので、あとはCloudFormationスタックを削除すれば終了です。

さいごに

当記事ではCloudFormationからの移行について説明しました。
CloudFormationを使っていて、ここまでDeletionポリシーを意識したことはありませんでした。
普段気に留めていなかった機能を活用できたので、良い勉強になりました。

執筆者: 後藤 涼太
AWSをメインとするクラウドエンジニア
2024 Japan AWS All Certifications Engineers
執筆記事:https://tech.nri-net.com/archive/author/r-goto