- 2-3. always_run 이슈 - 코드 수정 없이 apply 실행시, 기존 리소스를 삭제하고 다시 생성하는 문제2024년 06월 23일
- yeongki0944
- 작성자
- 2024.06.23.:00
이슈 설명
- 테라폼 코드 수정 없이, terraform apply 를 실행할 때마다 EC2 인스턴스와 관련된 리소스들이 삭제되고 새로 생성
문제의 코드
# AWS에서 PEM 키 파일의 존재 여부를 확인하는 null_resource resource "null_resource" "check_aws_key_pair" { provisioner "local-exec" { command = <<EOT if aws ec2 describe-key-pairs --key-names ${var.pem_file_name} 2>/dev/null; then echo 'key_pair_exists=true' > ${local.key_pair_check_file} else echo 'key_pair_exists=false' > ${local.key_pair_check_file} fi EOT } # [문제 원인] always_run 트리거가 매번 현재 시간을 사용하여 강제로 트리거를 실행 triggers = { always_run = "${timestamp()}" } } # 새로운 키를 생성하는 null_resource (AWS에서 PEM 키 파일이 없는 경우) # [문제 원인] null_resource가 항상 변경된 것으로 간주되어 재생성됨 resource "null_resource" "create_new_key" { provisioner "local-exec" { command = <<EOT if [ "${local.key_pair_exists}" == "false" ]; then aws ec2 create-key-pair --key-name ${local.new_key_name} --query 'KeyMaterial' --output text > ${local.new_key_file_path} chmod 400 ${local.new_key_file_path} fi EOT } triggers = { key_pair_exists = local.key_pair_exists ? "true" : "false", create_key = "${local.random_suffix}" } }
문제의 전체 코드
더보기provider "aws" { region = var.region } variable "pem_file_name" { description = "The name of the PEM key file (without .pem extension)" type = string default = "my-tf-test-2ada6" } variable "ec2_instance_name" { description = "The name of the EC2 instance" type = string default = "my-ec2-instance" } variable "region" { description = "The AWS region to create resources in" type = string default = "us-east-2" } variable "file_key" { description = "The key (name) of the file to be uploaded to S3" type = string default = "test_2.txt" } variable "instance_count" { description = "The number of EC2 instances to create" type = number default = 3 } locals { key_pair_check_file = "${path.module}/key_pair_exists.txt" } # AWS에서 PEM 키 파일의 존재 여부를 확인하는 null_resource resource "null_resource" "check_aws_key_pair" { provisioner "local-exec" { command = <<EOT if aws ec2 describe-key-pairs --key-names ${var.pem_file_name} 2>/dev/null; then echo 'key_pair_exists=true' > ${local.key_pair_check_file} else echo 'key_pair_exists=false' > ${local.key_pair_check_file} fi EOT } triggers = { always_run = "${timestamp()}" } } # 결과 파일을 읽기 위한 data 소스 data "local_file" "key_pair_exists_file" { filename = local.key_pair_check_file depends_on = [null_resource.check_aws_key_pair] } # 결과를 로컬 변수로 정의 locals { key_pair_exists = trimspace(data.local_file.key_pair_exists_file.content) == "key_pair_exists=true" random_suffix = substr(uuid(), 0, 5) new_key_name = "${var.pem_file_name}-${local.random_suffix}" new_key_file_path = "${path.module}/${local.new_key_name}.pem" } # EC2 인스턴스를 생성 resource "aws_instance" "ec2_instance" { count = var.instance_count ami = "ami-0c55b159cbfafe1f0" # 원하는 AMI ID로 변경하세요 instance_type = "t2.micro" key_name = local.key_pair_exists ? var.pem_file_name : local.new_key_name tags = { Name = "${var.ec2_instance_name}-${count.index}" } depends_on = [null_resource.create_new_key] } # 새로운 키를 생성하는 null_resource (AWS에서 PEM 키 파일이 없는 경우) resource "null_resource" "create_new_key" { provisioner "local-exec" { command = <<EOT if [ "${local.key_pair_exists}" == "false" ]; then aws ec2 create-key-pair --key-name ${local.new_key_name} --query 'KeyMaterial' --output text > ${local.new_key_file_path} chmod 400 ${local.new_key_file_path} fi EOT } triggers = { key_pair_exists = local.key_pair_exists ? "true" : "false", create_key = "${local.random_suffix}" } } # 키 페어 존재 여부를 출력하는 output output "key_pair_exists" { value = local.key_pair_exists } # 새로운 키 이름을 출력하는 output (AWS에서 PEM 키 파일이 없는 경우) output "new_key_name" { value = local.key_pair_exists ? "" : local.new_key_name } # 새로운 키 파일 경로를 출력하는 output (AWS에서 PEM 키 파일이 없는 경우) output "new_key_file_path" { value = local.key_pair_exists ? "" : local.new_key_file_path }
원인 분석
- null_resource 리소스의 triggers 속성에서 always_run 트리거가 사용된 것.
- always_run 트리거는 매번 현재 시간을 사용하여 트리거를 강제로 실행하도록 설정되어 있음.
즉, null_resource 리소스가 항상 변경된 것으로 간주됩니다.
이에 따라 해당 리소스(pem key)에 의존하는 다른 리소스(EC2)들도 재생성됩니다.문제 해결을 위해 필요한 배경 지식
- Terraform의 triggers 속성
- triggers 속성은 특정 조건이 변경될 때 null_resource 리소스를 다시 생성하도록 합니다.
이 속성을 올바르게 사용하는 방법을 이해해야 합니다.
- triggers 속성은 특정 조건이 변경될 때 null_resource 리소스를 다시 생성하도록 합니다.
- Terraform의 리소스 의존성 관리
- depends_on 속성을 사용하여 리소스 간의 의존성을 관리하는 방법을 알아야 합니다.
- Terraform의 lifecycle 블록
- lifecycle 블록을 사용하여 리소스의 변경 사항을 무시하거나 생성 전에 특정 조건을 확인하는 방법을 이해해야 합니다.
문제 해결
- always_run 트리거를 제거 > null_resource 리소스의 재생성을 방지
- depends_on 속성을 사용하여 리소스 간의 의존성을 정확히 명시함
수정된 코드
# 수정 부분: always_run 트리거 제거하고, PEM 키 파일 이름을 트리거로 사용 resource "null_resource" "check_aws_key_pair" { provisioner "local-exec" { command = <<EOT if aws ec2 describe-key-pairs --key-names ${var.pem_file_name} 2>/dev/null; then echo 'key_pair_exists=true' > ${local.key_pair_check_file} else echo 'key_pair_exists=false' > ${local.key_pair_check_file} fi EOT } triggers = { key_pair_name = var.pem_file_name } } # 수정 부분: null_resource의 의존성을 명확히 하고 불필요한 재생성을 방지 resource "null_resource" "create_new_key" { provisioner "local-exec" { command = <<EOT if [ "${local.key_pair_exists}" == "false" ]; then aws ec2 create-key-pair --key-name ${local.new_key_name} --query 'KeyMaterial' --output text > ${local.new_key_file_path} chmod 400 ${local.new_key_file_path} fi EOT } triggers = { key_pair_exists = local.key_pair_exists ? "true" : "false", create_key = "${local.random_suffix}" } depends_on = [null_resource.check_aws_key_pair] }
수정된 전체 코드
더보기provider "aws" { region = var.region } variable "pem_file_name" { description = "The name of the PEM key file (without .pem extension)" type = string default = "my-tf-test-2ada6" } variable "ec2_instance_name" { description = "The name of the EC2 instance" type = string default = "my-ec2-instance" } variable "region" { description = "The AWS region to create resources in" type = string default = "us-east-2" } variable "file_key" { description = "The key (name) of the file to be uploaded to S3" type = string default = "test_2.txt" } variable "instance_count" { description = "The number of EC2 instances to create" type = number default = 3 } locals { key_pair_check_file = "${path.module}/key_pair_exists.txt" } # AWS에서 PEM 키 파일의 존재 여부를 확인하는 null_resource resource "null_resource" "check_aws_key_pair" { provisioner "local-exec" { command = <<EOT if aws ec2 describe-key-pairs --key-names ${var.pem_file_name} 2>/dev/null; then echo 'key_pair_exists=true' > ${local.key_pair_check_file} else echo 'key_pair_exists=false' > ${local.key_pair_check_file} fi EOT } triggers = { key_pair_name = var.pem_file_name } } # 결과 파일을 읽기 위한 data 소스 data "local_file" "key_pair_exists_file" { filename = local.key_pair_check_file depends_on = [null_resource.check_aws_key_pair] } # 결과를 로컬 변수로 정의 locals { key_pair_exists = trimspace(data.local_file.key_pair_exists_file.content) == "key_pair_exists=true" random_suffix = substr(uuid(), 0, 5) new_key_name = "${var.pem_file_name}-${local.random_suffix}" new_key_file_path = "${path.module}/${local.new_key_name}.pem" } # 새로운 키를 생성하는 null_resource (AWS에서 PEM 키 파일이 없는 경우) resource "null_resource" "create_new_key" { provisioner "local-exec" { command = <<EOT if [ "${local.key_pair_exists}" == "false" ]; then aws ec2 create-key-pair --key-name ${local.new_key_name} --query 'KeyMaterial' --output text > ${local.new_key_file_path} chmod 400 ${local.new_key_file_path} fi EOT } triggers = { key_pair_exists = local.key_pair_exists ? "true" : "false", create_key = "${local.random_suffix}" } depends_on = [null_resource.check_aws_key_pair] } # EC2 인스턴스를 생성 resource "aws_instance" "ec2_instance" { count = var.instance_count ami = "ami-0c55b159cbfafe1f0" # 원하는 AMI ID로 변경하세요 instance_type = "t2.micro" key_name = local.key_pair_exists ? var.pem_file_name : local.new_key_name tags = { Name = "${var.ec2_instance_name}-${count.index}" } depends_on = [null_resource.create_new_key] } # 키 페어 존재 여부를 출력하는 output output "key_pair_exists" { value = local.key_pair_exists } # 새로운 키 이름을 출력하는 output (AWS에서 PEM 키 파일이 없는 경우) output "new_key_name" { value = local.key_pair_exists ? "" : local.new_key_name } # 새로운 키 파일 경로를 출력하는 output (AWS에서 PEM 키 파일이 없는 경우) output "new_key_file_path" { value = local.key_pair_exists ? "" : local.new_key_file_path }
다음글이전글이전 글이 없습니다.댓글
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)