Slide 1

Slide 1 text

terraformに ベストプラクティスを取り入れた 基幹システムグループ  入会システムチーム 高畑 孝輝 

Slide 2

Slide 2 text

自己紹介 名前: 高畑孝輝 所属: 基幹システムグループ/入会システムチーム 業務内容: 入会システムの開発運用 業務で利用している技術/サービス: terraform/CDK/PHP/Python 2

Slide 3

Slide 3 text

発表背景 ● 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

Slide 4

Slide 4 text

発表内容 terraformを使いはじめて発生した課題と 実践したベストプラクティスについて 4

Slide 5

Slide 5 text

ベストプラクティスの目的 ● 一貫性ができる ● コードが修正しやすくする ● コードが読みやすくなる 5

Slide 6

Slide 6 text

実施しているベストプラクティス 1. リソースをできるだけ分ける 2. 命名規則を守る 3. 変数の使用を適切に行う 4. for_eachでリソースを反復作成する 6

Slide 7

Slide 7 text

リソースをできるだけ分ける 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"] } } ひとつのリソースにブロックを追加す ることで同時にリソース内で必要な設 定を追加できる

Slide 8

Slide 8 text

リソースをできるだけ分ける/差分を取ってみる 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ルールを全て削除 して全て再作成するような 差分となる

Slide 9

Slide 9 text

リソースをできるだけ分ける 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ルール毎にリソースを指定する

Slide 10

Slide 10 text

リソースをできるだけ分ける/差分を取ってみる 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. リソース毎にルールが作成され ているため変更時の差分がわ かりやすくなった

Slide 11

Slide 11 text

リソースをできるだけ分ける/その他リソース 11 ● セキュリティグループ ● ルートテーブル ● IAMロールとIAMポリシー

Slide 12

Slide 12 text

リソースをできるだけ分ける/ベストプラクティス 12 ● アタッチメントリソースを使用する ○ https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/terraform -aws-provider-best-practices/structure.html#attachment-resources

Slide 13

Slide 13 text

実施しているベストプラクティス 1. リソースをできるだけ分ける 2. 命名規則を守る 3. 変数の使用を適切に行う 4. for_eachでリソースを反復作成する 13

Slide 14

Slide 14 text

命名規則を守る ● リソースタイプにあわせてアンダース コアで区切る ● リソース名にリソースタイプを繰り返 さない ● 目的をリソース名する ● ひとつしかないリソースは”main”と いう名称も検討する 14 “resource” “aws_lb” “load-balancer” { … } “resource” “aws_lb” “web_global” { … }

Slide 15

Slide 15 text

命名規則を守る 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つの目的に対するリソースが複 数あってもわかりやすい ● 参照する際にも情報が重複しな い

Slide 16

Slide 16 text

命名規則を守る 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

Slide 17

Slide 17 text

実施しているベストプラクティス 1. リソースをできるだけ分ける 2. 命名規則を守る 3. 変数の使用を適切に行う 4. for_eachでリソースを反復作成する 17

Slide 18

Slide 18 text

変数の使用を適切に行う あとから変えられるように多くを 変数化していたところ、変数定義、 モジュール利用時の設定値が肥大 化した 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 }

Slide 19

Slide 19 text

変数の使用を適切に行う 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を使 い、繰り返しもない場合はハード コーディングする ● 読みやすさが向上した

Slide 20

Slide 20 text

変数の使用を適切に行う 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

Slide 21

Slide 21 text

実施しているベストプラクティス 1. リソースをできるだけ分ける 2. 命名規則を守る 3. 変数の使用を適切に行う 4. for_eachでリソースを反復作成する 21

Slide 22

Slide 22 text

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以外が同じ設定であるため冗長に なる

Slide 23

Slide 23 text

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 } 設定値の差分を変数として持たせる

Slide 24

Slide 24 text

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の選択肢も ある

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

実施しているベストプラクティス 1. リソースをできるだけ分ける 2. 命名規則を守る 3. 変数の使用を適切に行う 4. for_eachでリソースを反復作成する 26 まとめ ● 手探りでコードを作りながら課題を感じ、ベストプラクティスを再確認するこ とで改善することができた