Terraform Data Source, Variable

kimchigood·2023년 9월 6일
0
post-thumbnail
post-custom-banner

이번 포스팅에서는 Terraform의 data source와 variable에 대해 알아보겠다. Terraform을 사용하다 보면 꼭 필요한 기능들이니 잘 익혀두면 도움이 된다.

1. Data Source

일반적으로 terraform을 통해서 리소스를 생성할 때는 resource를 사용하게 된다. 그럼 data source는 어디에 쓰일까?

# Create Azure Storage Account required for Function App
resource "azurerm_storage_account" "primary" {
  name                     = "b59storage"
  resource_group_name      = azurerm_resource_group.primary.name
  location                 = azurerm_resource_group.primary.location
  account_kine             = "StorageV2"
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

바로, 외부 리소스 또는 이미 저장된 정보를 terraform 내에서 참조할 때 사용하게 된다.

쉽게 예를 들면, terraform을 통해 aks를 만든다고 가정해보자.

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "West Europe"
}

resource "azurerm_kubernetes_cluster" "example" {
  name                = "example-aks1"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  dns_prefix          = "exampleaks1"

  default_node_pool {
    name       = "default"
    node_count = 1
    vm_size    = "Standard_D2_v2"
  }

  identity {
    type = "SystemAssigned"
  }

  tags = {
    Environment = "Production"
  }
}

output "client_certificate" {
  value = azurerm_kubernetes_cluster.example.kube_config.0.client_certificate
}

output "kube_config" {
  value = azurerm_kubernetes_cluster.example.kube_config_raw

  sensitive = true
}

이렇게 만들어진 aks를 만약 다른 terrform에서 참조해야하는 상황이라고 한다면,
참고로, output을 통해 만들어진 결과 중 중요한 값들을 콘솔에서 확인도 가능하다.

data "azurerm_kubernetes_cluster" "example" {
  name                = "myakscluster"
  resource_group_name = "my-example-resource-group"
}

이런식으로 data resource를 선언해 주고,

data.azurerm_kubernetes_cluster.example.name 

으로 참조가 가능하다.

2. Variable

Variable를 통해 인프라 구성 시 필요한 값을 미리 지정해두고, 코드에 하드코딩이나 코드변경이 없이 사용할 수 있게 하는 장점이있다.

예제코드를 보자.

# variable 블록 선언의 예
variable "<이름>" {
 <인수> = <>
}

variable "image_id" {
 type = string
}

간단한 코드이지만, Variable에는 default, type, descrption, validation, sensitive, nullable 과 같은 메타인수 사용이 가능하다.

variable "ingress_rules" { # optional ( >= terraform 1.3.0)
  type = list(object({
    port        = number,
    description = optional(string),
    protocol    = optional(string, "tcp"),
  }))
  default = [
    { port = 80, description = "web" },
  { port = 53, protocol = "udp" }]
}

위와 같이 ingress rule 세팅 시 list type의 변수로 지정해서 사용도 가능하다.

validation check

variable "image_id" {
  type        = string
  description = "The id of the machine image (AMI) to use for the server."

  validation {
    condition     = length(var.image_id) > 4
    error_message = "The image_id value must exceed 4."
  }

  validation {
    # regex(...) fails if it cannot find a match
    condition     = can(regex("^ami-", var.image_id))
    error_message = "The image_id value must starting with \"ami-\"."
  }
}

variable 사용 시 validation check를 통해 사용할 변수의 유효성 검증하는 방법도 있다. 위의 예제는 AMI type을 변수로 설정하는 건데, 변수 길이와 정규표현식을 통해 검증을 하게 된다.

사용자가 잘못된 값을 입력하면 아래 그림과 같이 미리 오류가 나기때문에 미연에 잘못된 세팅방지가 가능하다.

과제

default VPC 대신 직접 VPC를 만들고, 해당 VPC내에 EC2 1대를 배포

Network - main.tf
1. VPC를 배포
2. Subnet 2개 IGW, Route Table 배포
3. Route Table에 Subnet 연결 및 Routing 정보 추가

provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_vpc" "kimchivpc" {
  cidr_block       = "10.10.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "t101-study"
  }
}

resource "aws_subnet" "kimchisubnet1" {
  vpc_id     = aws_vpc.kimchivpc.id
  cidr_block = "10.10.1.0/24"

  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "t101-subnet1"
  }
}

