Programming/IaC

[IaC] Terraform modules

Hayley Shim 2023. 10. 28. 17:49

안녕하세요. CloudNet@ Terraform Study를 진행하며 해당 내용을 이해하고 공유하기 위해 작성한 글입니다. 도서 ‘Terraform: Up & Running(By Yevgeniy Brikman)’ 의 내용 및 스터디 시간 동안 언급된 주요 내용 위주로 간단히 정리했습니다.

모듈

  • 테라폼을 사용하면 코드를 테라폼 모듈에 넣고 전체 코드의 여러 위치에서 해당 모듈을 재사용할 수 있습니다.

Figure 4–5. Putting code into modules allows you to reuse that code from multiple environments

  • 위 그림에서와 같이 Staging 와 Production 환경에서 동일한 코드를 복사하여 사용하는 대신 아래 처럼 두 환경에서 동일한 모듈의 코드를 재사용할 수 있습니다.

모듈의 기본

module "<NAME>" {
  source = "<SOURCE>"[CONFIG ...]
}
  • NAME : 테라폼 코드 전체에서 참조하기 위해 사용하는 식별자
  • SOURCE : modules/services/webserver-cluster 같은 모듈 코드를 찾을 수 있는 경로
  • CONFIG : 그 모듈과 관련된 특정한 하나 이상의 인수로 구성됨

Staging 예시

  • 아래와 같이 stage/services/webserver-cluster/main.tf 에 새 파일을 만들고 다음과 같이 webserver-cluster 모듈을 사용 할 수 있습니다.
  • 이때, modules/services/webserver-cluster 에서 main.tf 파일을 생성하고 provider 정의를 제거해줘서 중복을 방지합니다.
 
  • 모듈을 적용하거나 source 파라미터를 수정하는 경우 반드시 terrraform init 실행이 필요합니다.
  • 즉, init 명령어 하나로 손쉽게 공급자와 모듈을 다운로드하고 백엔드를 구성합니다.

$ terraform init
Initializing modules...
- webserver_cluster in ../../../modules/services/webserver-cluster
  • 마지막으로 실제 적용 시 실패하게 됩니다.
  • 이는 이름이 하드코딩 되어 있어서 중복 이름으로 실패하게 되는 것이므로 모듈에도 입력 매개 변수를 만들어줘야합니다.

모듈 입력

  • 테라폼에서는 모듈에도 입력 변수(input variables) 사용이 가능합니다.
  • modules/services/webserver-cluster/variables.tf 에 새로운 입력 변수 3개를 추가해줍니다.
 
  • modules/services/webserver-cluster/main.tf 에 하드 코딩된 이름 대신 var.cluster_name 을 사용해줍니다
  • 아래 예시에서는 ALB가 사용할 보안 그룹 이름에 사용해줬습니다.
 

스테이징 환경

  • stage/services/webserver-cluster/main.tf 에서 아래와 같이 새로운 입력 변수를 설정해줍니다.
 

모듈과 지역 변수

  • 입력 변수를 사용하여 모듈의 입력을 정의하는 것도 좋지만 중간에 계산을 수행하거나 코드가 중복되지 않게끔 모듈에서 변수를 정의하는 방법이 필요합니다.
  • 입력 변수를 사용하는 대신 이러한 값을 locals 블록에서 로컬값(local values)으로 정의하면 됩니다.
  • 모듈에서 로컬 값 사용 시 이름은 모듈 내에서만 표시되므로 다른 모듈에는 영향을 미치지 않으며, 모듈 외부에서 이 값을 재정의할 수 없습니다.
  • 로컬 값을 읽으려면 다음구문으로 된 로컬 참조(local reference) 를 사용해야 합니다.
local.<NAME>
 

모듈 출력

  • 모듈에 출력 Output 값을 활용합니다.
# 사용 구문
module.<MODULE_NAME>.<OUTPUT_NAME># 다음과 같이 사용
module.frontend.asg_name

