DDetB.Log
article thumbnail
이 포스팅은 CloudNet@ 팀이 진행하는 테라폼 기초 입문 스터디에 참여하며 ‘테라폼으로 시작하는 IaC’ 책을 기준하여 정리한 글입니다.

1. terraform_data 

아무 작업도 수행하지 않는 리소스를 구현하며, 테라폼 1.4 버전이 릴리즈되면서 기존 null_resource 리소스를 대체하는 terraform_data 리소스가 추가됨. 사용자가 의도적으로 프로비저닝하는 동작을 조율해야 하는 상황이 발생할 때 사용.

  • 주요 사용 시나리오
    • 프로비저닝 수행 과정에서 명령어 실행
    • 프로비저너와 함께 사용
    • 모듈, 반복문, 데이터 소스, 로컬 변수와 함께 사용
    • 출력을 위한 데이터 가공
  • 요구사항
    • AWS EC2 인스턴스를 프로비저닝하면서 웹서비스를 실행시켜야 함
    • 웹서비스 설정에는 노출되어야 하는 고정된 외부 IP가 포함된 구성이 필요하므로 aws_eip 리소스를 생성

main.tf

<bash />
provider "aws" { region = "ap-northeast-2" } resource "aws_security_group" "instance" { name = "t101sg" ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_instance" "example" { ami = "ami-0c9c942bd7bf113a2" instance_type = "t2.micro" subnet_id = "subnet-dbc571b0" private_ip = "172.31.1.100" vpc_security_group_ids = [aws_security_group.instance.id] user_data = <<-EOF #!/bin/bash echo "Hello, T101 Study" > index.html nohup busybox httpd -f -p 80 & EOF tags = { Name = "Single-WebSrv" } provisioner "remote-exec" { inline = [ "echo ${aws_eip.myeip.public_ip}" ] } } resource "aws_eip" "myeip" { #vpc = true instance = aws_instance.example.id associate_with_private_ip = "172.31.1.100" } output "public_ip" { value = aws_instance.example.public_ip description = "The public IP of the Instance" }

실행 및 확인

<bash />
$ terraform plan ╷ │ Error: Cycle: aws_eip.myeip, aws_instance.example │ ╵

=> 두 리소스의 종속성이 상호 참조되어 발생하는 에러

=> aws_eip가 생성되는 고정된 IP를 할당하기 위해서는 대상인 aws_instance의 id값이 필요

=> aws_instance의 프로비저너 동작에서는 aws_eip가 생성하는 속성 값인 public_ip가 필요

main.tf 수정

<bash />
provider "aws" { region = "ap-northeast-2" } resource "aws_security_group" "instance" { name = "t101sg" ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_instance" "example" { ami = "ami-0c9c942bd7bf113a2" instance_type = "t2.micro" subnet_id = "subnet-98d276f3" private_ip = "172.31.0.100" key_name = "aiden_key" # 각자 자신의 EC2 SSH Keypair 이름 지정 vpc_security_group_ids = [aws_security_group.instance.id] user_data = <<-EOF #!/bin/bash echo "Hello, T101 Study" > index.html nohup busybox httpd -f -p 80 & EOF tags = { Name = "Single-WebSrv" } } resource "aws_eip" "myeip" { #vpc = true instance = aws_instance.example.id associate_with_private_ip = "172.31.0.100" } resource "terraform_data" "echomyeip" { provisioner "remote-exec" { connection { host = aws_eip.myeip.public_ip type = "ssh" user = "ubuntu" private_key = file("/home/aiden/terraform_study/aiden_key.pem") # 각자 자신의 EC2 SSH Keypair 파일 위치 지정 } inline = [ "echo ${aws_eip.myeip.public_ip}" ] } } output "public_ip" { value = aws_instance.example.public_ip description = "The public IP of the Instance" } output "eip" { value = aws_eip.myeip.public_ip description = "The EIP of the Instance" }

실행 및 확인

<bash />
$ terraform apply -auto-approve ... aws_eip.myeip: Creating... aws_eip.myeip: Creation complete after 2s [id=eipalloc-04a4474b8c52faf40] terraform_data.echomyeip: Creating... terraform_data.echomyeip: Provisioning with 'remote-exec'... terraform_data.echomyeip (remote-exec): Connecting to remote host via SSH... terraform_data.echomyeip (remote-exec): Host: 15.165.173.77 terraform_data.echomyeip (remote-exec): User: ubuntu terraform_data.echomyeip (remote-exec): Password: false terraform_data.echomyeip (remote-exec): Private key: true terraform_data.echomyeip (remote-exec): Certificate: false terraform_data.echomyeip (remote-exec): SSH Agent: false terraform_data.echomyeip (remote-exec): Checking Host Key: false terraform_data.echomyeip (remote-exec): Target Platform: unix ... terraform_data.echomyeip (remote-exec): Connected! terraform_data.echomyeip (remote-exec): 15.165.173.77 ... Outputs: eip = "15.165.173.77" public_ip = "52.78.242.232" $ terraform state list aws_eip.myeip aws_instance.example aws_security_group.instance terraform_data.echomyeip # 출력된 EC2 퍼블릭IP로 curl 접속 확인 $ MYIP=$(terraform output -raw eip) $ while true; do curl --connect-timeout 1 http://$MYIP/ ; echo "------------------------------"; date; sleep 1; done Hello, T101 Study ------------------------------ Sat 22 Jul 2023 04:05:27 AM KST Hello, T101 Study ------------------------------ Sat 22 Jul 2023 04:05:28 AM KST ...

2. moved blocks

테라폼의 State에 기록되는 리소스 주소의 이름이 변경되면 기존 리소스는 삭제되고 새로운 리소스가 생성된다. 리소스의 이름은 변경되지만 이미 테라폼으로 프로비저닝된 환경을 그대로 유지하고자 하는 경우 moved 블록을 사용한다. 예를 들면 아래와 같은 상황이 있다.

  • 리소스 이름을 변경
  • count로 처리하던 반복문을 for_each로 변경
  • 리소스가 모듈로 이동하여 참조되는 주소가 변경

main.tf

<bash />
resource "local_file" "a" { content = "foo!" filename = "${path.module}/foo.bar" } output "file_content" { value = local_file.a.content }

실행 및 확인

<bash />
$ terraform init && terraform plan && terraform apply -auto-approve ... $ terraform state show local_file.a # local_file.a: resource "local_file" "a" { content = "foo!" content_base64sha256 = "wOCqrqBQvPO+JsDCPVj6iQwN+3nIojAWtKhs0oym6nE=" content_base64sha512 = "TSCmPxazw2YStHurNILfRykjK/J4evgArH/2KnQuzQZodz4cq1f/ig2GeQO7mBI+Qx5jkTQEZxLCGs3mPtsB3Q==" content_md5 = "35af8b7a9490467f75f19c1e5459f7e7" content_sha1 = "4bf3e335199107182c6f7638efaad377acc7f452" content_sha256 = "c0e0aaaea050bcf3be26c0c23d58fa890c0dfb79c8a23016b4a86cd28ca6ea71" content_sha512 = "4d20a63f16b3c36612b47bab3482df4729232bf2787af800ac7ff62a742ecd0668773e1cab57ff8a0d867903bb98123e431e639134046712c21acde63edb01dd" directory_permission = "0777" file_permission = "0777" filename = "./foo.bar" id = "4bf3e335199107182c6f7638efaad377acc7f452" }

main.tf 수정 - local_file 이름 변경

<bash />
resource "local_file" "b" { content = "foo!" filename = "${path.module}/foo.bar" } output "file_content" { value = local_file.b.content }

=> local_file 이름을 a에서 b로 변경

실행 및 확인

<bash />
$ terraform plan ... Plan: 1 to add, 0 to change, 1 to destroy.

=> 기존 리소스를 제거하고 새로운 리소스를 생성

main.tf 수정 - moved block 추가

<bash />
resource "local_file" "b" { content = "foo!" filename = "${path.module}/foo.bar" } moved { from = local_file.a to = local_file.b } output "file_content" { value = local_file.b.content }

실행 및 확인

<bash />
$ terraform plan ... # local_file.a has moved to local_file.b resource "local_file" "b" { id = "4bf3e335199107182c6f7638efaad377acc7f452" # (10 unchanged attributes hidden) } Plan: 0 to add, 0 to change, 0 to destroy.

=> 기존 리소스를 제거하지 않고 이름 변경. State ID도 동일함을 확인.

=> apply 이후 moved 블럭을 삭제하면 리팩터링 완료.

profile

DDetB.Log

@DDetMok

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!