1. Terraform Resource Block 구문 문법
Terraform의 리소스 블록 구문에는 두 가지 주요 요소가 있습니다.
첫 번째는 Arguments로, 리소스를 생성하기 위해 필요한 특정 정보입니다.
- 필수적으로 명시해야 하는 필수(Required) 항목과 추가 설정을 위한 선택적(Optional) 항목으로 나뉩니다.
- 각 리소스에 필요한 Arguments는 해당 프로바이더의 docs 페이지에서 확인할 수 있습니다.
두 번째는 Meta Arguments로, 모든 리소스에서 공통적으로 사용할 수 있는 Arguments입니다.
- 리소스 생성에 필요한 기본 Arguments 외에 추가적인 설정을 가능하게 합니다.
- ex) count, for_each, depends_on, lifecycle 등등
2. Arguments 예시
Terraform에서 AWS EC2 인스턴스를 생성하기 위한 리소스 블록을 예로 들어 설명합니다. (AWS EC2 Argument Reference)
aws_instacne 리소스의 기본 Arguments는 리소스를 생성하는 데 필수적인 정보를 포함합니다.
예를 들어, ami와 instance_type는 필수 Arguments로 필수(Required) 요소입니다.
- ami와 instance_type는 필수 Arguments로, 각각 EC2 인스턴스에 사용할 Amazon Machine Image(AMI)의 ID와 인스턴스 유형을 지정합니다. 이 두 필수 Arguments는 EC2 인스턴스 생성 시 반드시 명시되어야 합니다.
선택적(Optional) Arguments로는 key_name 과 vpc_security_group_ids 등을 설정할 수 있습니다.
- key_name과 vpc_security_group_ids는 선택 Arguments로, 각각 EC2 인스턴스에 할당할 키 페어 이름과 인스턴스에 적용할 보안 그룹을 지정합니다.
- 선택적 Arguments로는 이러한 구조를 통해 Terraform 사용자는 필요에 맞게 EC2 인스턴스를 세부적으로 설정할 수 있습니다.
# EC2 인스턴스를 생성하는 Terraform 리소스 블록
resource "aws_instance" "example" {
# 필수 Arguments
ami = "ami-1234567890abcdef0" # 인스턴스 생성에 사용할 Amazon Machine Image (AMI) ID
instance_type = "t2.micro" # EC2 인스턴스 유형
# 선택적 Arguments
key_name = "my-key-pair" # 인스턴스에 할당할 키 페어 이름
vpc_security_group_ids = ["sg-12345678"] # 인스턴스에 적용할 보안 그룹 ID
# 태그 추가 (선택적)
tags = {
Name = "MyExampleInstance"
}
}
3. Meta Arguments
resource를 생성하기 위해 필요한 Arguments 외에 모든 resource가 공통적으로 사용할 수 있는 Arguments를 Meta Arguments라 합니다.
3-1) Count
count는 리소스 복수 생성 시 사용되는 Meta Argument로, 정수 값을 받아 해당 수만큼 리소스를 생성합니다.
아래와 같이 count를 사용하여 AWS EC2를 여러개 생성할 수 있습니다.
data "aws_ami" "latest_amazon_linux_2" {
most_recent = true
filter {
name = "name"
values = ["*amzn2-ami-hvm*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
filter {
name = "architecture"
values = ["x86_64"]
}
owners = ["amazon"]
}
resource "aws_instance" "example" {
count = 3 # 세 개의 EC2 인스턴스 생성
ami = data.aws_ami.latest_amazon_linux_2.id
instance_type = "t2.micro"
}
- 위 코드는 AWS EC2를 생성하는 resource block에 count Meta Argument를 사용하여 count에 정의해놓은 수 만큼 반복하여 AWS EC2를 생성합니다.
- count Argument 로 생성된 각 인스턴스에는 count 0부터 시작하여 추가 인스턴스마다 1씩 증가하는 고유 index가 할당됩니다.
- 이 index는 리소스 블록 내에서 count.index로 액세스할 수 있으므로 각 인스턴스의 구성을 차별화할 수 있습니다.
- 예를 들어 인덱스를 사용하여 각 인스턴스에 고유한 이름을 할당하거나 인덱스 위치를 기반으로 목록에서 특정 값을 검색할 수 있습니다.
resource "aws_instance" "example" {
count = 3 # 세 개의 EC2 인스턴스 생성
ami = data.aws_ami.latest_amazon_linux_2.id
instance_type = "t2.micro"
tags = {
Name = "Server-${count.index}" # Names will be Server-0, Server-1, Server-2
}
}
- output으로 count로 생성된 리소스값을 추출하기 위해 을 정의하는 방법은 다음과 같습니다.
- output 블록은 리소스 블록이 count로 생성한 두 번째 인스턴스의 퍼블릭 IP 주소를 검색합니다.
- index [1]는 0부터 시작한다는 점을 고려하여 두 번째 인스턴스를 참조하는 데 사용됩니다. 이렇게 하면 으로 여러 인스턴스를 생성한 경우 특정 인스턴스에 직접 쉽게 액세스할 수 있습니다 .
output "secondary_instance_public_ip" {
value = aws_instance.example[1].public_ip
}
3-2) for_each
for_each는 Terraform에서 동일한 리소스 유형의 여러 리소스를 생성할 때 사용되며, count와는 달리 map이나 set 형식을 기반으로 각 요소에 대한 리소스를 생성합니다.
for_each를 사용할 경우, 리소스 블록 내에서 동일한 리소스 타입의 다수 인스턴스를 효율적으로 관리할 수 있습니다. 단, for_each와 count는 동일한 리소스 블록에서 함께 사용할 수 없습니다.
set 형식은 list unique element 특징을 가지고 있어서 리스트 안에 중복 값을 가질 수 없습니다.
- [a,b,c]는 가능하지만, [a,a,b,c]는 불가능
map 형식은 각 요소를 each.key와 each.value를 통해 참조할 수 있습니다.
- {name: "junho"}에서 each.key는 "name", each.value는 "junho"
- set 형식 예시
- for_each를 통해 여러명의 IAM User를 생성합니다.
# set 형식
resource "aws_iam_user" "the-accounts" {
for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
name = each.key
}
- set 형식 output 예시
- for_each를 set 형식으로 생성 후 output은 다음과 같이 확인할 수 있습니다.
# 모든 User의 이름 출력
output "user_names" {
value = [for user in aws_iam_user.the-accounts : user.name]
}
# Alice User의 이름 출력
output "Alice_name" {
value = aws_iam_user.the-accounts["Alice"].name
}
- map 형식 예시
- for_each로 리소스를 생성시 map 형식을 사용하여 key, value값을 통해 user 이름과 tag 를 함께 코드를 작성 가능합니다.
# map 형식
resource "aws_iam_user" "iam-user-account" {
for_each = {
alice = {
level = "low"
manager = "developer"
}
bob = {
level = "mid"
manager = "cloud-ta"
}
jh = {
level = "high"
manager = "devops"
}
}
name = each.key
tags = each.value
}
- map 형식 output 예시
- for_each를 map 형식으로 생성 후 output은 다음과 같이 확인할 수 있습니다.
output "user_names" {
value = [for user in aws_iam_user.iam_user_account : user.name]
}
output "alice_user_arn" {
value = aws_iam_user.iam_user_account["alice"].arn
}
4. for_each 와 Count 비교
for_each 문은 반복을 수행 시 object key로 접근하여, index로 접근하는 list type의 count 와는 다르게 효율적입니다.
예로 index형식의 count를 사용하여 iam user 생성 시 중간에 유저를 지우고 apply하면 오류가 발생하지만, for_each 를 사용하여 iam user 생성 시 중간 유저를 지우고 apply하면 정상적으로 유저를 지울 수 있습니다.
4-1) count 를 이용하여 IAM 사용자 생성 및 삭제 테스트
- count를 사용하여 iam user 생성 시 중간에 유저를 지우고 apply하는 테스트를 진행합니다.
resource "aws_iam_user" "user_count" {
count = length(var.user_names) # var.user_names is a list of names
name = var.user_names[count.index]
}
# Assuming var.user_names = ["user1", "user2", "user3"]
variable "user_names" {
default = ["user1", "user2", "user3"]
}
- var.user_names에서 "user2"를 제거하고 적용하면 Terraform은 나머지 사용자를 다시 색인화합니다. 이로 인해 "user3"이 "user2"의 위치로 이동하므로 의도하지 않은 삭제나 재생성이 발생할 수 있습니다.
- "user2"라는 IAM 사용자를 "user3"으로 업데이트하려고 할 때 오류가 발생한 것 같지만 "user3"이 AWS 환경에 이미 존재합니다. 이 오류는 일반적으로 IAM 시스템의 다른 활성 사용자가 이미 사용한 이름으로 사용자의 이름을 바꾸거나 다시 생성하려고 할 때 발생합니다.
- 즉, "user3"이 지워지기 전에 "user2"의 이름을 "user3"으로 변경하려고 했기 때문에 발생한 에러입니다.
- 다시 Terraform apply를 실행하게 되면 다음과 같이 "user2"가 "user3"이란 이름으로 변경됨을 확인할 수 있습니다.
- 결론
- 처음 원했던 결과는 "user2"만 삭제되는 것이였지만, "user2"의 이름이 "user3"으로 변경되었고, "user3"은 삭제가 되었습니다.
- 만약 실제 운영환경에서의 서버 리소스였다면 중요한 서버 리소스를 잘못 삭제하는 경우, 복구할 수 없는 심각한 결과를 초래할 수 있습니다.
4-2) for_each 를 이용하여 IAM 사용사 생성 및 삭제 테스트
- for_each를 사용하여 iam user 생성 시 중간에 유저를 지우고 apply하는 테스트를 진행합니다.
resource "aws_iam_user" "user_each" {
for_each = toset(var.user_names) # Convert the list of names to a set
name = each.value # Use each.value to access the user name
}
variable "user_names" {
default = ["user1", "user2", "user3"]
}
- 결론
- count와 다르게 for_each를 사용했을 경우 원했던 결과는 "user2"만 삭제되는 것이였으며, 원하는 결과처럼 "user2"만 삭제" 되었습니다.
'Terraform' 카테고리의 다른 글
[테라폼] ECS배포 및 revision관리 (1) | 2023.12.03 |
---|---|
[테라폼] EKS 배포 및 Add on 설치 (0) | 2023.10.20 |
[테라폼] Workflow & gitlab runner 프로비저닝 파이프라인 (0) | 2023.08.20 |
[테라폼] State & Module (1) | 2023.07.29 |
[Terraform] 조건문 - 3항 연산자 (0) | 2023.07.22 |