resource "aws_subnet" "kimchisubnet2" {
  vpc_id     = aws_vpc.kimchivpc.id
  cidr_block = "10.10.2.0/24"

  availability_zone = "ap-northeast-2c"

  tags = {
    Name = "t101-subnet2"
  }
}

resource "aws_internet_gateway" "kimchiigw" {
  vpc_id = aws_vpc.kimchivpc.id

  tags = {
    Name = "t101-igw"
  }
}

resource "aws_route_table" "kimchirt" {
  vpc_id = aws_vpc.kimchivpc.id

  tags = {
    Name = "t101-rt"
  }
}

resource "aws_route_table_association" "kimchirtassociation1" {
  subnet_id      = aws_subnet.kimchisubnet1.id
  route_table_id = aws_route_table.kimchirt.id
}

resource "aws_route_table_association" "kimchirtassociation2" {
  subnet_id      = aws_subnet.kimchisubnet2.id
  route_table_id = aws_route_table.kimchirt.id
}

resource "aws_route" "kimchidefaultroute" {
  route_table_id         = aws_route_table.kimchirt.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.kimchiigw.id
}


output "aws_vpc_id" {
  value = aws_vpc.kimchivpc.id
}

Security Group - sg.tf
Security Group 생성 후 inbound/outbound 규칙 설정

resource "aws_security_group" "kimchisg" {
  vpc_id      = aws_vpc.kimchivpc.id
  name        = "T101 SG"
  description = "T101 Study SG"
}

resource "aws_security_group_rule" "kimchisginbound" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.kimchisg.id
}

resource "aws_security_group_rule" "kimchisgoutbound" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.kimchisg.id
}

EC2 - ec2.tf

data "aws_ami" "kimchi_amazonlinux2" {
  most_recent = true
  filter {
    name   = "owner-alias"
    values = ["amazon"]
  }

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-ebs"]
  }

  owners = ["amazon"]
}

resource "aws_instance" "kimchiec2" {

  depends_on = [
    aws_internet_gateway.kimchiigw
  ]

  ami                         = data.aws_ami.kimchi_amazonlinux2.id
  associate_public_ip_address = true
  instance_type               = "t2.micro"
  vpc_security_group_ids      = ["${aws_security_group.kimchisg.id}"]
  subnet_id                   = aws_subnet.kimchisubnet1.id

  user_data = <<-EOF
              #!/bin/bash
              wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64
              mv busybox-x86_64 busybox
              chmod +x busybox
              RZAZ=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone-id)
              IID=$(curl 169.254.169.254/latest/meta-data/instance-id)
              LIP=$(curl 169.254.169.254/latest/meta-data/local-ipv4)
              echo "<h1>RegionAz($RZAZ) : Instance ID($IID) : Private IP($LIP) : Web Server</h1>" > index.html
              nohup ./busybox httpd -f -p 80 &
              EOF

  user_data_replace_on_change = true

  tags = {
    Name = "t101-kimchiec2"
  }
}

output "kimchiec2_public_ip" {
  value       = aws_instance.kimchiec2.public_ip
  description = "The public IP of the Instance"
}

결과


Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + myec2_public_ip = (known after apply)
aws_instance.kimchiec2: Creating...
aws_instance.kimchiec2: Still creating... [10s elapsed]
aws_instance.kimchiec2: Still creating... [20s elapsed]
aws_instance.kimchiec2: Still creating... [30s elapsed]
aws_instance.kimchiec2: Still creating... [40s elapsed]
aws_instance.kimchiec2: Creation complete after 41s [id=i-06c6d0321c172df7f]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

aws_vpc_id = "vpc-0bb4099e0c894f0ff"
myec2_public_ip = "X.XX.XX.XX"

확인

MYIP=$(terraform output -raw kimchiec2_public_ip)
while true; do curl --connect-timeout 1  http://$MYIP/ ; echo "------------------------------"; date; sleep 1; done

EC2가 잘 생성되었고, 조금 기다렸다가 curl을 날리면 위와 같은 결과를 얻을 수 있다.

vpc_security_group_ids      = ["${aws_security_group.kimchisg.id}"]

원래 module을 사용해서 참조하는 방법은 알고 있었는데, 이런 방법으로 같은 레벨에 있는 파일의 리소스 값을 참조도 가능하다!

Wrap up

이번 스터디에서는 terraform data resource, variable, for 문 등에 대해 배웠다. 실무에서 사용할 수 있는 기능들이니 하나씩 익혀가면 좋을 것 같다.

profile
Shout out to Kubernetes⎈
post-custom-banner

0개의 댓글