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

IaCコードリーディング ~Terraformのコードを一緒に読んで行こう~

IaCコードリーディング ~Terraformのコードを一緒に読んで行こう~

インフラをコードで設定する技術であるIaC(Infrastructure as Code)ですが、活用すればインフラの構築を自動化し、効率的なインフラ構築を可能とします。一方で、コードの内容を理解しなければ、コードを書くことはおろか、その構築結果を理解することもできません。今回の勉強会では、Terraformのコードを参考に、コードを一つ一つ追いながら、一緒にその中身を理解していきます。

とことんDevOps

December 21, 2023
Tweet

More Decks by とことんDevOps

Other Decks in Technology

Transcript

  1. ⽇本仮想化技術株式会社 概要 • 社名:⽇本仮想化技術株式会社 • 英語名:VirtualTech Japan Inc. • 設⽴:2006年12⽉

    • 資本⾦:3,000万円 • 本社:東京都渋⾕区渋⾕1-8-1 • 取締役:宮原 徹(代表取締役社⻑兼CEO)、伊藤 宏通(取締役CTO) • スタッフ:11名(うち、8名が仮想化技術専⾨エンジニアです) • URL:http://VirtualTech.jp/ • 仮想化技術に関する研究および開発 • 仮想化技術に関する各種調査 • 仮想化技術に関連したソフトウェアの開発 • 仮想化技術を導⼊したシステムの構築 • OpenStackの導⼊⽀援・新規機能開発 2 ベンダーニュートラルな 独⽴系仮想化技術の エキスパート集団 会社概要
  2. 発表者について • たなかともあき • 技術部所属 • お仕事 • DevOpsのOps •

    執筆 • Think IT https://thinkit.co.jp/series/10843 • Software Design https://gihyo.jp/magazine/SD/archive/2023/202303 https://gihyo.jp/magazine/SD/archive/2023/202311 3
  3. versions.tf 12 terraform { required_version = "~> 1.6.0" required_providers {

    aws = { source = "hashicorp/aws" version = "~> 5.29.0" } helm = { source = "hashicorp/helm" version = "~> 2.12.1" } } } • Terraformのバージョンを指定 • ~> ⼀番右のバージョンが指定された数値以上 • 1.6.0以上、1.7.0未満
  4. 13

  5. 14

  6. 15

  7. 16

  8. variables.tf 18 variable "aws_account_id" { description = "環境取り違え防⽌のためTerraform実⾏対象のアカウントID" type =

    number } variable "aws_region" { description = "リソース作成先のAWSリージョン" type = string } variable "aws_vpc_cidr_block" { description = "VPC CIDR Block" type = string default = "10.0.0.0/16" } ... • デフォルト値が設定されていないの で必須の変数 • デフォルト値が設定されているので オプショナルな変数
  9. terraform.tfvars 20 aws_account_id = 123456789012 aws_region = "ap-northeast-1" #aws_vpc_cidr_block =

    "10.0.0.0/16” aws_eks_cluster_name = "demo" aws_eks_cluster_version = "1.28" aws_eks_nodegroups = 2 podinfo_chart_version = "6.5.3" podinfo_namespace = "app"
  10. Public Subnet 27 resource "aws_subnet" "public" { for_each = toset(data.aws_availability_zones.available.names)

    vpc_id = aws_vpc.demo.id availability_zone = each.value cidr_block = cidrsubnet(var.aws_vpc_cidr_block, 8, index(tolist(toset(data.aws_availability_zones.available.names)), each.key)) }
  11. 28

  12. listとset 29 $ echo 'tolist(["b", "a", "b", "c"])' | terraform

    console tolist([ "b", "a", "b", "c", ]) $ echo 'toset(["b", "a", "b", "c"])' | terraform console toset([ "a", "b", "c", ])
  13. indexの実⾏結果 30 $ echo 'index(["ap-northeast-1c", "ap-northeast-1a", "ap-northeast-1d", "ap-northeast-1a"], "ap-northeast-1a")' |

    terraform console 1 $ echo 'index(["ap-northeast-1c", "ap-northeast-1a", "ap-northeast-1d", "ap-northeast-1a"], "ap-northeast-1c")' | terraform console 0 $ echo 'index(tolist(toset(["ap-northeast-1c", "ap-northeast-1a", "ap- northeast-1d", "ap-northeast-1a"])), "ap-northeast-1a")' | terraform console 0 $ echo 'index(tolist(toset(["ap-northeast-1c", "ap-northeast-1a", "ap- northeast-1d", "ap-northeast-1a"])), "ap-northeast-1c")' | terraform console 1
  14. cidrsubnetの実⾏結果 31 $ echo 'cidrsubnet("10.0.0.0/16", 8, 0)' | terraform console

    "10.0.0.0/24" $ echo 'cidrsubnet("10.0.0.0/16", 8, 1)' | terraform console "10.0.1.0/24" $ echo 'cidrsubnet("10.0.0.0/16", 8, 2)' | terraform console "10.0.2.0/24" $ echo 'cidrsubnet("10.0.0.0/16", 4, 0)' | terraform console "10.0.0.0/20" $ echo 'cidrsubnet("10.0.0.0/16", 4, 1)' | terraform console "10.0.16.0/20" $ echo 'cidrsubnet("10.0.0.0/16", 4, 2)' | terraform console "10.0.32.0/20"
  15. Public Subnet 32 resource "aws_subnet" "public" { vpc_id = aws_vpc.demo.id

    availability_zone = "ap-northeast-1a" cidr_block = "10.0.0.0/24" } resource "aws_subnet" "public" { vpc_id = aws_vpc.demo.id availability_zone = "ap-northeast-1c" cidr_block = "10.0.1.0/24" } resource "aws_subnet" "public" { vpc_id = aws_vpc.demo.id availability_zone = "ap-northeast-1d" cidr_block = "10.0.2.0/24" }
  16. Public Route Table 36 resource "aws_route_table" "public" { vpc_id =

    aws_vpc.demo.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.public.id } }
  17. Route Table Association 37 resource "aws_route_table_association" "public" { for_each =

    aws_subnet.public subnet_id = each.value.id route_table_id = aws_route_table.public.id }
  18. Private Subnet 39 resource "aws_subnet" "private" { for_each = toset(data.aws_availability_zones.available.names)

    vpc_id = aws_vpc.demo.id availability_zone = each.value cidr_block = cidrsubnet(var.aws_vpc_cidr_block, 8, index(tolist(toset(data.aws_availability_zones.available.names)), each.key) + length(aws_subnet.public)) }
  19. NAT Gateway 42 resource "aws_nat_gateway" "private" { subnet_id = aws_subnet.public[data.aws_availability_zones.available.names[0]].id

    allocation_id = aws_eip.nat_gateway.id } resource "aws_nat_gateway" "private" { subnet_id = aws_subnet.public["ap-northeast-1a"].id allocation_id = aws_eip.nat_gateway.id }
  20. Private Route Table 43 resource "aws_route_table" "private" { vpc_id =

    aws_vpc.demo.id route { cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.private.id } }
  21. Route Table Association 44 resource "aws_route_table_association" "private" { for_each =

    aws_subnet.private subnet_id = each.value.id route_table_id = aws_route_table.private.id }
  22. Policy Document 48 data "aws_iam_policy_document" "cluster_assume_role" { statement { effect

    = "Allow" principals { type = "Service" identifiers = ["eks.amazonaws.com"] } actions = ["sts:AssumeRole"] } }
  23. IAM Role 49 resource "aws_iam_role" "cluster" { name_prefix = "${var.aws_eks_cluster_name}-cluster-"

    assume_role_policy = data.aws_iam_policy_document.cluster_assume_role.json managed_policy_arns = [ "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController", ] }
  24. EKS 50 resource "aws_eks_cluster" "demo" { name = var.aws_eks_cluster_name role_arn

    = aws_iam_role.cluster.arn vpc_config { subnet_ids = [for k, v in aws_subnet.public : v.id] } version = var.aws_eks_cluster_version }
  25. subnet_idsに渡してるリスト 51 $ terraform console > [for k, v in

    aws_subnet.public : v.id] [ "subnet-0bf86ee5ce3ef0ef8", "subnet-0136c78fa0ebcd5c1", "subnet-01c33f17f65692b33", ]
  26. EKS Addon 52 resource "aws_eks_addon" "vpc_cni" { cluster_name = aws_eks_cluster.demo.name

    addon_name = "vpc-cni" } resource "aws_eks_addon" "coredns" { cluster_name = aws_eks_cluster.demo.name addon_name = "coredns" } resource "aws_eks_addon" "kube_proxy" { cluster_name = aws_eks_cluster.demo.name addon_name = "kube-proxy" }
  27. Policy Document 56 data "aws_iam_policy_document" "nodegroup_assume_role" { statement { effect

    = "Allow" principals { type = "Service" identifiers = ["ec2.amazonaws.com"] } actions = ["sts:AssumeRole"] } }
  28. IAM Role 57 resource "aws_iam_role" "nodegroup" { name_prefix = "${aws_eks_cluster.demo.name}-nodegroup-"

    assume_role_policy = data.aws_iam_policy_document.nodegroup_assume_role.json managed_policy_arns = [ "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy", "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy", "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" ] }
  29. Nodegroup 58 resource "aws_eks_node_group" "demo" { cluster_name = aws_eks_cluster.demo.name node_group_name_prefix

    = "${aws_eks_cluster.demo.name}-" node_role_arn = aws_iam_role.nodegroup.arn subnet_ids = [for k, v in aws_subnet.private : v.id] scaling_config { min_size = 1 max_size = var.aws_eks_nodegroups desired_size = var.aws_eks_nodegroups } update_config { max_unavailable = 1 } }
  30. Helmプロバイダー 61 provider "helm" { kubernetes { host = aws_eks_cluster.demo.endpoint

    cluster_ca_certificate = base64decode(data.aws_eks_cluster.demo.certificate_authority.0.data) token = data.aws_eks_cluster_auth.demo.token } }
  31. EKS Cluster Data Sources 62 data "aws_eks_cluster" "demo" { name

    = aws_eks_cluster.demo.name } data "aws_eks_cluster_auth" "demo" { name = aws_eks_cluster.demo.name }
  32. アプリケーションのデプロイ 63 resource "helm_release" "podinfo" { name = "podinfo" repository

    = "https://stefanprodan.github.io/podinfo" chart = "podinfo" version = var.podinfo_chart_version namespace = var.podinfo_namespace create_namespace = true wait = true set { name = "replicaCount" value = var.aws_eks_nodegroups } }
  33. outputs.tf 65 output "aws_eks_update_kubeconfig" { value = "aws eks update-kubeconfig

    --name ${var.aws_eks_cluster_name} -- alias ${var.aws_eks_cluster_name}" } output "port_forward_command" { value = "kubectl port-forward -n ${var.podinfo_namespace} services/podinfo 9898:9898" }
  34. 確認 66 $ terraform output -raw aws_eks_update_kubeconfig aws eks update-kubeconfig

    --name demo --alias demo $ eval "$(terraform output -raw aws_eks_update_kubeconfig)" Updated context demo in /Users/tanaka/.kube/config $ kubectl get pods -n app NAME READY STATUS RESTARTS AGE podinfo-65d9887677-7l45r 1/1 Running 0 35m podinfo-65d9887677-gc45s 1/1 Running 0 35m
  35. 確認 67 $ terraform output -raw port_forward_command kubectl port-forward -n

    app services/podinfo 9898:9898 $ eval "$(terraform output -raw port_forward_command)" Forwarding from 127.0.0.1:9898 -> 9898 Forwarding from [::1]:9898 -> 9898 Handling connection for 9898 ...
  36. 関連リンク • Terraform AWS provider https://registry.terraform.io/providers/hashicorp/aws/latest/ docs • Terraform Helm

    provider https://registry.terraform.io/providers/hashicorp/helm/latest /docs • サンプルコード https://github.com/VirtualTech-DevOps/terraform- codereading-demo 69
  37. 71