모듈 주의 사항

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

1. 파일 경로

  • 루트 모듈에서 file 함수 사용은 가능하지만, 별도의 폴더에 정의된 모듈에서 file 함수를 사용하기 위해서 경로 참조(path reference) 표현식을 사용할 수 있습니다.

— path.module : 표현식이 정의된 모듈의 파일 시스템 경로를 반환

— path.root : 루트 모듈의 파일 시스템 경로를 반환

— path.cwd : 현재 작업 중인 디렉터리의 파일 시스템 경로를 반환

  • 예를 들어 아래와 같이 사용자 데이터 스크립트의 경우 모듈 자체에 상대 경로가 필요하므로 modules/services/webserver-cluster/main.tf 의 templatefile 데이터소스에서 path.module 사용합니다.
user_data = templatefile("${path.module}/user-data.sh", {
    server_port = var.server_port
    db_address  = data.terraform_remote_state.db.outputs.address
    db_port     = data.terraform_remote_state.db.outputs.port
  })

2. 인라인 블록

  • 일부 테라폼 리소스는 인라인 블록(inline block) 또는 별도의 리소스(권장)로 정의 할 수 있습니다.
  • 예를 들어 aws_security_group 리소스에 인라인 블록을 통해 인/아웃 규칙을 정의할 수 있습니다.
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 리소스와 aws_security_group_rule 리소스를 통해서 별도로 정의하여 사용합니다.
 

모듈 버전 관리

  • 스테이징 환경과 프로덕션 환경이 동일한 모듈 폴더를 가리키는 경우 해당 폴더를 변경하면 바로 다음 배포 시 두 환경에 모두 영향을 미칩니다.
  • 환경별로 다른 버전을 사용할 수 있도록 버전이 지정된 모듈(versioned modules)을 만드는 것이 더 적절한 접근 방식입니다.

Figure 4–7. Using different versions of a module in different environments

모듈 실습

  • 기존 코드 재생성 : Github repo
  • 주의 : region 변경 시 AMI 이미지 바꿔주기, ASG 테스트 시 AZ 4개까지 지원되는 t3 instance type 이상(t3.nano 등) 적용할 것

모듈화 적용 후 실행 화면(s3)

모듈화 적용 후 실행 화면(EC2)

추가 실습

# init
terraform init# 폴더 확인
tree .terraform -L 2
.terraform
├── modules
│   ├── ec2_instances
│   ├── modules.json
│   └── vpc
└── providers
    └── registry.terraform.io# (옵션) NATGW 제거
export TF_VAR_vpc_enable_nat_gateway=false  # macOS/Linux
set TF_VAR_vpc_enable_nat_gateway=false     # windows
 
# plan & apply
terraform plan && terraform apply -auto-approve# 확인
terraform state list# 삭제
terraform destroy -auto-approve
# init
terraform init# 폴더 확인
tree .terraform -L 2
.terraform
├── modules
│   ├── ec2_instances
│   ├── modules.json
│   └── vpc
└── providers
    └── registry.terraform.io# (옵션) NATGW 제거
export TF_VAR_vpc_enable_nat_gateway=false  # macOS/Linux
set TF_VAR_vpc_enable_nat_gateway=false     # windows
 
# plan & apply
terraform plan && terraform apply -auto-approve# 확인
terraform state list#
aws s3 cp modules/aws-s3-static-website-bucket/www/ s3://$(terraform output -raw website_bucket_name)/ --recursive# curl 혹은 웹 브라우저에서 S3 버킷 접속
curl -s http://$NICKNAME-t101-s3.s3-website.ap-northeast-2.amazonaws.com/
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Static Website</title>
  </head>
  <body>
    <p>Nothing to see here.</p>
  </body>
</html>
# 삭제
terraform destroy -auto-approve

 

 

blog migration project

written in 2022.11.6

https://medium.com/techblog-hayleyshim/iac-terraform-modules-354392b63fdd