[Terraform] 모듈 주의 사항

업데이트:     Updated:

카테고리:

태그:

🎯모듈 주의 사항

모듈을 만들 때는 다음과 같은 사항을 주의해야 합니다.

  • 파일 경로
  • 인라인 블록

파일 경로

기본적으로 테라폼은 현재 작업 중인 디렉터리를 기준으로 경로를 해석합니다. terraform apply를 실행하는 디렉터리와 동일한 디렉터리에 있는 테라폼 구성 파일에서 file 함수를 사용하는 것, 즉 루트 모듈에서 file 함수를 사용하는 것은 가능하지만, 별도의 폴더에 정의된 모듈에서 file 함수를 사용할 수는 없습니다.

이 문제를 해결하기 위해 path.<TYPE> 형태의 경로 참조 표현식을 사용할 수 있습니다. 테라폼은 다음 유형의 경로 참조를 지원합니다.

  • path.module: 표현식이 정의된 모듈의 파일 시스템 경로를 반환합니다.
  • path.root: 루트 모듈의 파일 시스템 경로를 반환합니다.
  • path.cwd: 현재 작업 중인 디렉터리의 파일 시스템 경로를 반환합니다. 테라폼을 사용할 때 이것은 path.root와 동일하지만 테라폼의 일부 기능은 루트 모듈 디렉터리 이외의 디렉터리에서 작동하므로 경로가 달라집니다.

사용자 데이터 스크립트의 경우 모듈 자체에 상대 경로가 필요하므로 template_file 데이터 소스에서 path.module을 사용해야 합니다.

data "template_file" "user_data" {
  template = file("$(path.module)/user-data.sh")

  vars = {
    server_port = var.server_port
    db_address  = data.terraform_remote_state.db.outputs.address
    db_port     = data.terraform_remote_state.db.outputs.port
  }
}

인라인 블록

일부 테라폼 리소스의 구성은 인라인 블록 또는 별도의 리소스로 정의할 수 있습니다. 모듈을 만들 때는 항상 별도의 리소스를 사용하는 것이 좋습니다.

예를 들어, aws_security_group 리소스를 사용하면 다음의 모듈에서 볼 수 있듯 인라인 블록을 통해 수신(ingress) 및 송신(egress) 규칙을 정의할 수 있습니다.

resource "aws_security_group" "alb" {
  name = "${var.cluster_name}-alb"

  ingress {
    from_port   = local.http_port
    to_port     = local.http_port
    protocol    = local.tcp.protocol
    cidr_blocks = local.all_ips
  }

  egress {
    from_port   = local.any_port
    to_port     = local.any_port
    protocol    = local.any_protocol
    cidr_blocks = local.all_ips
  }
}

별도의 aws_security_group_rule 리소스를 사용하여 정확히 동일한 수신 및 송신 규칙을 정의하도록 이 모듈을 변경해야 합니다. 모듈의 두 보안 그룹 모두에 이 작업을 수행합니다.

resource "aws_security_group" "alb" {
  name = "${var.cluster_name}-alb"
}

resource "aws_security_group_rule" "allow_http_inbound" {
  type              = "ingress"
  security_group_id = aws_security_group.alb.id

  from_port   = local.http_port
  to_port     = local.http_port
  protocol    = local.tcp_protocol
  cidr_blocks = local.all_ips
}

resource "aws_security_group_rule" "allow_all_outbound" {
  type              = "egress"
  security_group_id = aws_security_group.alb.id

  from_port   = local.any_port
  to_port     = local.any_port
  protocol    = local.any_protocol
  cidr_blocks = local.all_ips
}

인라인 블록 대신 별도의 리소스를 사용해야 하는 이유


인라인 블록과 별도의 리소스를 혼합하여 사용하려고 하면 라우팅 규칙이 충돌하여 덮어쓰는 오류가 발생합니다. 따라서 둘 중 하나만 사용해야 합니다. 이 제한 사항으로 인해 모듈을 작성할 때 항상 인라인 블록 대신 별도의 리소스를 사용해야합니다. 그렇지 않으면 모듈의 유연성이 떨어집니다.

예를 들어 모듈 내의 모든 수신 및 송신 규칙이 별도의 aws_security_group_rule 리소스로 정의된 경우 사용자가 모듈 외부에서 사용자 정의 규칙을 추가할 수 있도록 모듈을 유연하게 만들 수 있습니다. 이를 위해 aws_security_group의 ID를 출력 변수로 내보냅니다.

output "alb_security_group_id" {
  value       = aws_security_group.alb.id
  description = "The ID of the Security Group attached to the load balancer"
}

이제 스테이징 환경에서 테스트를 위해 포트를 추가로 노출해야 한다고 가정하겠습니다. aws_security_group_rule 리소스를 루트 모듈에 추가하기만 하면 됩니다.

resource "aws_security_group_rule" "allow_testing_inbound" {
  type              = "ingress"
  security_group_id = module.webserver_cluster.alb_security_group.id

  from_port   = 12345
  to_port     = 12345
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
}

aws_security_group과 같이 인라인 블록과 별도의 리소스를 모두 사용할 수 있는 리소스에는 다음의 것들이 있습니다. 이러한 유형의 리소스를 사용할 때는 항상 별도의 리소스를 정의하시기 바랍니다.

  • aws_security_group과 aws_security_group_rule
  • aws_route_table과 aws_route
  • aws_network_acl과 aws_network_acl_rule

👍 개인 공부 기록용 블로그입니다. 오류나 조언이 있으시면 언제든지 댓글 혹은 메일로 남겨주시면 감사하겠습니다! 😄

맨 위로 이동하기

terraform 카테고리 내 다른 글 보러가기

댓글남기기