본문 바로가기

AWS

[Terraform] 테라폼으로 모듈 구성하기 - count, for-each 등

Terraform?

IaC 도구로, AWS의 서비스를 코드로서 관리할 수 있게 해주는 플랫폼이다.

 

특히 AWS의 여러 서비스가 유기적으로 관련되어 있고, 콘솔로 반복적인 작업을 해야할 때 Terraform을 사용한다.

Terraform 모듈을 생성하면서 깨달은 것
- 테라폼에는 생각보다 다양한 문법이 있다. 잘 사용하면, 복잡한 구성도 테라폼으로 설계가 가능하다. 
- 모듈을 만들 때는 고려해야 할 부분이 꽤있지만, 잘 만들어놓으면 편하다.

Terraform Module

Terraform 모듈 내에 원하는 리소스들을 구성해놓으면, 여러 다른 위치에서 다른 변수값을 사용해서 리소스를 생성할 수 있다.

 

모듈은 다음과 같이 사용할 수 있다. 리소스를 구성해놓은 모듈 코드가 있는 PATH를 설정하고, Module이 필요로 하는 변수들을 적어주면 된다.

 

module "<NAME>" {
  source = "<MODULE_PATH>"
  cluster_name = "cluster-a"
}

 

모듈이 생성하는 resource는 다음과 같다. 보통의 리소스를 생성하는 코드와 동일하지만, 모듈을 사용하는 코드에서 건네주는 변수들을 사용해서 리소스를 생성해야 한다. var.cluster_name 과 같이 모듈을 사용하는 곳에서 설정한 변수를 받아와 리소스를 생성할 수 있다.

 

resource "aws_security_group" "elb-sg" {
  name = "${var.cluster_name}-elb-sg"
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

이러한 변수를 받아오기 위해서는 모듈에서 variable을 설정해주어야 한다. default 값을 설정할 수도 있고, 비워둬도 된다.

 

variable "cluster_name" {
	default = "cluster_default"
}

모듈에서 리소스를 생성한 후, 생성한 리소스에 대한 정보(arn, id 등)를 받기 위해 모듈에서 output을 통해 리소스 정보를 출력해주어야 한다.

모듈을 사용하는 곳에서는 module.<MODULE_NAME>.elb_sg_name 으로 output을 받아올 수 있다.

 

output "elb_sg_name" {
	value = aws_secruity_group.elb-sg.name 
}

Terraform 문법

 

위의 작업만으로도 테라폼 모듈을 생성하는데 큰 문제는 없지만, 다양한 문법들을 통해 확장성 있는 모듈을 구성할 수 있다.

 

1. Count

해당 리소스를 몇 개 생성할 것인지 명시해줄 수 있다. 

resource "aws_instance" "server" {
  count = 4 # create four similar EC2 instances
  [CONFIG]
  }
}

 

조금 더 응용해보면, ec2_create_enabled 라는 변수가 true일 때만, 해당 리소스를 생성할 수 있다. (모듈의 확장성을 위해 꼭 필요한 부분이라고 생각한다. 🙆🏻‍♀️)

count = var.ec2_create_enabled ? 1 : 0

 

다음과 같이 배열에 생성하고자 하는 정보를 담아서 정보가 다른 동일한 리소스를 여러 개 생성할 수도 있다.

variable "subnet_ids" {
  type = list(string)
}

resource "aws_instance" "server" {
  # Create one instance for each subnet
  count = length(var.subnet_ids)

  ami           = "ami-a1b2c3d4"
  instance_type = "t2.micro"
  subnet_id     = var.subnet_ids[count.index]

  tags = {
    Name = "Server ${count.index}"
  }
}

 

2. For-each

for each 구문을 사용해서 map object 기반으로 리소스 생성이 가능하다. each Object의 key, value를 사용해서 설정값들을 기반으로 리소스를 생성할 수 있다.

(set을 기반으로 사용할 때는 each.key만 사용하면 된다.)

firehose_iam_role_policy_objects = {
    "kinesis-policy" = {
        policy_name = ""
        policy = ""
    }, 
    "s3-policy" = {
        policy_name = ""
        policy = ""        
    }
    ...
}
resource "aws_iam_role_policy" "firehose_iam_role_policy" {
  for_each = var.firehose_iam_role_policy_objects

  name = each.value.policy_name
  role = aws_iam_role.firehose_iam_role.id
  policy = each.value.policy
}

 

더 많은 문법들이 있겠지만, 이번에 모듈을 생성할 때 가장 중요했던 문법은 count와 for_each 였다. 이를 통해 조금 더 동적으로 테라폼 리소스를 생성할 수 있었다.

 

복잡한 리소스들을 구성할 때, 최대한 코드를 건드리지 않고 변수 이름, 간단한 구성만을 설정해 리소스를 구성하게 하는 것이 테라폼 모듈을 만들 때 가장 중요한 것 같고 앞으로도 더 노력해야겠다. 🌿