こんにちは。
前回はAWSの既存環境をTerraformでコード化してみたを投稿しましたが、
今回はその振り返りをしていきます。
前半はTerraformの基本的なところから、少し躓いた三項演算子について書いていきます。
これからTerraformでコード化していく方の助けになれればと思います。
後半は今回のコード化を通しての個人的な感想を書いていきます。
1.目次
2. terraformコマンド
主に以下のコマンドを使用します。
#初期化 terraform init #仮実行 terraform plan #本実行 terraform apply #リソース取込 terraform import
terraform init
書いたコードで他コマンドを実行するための準備をします。
これを実行しておかないとplanやapplyはできません。terraform plan
実際に変更は行わず、追加/変更/削除の確認ができます(いわゆるdry-run)。
planは実環境ではなくterraform.tfstateとの比較を行います。 terraform.tfstateはリソース情報が記載されているjsonファイルです。terraform apply
コードを元に変更を行います。
planでエラーが出ていない場合でも、applyで出ることもあります。terraform import
コード化したリソースがすでに存在する場合、このコマンドを用いてterraform.tfstateに取り込みます。
importの書式は公式ドキュメントの各リソースのページ下部にあります。上記以外にもterraform.tfstateを参照するコマンドで
terraform state list
:terraform.tfstateで管理しているリソースのリスト
terraform state show "リソース名"
:"リソース名"の情報
があります。
そのほか、plan/applyの実行時に-target=特定リソース
と引数を渡すことで全体ではなく対象を絞ることが可能になります。
example_ec2_instance
というリソースのみplanを実行する場合は、
terraform plan -target=module.aws_ec2.example_ec2_instance
複数のリソースにしたい場合は、-target=
を含めスペース区切りで引数を追加すれば可能です。
3. コード
リソースごとに必要な設定項目は公式ドキュメントが分かりやすいと思います。
VSCodeを使用されている場合は、拡張機能に「HashiCorp Terraform」がありますので、そちらをインストールすることで設定項目などの補完もしてくれます。
- count 三項演算子を使用することができ、本番/検証環境で場合分けをすることが可能です。 ただし、多用しすぎると可読性が下がるため、なるべく使わなくていいようにした方が無難だと思います・・・。
以下がcountを用いた三項演算子の使い方の一例です。
count = "${var.a == "値" ? "0" : "1"}"
変数aに格納されている値と、条件となる値が一致していない場合に、そのリソースが作成されます。
main.tfで変数envにstaging以外が格納されている場合に、「application_loadbalancer_public」が作成されます。
module "elb_module" { source = "../../modules/elb" env = "product" ※省略 }
resource "aws_lb" "application_loadbalancer_public" { count = "${var.env == "staging" ? "0" : "1"}" name = "application-loadbalancer-public" subnets = [ var.example_subnet1_id, var.example_subnet2_id ] load_balancer_type = "application" internal = false enable_deletion_protection = false desync_mitigation_mode = "defensive" xff_header_processing_mode = "append" idle_timeout = 60 access_logs { bucket = "example-bucket" enabled = true prefix = "AWSLogs" } }
しかし、こうして作成したLBに対してリスナーを設定しようとすると、
そのままではエラーとなってしまいます。
LBのARNを参照させる際にインデックスを指定---①してあげる必要があります。
resource "aws_lb_listener" "listener_https" { count = "${var.env == "staging" ? "0" : "1"}" load_balancer_arn = aws_lb.alb_from_office[0].arn ---① port = "443" protocol = "HTTPS" ssl_policy = "ELBSecurityPolicy-2016-08" certificate_arn = var.default_certificate_arn tags = {} tags_all = {} default_action { type = "fixed-response" order = 1 fixed_response { content_type = "text/plain" message_body = "Not Found" status_code = "404" } } }
for_each
同じ構成のリソースが複数必要な場合に有用です。
今回のコード化ではfor_eachを使用していないため、具体的な使用例は割愛させて頂きます。
こちらも公式ドキュメントに詳細があります。
4. コード化を通して
コード書くよりも・・・
AWSのリソースを見てコード化していくことは苦ではありませんでしたが、
importでのリソース取り込みが個人的に大変でした。リソース取り込みにはARNやIDが必要となります。
リソースを一つずつ取り込まなければならず、route53であればレコード毎、LBであればルール毎など細かいリソースもあるため気が遠くなりそうでした。達成感
コードを書ききってplan実行時のエラーも解消させ、最終的にコードと環境で差分が出ないとなった時の達成感は大きかったです。
今後はTerraformを運用に乗せていき、コードもブラッシュアップしていく必要がありますが一区切りつきました。
最終的なゴールはCI/CDのパイプラインも実装して、インフラ部分を自動化していければと思っています。
5. 終わりに
今年の4月から本格的にAWSに触り始め、Terraform?何それ?状態からスタートしたAWS環境のコード化でした。
最初のディレクトリ構成に悩んだり、planを実行すると出てくる差分を一つずつ潰すなど、大変なことが多くありました。
ですが、やりきることはできたので次のステップも自信をもって進めていける良い体験にはなったかと思います。