Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Terraformにベストプラクティスを取り入れた - NIFTY Tech Talk #23

Terraformにベストプラクティスを取り入れた - NIFTY Tech Talk #23

イベント
これから始めるTerraform超入門! NIFTY Tech Talk #23
https://nifty.connpass.com/event/337326/

登壇者
ニフティ株式会社
高畑 孝輝

ニフティ株式会社

November 27, 2024
Tweet

Video

More Decks by ニフティ株式会社

Other Decks in Technology

Transcript

  1. 発表背景 • terraformを触り始めてから2年経過した • ベストプラクティスを改めて確認し最初から実施したかっ た内容がいくつかあった 3 Terraform を使用するためのベスト プラクティス

    https://cloud.google.com/docs/terraform/best-practices-for-terraform Terraform AWS プロバイダーを使用するためのベストプラクティス https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/terraform-aws-provid er-best-practices/introduction.html Style Guide - Configuration Language | Terraform | HashiCorp Developer https://developer.hashicorp.com/terraform/language/style
  2. リソースをできるだけ分ける 7 resource "aws_security_group" "web_api" { name = "web-api" vpc_id

    = var.vpc_id ingress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["172.16.0.0/16"] } ingress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["192.168.32.0/24"] } } ひとつのリソースにブロックを追加す ることで同時にリソース内で必要な設 定を追加できる
  3. リソースをできるだけ分ける/差分を取ってみる 8 Terraform will perform the following actions: # aws_security_group.all

    will be updated in-place ~ resource "aws_security_group" "web_app" { id = "sg-xxxxxxxxxxxxxxxxxxxx" ~ ingress = [ - { - cidr_blocks = [ - "0.0.0.0/0", ] - from_port = 0 - ipv6_cidr_blocks = [] - prefix_list_ids = [] - protocol = "-1" - security_groups = [] - self = false - to_port = 0 # (1 unchanged attribute hidden) }, + { + cidr_blocks = [ + "0.0.0.0/0", ] + from_port = 0 + ipv6_cidr_blocks = [] + prefix_list_ids = [] + protocol = "-1" + security_groups = [] + self = false + to_port = 0 }, … … + { + cidr_blocks = [ + "1.1.1.1/32", ] + from_port = 80 + ipv6_cidr_blocks = [] + prefix_list_ids = [] + protocol = "tcp" + security_groups = [] + self = false + to_port = 80 # (1 unchanged attribute hidden) }, ] name = "web-app" # (8 unchanged attributes hidden) } Plan: 0 to add, 1 to change, 0 to destroy. ingressルールを全て削除 して全て再作成するような 差分となる
  4. リソースをできるだけ分ける 9 resource "aws_security_group" "web_api" { name = "web-api" vpc_id

    = var.vpc_id } resource "aws_vpc_security_group_ingress_rule" "web_api" { security_group_id = aws_security_group.rule2.id cidr_ipv4 = "0.0.0.0/0" from_port = 0 ip_protocol = "tcp" to_port = 0 } resource "aws_vpc_security_group_ingress_rule" "web_api" { security_group_id = aws_security_group.rule2.id cidr_ipv4 = "0.0.0.0/0" from_port = 0 ip_protocol = "tcp" to_port = 0 } 1ルール毎にリソースを指定する
  5. リソースをできるだけ分ける/差分を取ってみる 10 Terraform will perform the following actions: # aws_vpc_security_group_ingress_rule.rule2_2

    will be created + resource "aws_vpc_security_group_ingress_rule" "rule2_2" { + arn = (known after apply) + cidr_ipv4 = "1.1.1.1/32" + from_port = 80 + id = (known after apply) + ip_protocol = "tcp" + security_group_id = "sg-0a1ef418ac7f2788d" + security_group_rule_id = (known after apply) + tags_all = {} + to_port = 80 } Plan: 1 to add, 0 to change, 0 to destroy. リソース毎にルールが作成され ているため変更時の差分がわ かりやすくなった
  6. 命名規則を守る • リソースタイプにあわせてアンダース コアで区切る • リソース名にリソースタイプを繰り返 さない • 目的をリソース名する •

    ひとつしかないリソースは”main”と いう名称も検討する 14 “resource” “aws_lb” “load-balancer” { … } “resource” “aws_lb” “web_global” { … }
  7. 命名規則を守る 15 resource “aws_lb” “front_end” { … } resource “aws_lb_listener”

    “front_end” { load_balancer_arn = aws_lb.front_end.arn … } resource "aws_lb_target_group" "front_end" { name = "front-end” port = 80 protocol = "HTTP" vpc_id = var.vpc_id } resource “aws_lb_target_group_attachment” “front_end”{ … ロードバランサに関わるリソース定義 • 1つの目的に対するリソースが複 数あってもわかりやすい • 参照する際にも情報が重複しな い
  8. 命名規則を守る 16 • Resource naming ◦ https://developer.hashicorp.com/terraform/language/style#resource-nami ng • 命名規則に従う

    ◦ https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/terraform -aws-provider-best-practices/structure.html#naming-conventions • 命名規則を採用する ◦ https://cloud.google.com/docs/terraform/best-practices-for-terraform?hl =ja#naming-convention
  9. 変数の使用を適切に行う あとから変えられるように多くを 変数化していたところ、変数定義、 モジュール利用時の設定値が肥大 化した 18 resource “aws_lb” “front_end” {

    name = var.service_name … } resource “aws_lb_listener” “front_end” { load_balancer_arn = aws_lb.front_end.arn port = var.listener_port ssl_policy = var.ssl_policy … } resource "aws_lb_target_group" "front_end" { name = “tg-{var.service_name}” port = var.target_group_port protocol = var.protocol vpc_id = var.vpc_id }
  10. 変数の使用を適切に行う 19 resource “aws_lb” “front_end” { name = var.service_name …

    } resource “aws_lb_listener” “front_end” { load_balancer_arn = aws_lb.front_end.arn port = 80 ssl_policy = “ELBSecurityPolicy-TLS13-1-0-2021-06” … } resource "aws_lb_target_group" "front_end" { name = “tg-{var.service_name}” port = 80 protocol = “HTTP” vpc_id = var.vpc_id } 繰り返しがある場合はlocalを使 い、繰り返しもない場合はハード コーディングする • 読みやすさが向上した
  11. 変数の使用を適切に行う 20 • Resource naming ◦ https://developer.hashicorp.com/terraform/language/style#resource-nami ng • 標準リポジトリ構造の実装

    ◦ https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/terraform -aws-provider-best-practices/structure.html#repo-structure • 変数を慎重に使用する ◦ https://cloud.google.com/docs/terraform/best-practices-for-terraform?hl =ja#variables
  12. for_eachでリソースを反復作成する 22 resource "aws_security_group" "web_api" { name = "web-api" vpc_id

    = var.vpc_id } resource "aws_vpc_security_group_ingress_rule" "web_api" { security_group_id = aws_security_group.web_api.id cidr_ipv4 = "192.168.1.0/24” from_port = 0 ip_protocol = "tcp" to_port = 0 } resource "aws_vpc_security_group_ingress_rule" "web_api" { security_group_id = aws_security_group.web_api.id cidr_ipv4 = "172.16.0.0/16” from_port = 0 ip_protocol = "tcp" to_port = 0 } cidr_ipv4以外が同じ設定であるため冗長に なる
  13. for_eachでリソースを反復作成する 23 locals { web_api_ingress_rules = [ “192.168.1.0/24”, “172.16.0.0/16”, ]

    } resource "aws_security_group" "web_api" { name = "web-api" vpc_id = var.vpc_id } resource "aws_vpc_security_group_ingress_rule" "web_api" { for_each = toset(local.web_api_ingress_rules) security_group_id = aws_security_group.web_api.id cidr_ipv4 = each.value from_port = 0 ip_protocol = "tcp" to_port = 0 } 設定値の差分を変数として持たせる
  14. for_eachでリソースを反復作成する 24 resource "aws_route" "privates" { for_each = merge([ for

    az in var.azs : { for route in var.routes : "${az}-${route.cidr_block}" => { az = az cidr_block = route.cidr_block gateway_id = route.gateway_id } if …... } ]...) route_table_id = aws_route_table.private[each.value.az].id destination_cidr_block = each.value.cidr_block gateway_id = each.value.gateway_id } • 反復が重なると可読性が下がる • ルートテーブルの場合 ▪ az毎の反復 ▪ route毎の反復 • 数が少ない場合は読みやすさか らdynamic blockの選択肢も ある
  15. for_eachでリソースを反復作成する 25 • Dynamic resource count ◦ https://developer.hashicorp.com/terraform/language/style#dynamic-resou rce-count •

    反復されるリソースに対して for_each を使用する ◦ https://cloud.google.com/docs/terraform/best-practices-for-terraform?hl =ja#for_each
  16. 実施しているベストプラクティス 1. リソースをできるだけ分ける 2. 命名規則を守る 3. 変数の使用を適切に行う 4. for_eachでリソースを反復作成する 26

    まとめ • 手探りでコードを作りながら課題を感じ、ベストプラクティスを再確認するこ とで改善することができた