RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

Terraformでコード化した振り返り

こんにちは。 前回は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を実行すると出てくる差分を一つずつ潰すなど、大変なことが多くありました。
ですが、やりきることはできたので次のステップも自信をもって進めていける良い体験にはなったかと思います。

6. 参考

Copyright © RAKUS Co., Ltd. All rights reserved.