cloudNet@ 팀의 가시다 님이 진행하는 AWS EKS 스터디 8주차 정리입니다.
테라폼 기본 사용법을 어느 정도 학습 한 뒤에는 실제 운영 환경에서 테라폼을 사용할때 고려 해야 하는 부분을 학습할것이다.
그중 하나가 모듈의 재사용성 부분이다.
테라폼 모듈
재사용성?
테라폼으로 인프라와 서비스를 관리하면 시간이 지날수록 구성이 복잡해지고 관리하는 리소스가 늘어나게 된다. 테라폼의 구성 파일과 디렉터리 구성에는 제약이 없기 때문에 단일 파일 구조상에서 지속적으로 업데이트할 수 있지만, 다음과 같은 문제가 발생한다.
- 테라폼 구성에서 원하는 항목을 찾고 수정하는 것이 점점 어려워짐
- 리소스들 간의 연관 관계가 복잡해질수록 변경 작업의 영향도를 분석하기 위한 노력이 늘어남
- 개발/스테이징/프로덕션 환경으로 구분된 경우 비슷한 형태의 구성이 반복되어 업무 효율이 줄어듦
- 새로운 프로젝트를 구성하는 경우 기존 구성에서 취해야 할 리소스 구성과 종속성 파악이 어려움
이를 해결하기 위해 모듈이라는 개념을 사용한다.
모듈의 종류
루트 모듈
- Root Module : 테라폼을 실행하고 프로비저닝하는 최상위 모듈
자식 모듈
- Child Module : 루트 모듈의 구성에서 호출되는 외부 구성 집합
모듈의 작성 원칙
- 테라폼 구성은 궁극적으로 모듈화가 가능한 구조로 작성할 것을 제안한다. 처음부터 모듈화를 가정하고 구성파일을 작성하면 단일 루트 모듈이라도 후에 다른 모듈이 호출할 것을 예상하고 구조화할 수 있다. 또한 작성자는 의도한 리소스 묶음을 구상한 대로 논리적인 구조로 그룹화할 수 있다.
- 각각의 모듈을 독립적으로 관리하기를 제안한다. 리모트 모듈을 사용하지 않더라도 처음부터 모듈화가 진행된 구성들은 떄로 루트 모듈의 하위 파일 시스템에 존재하는 경우가 있다. 하위 모듈 또한 독립적인 모듈이므로 루트 모듈 하위에 두기보다는 동일한 파일 시스템 레벨에 위치하거나 별도 모듈만을 위한 공간에서 불러오는 것을 권장한다. 이렇게 하면 VCS를 통해 관리하기가 더 수월하다.
- 공개된 테라폼 레지스트리의 모듈을 참고하기를 제안한다. 대다수의 테라폼 모듈은 공개된 모듈이 존재하고 거의 모든 인수에 대한 변수 처리, 반복문 적용 리소스, 조건에 따른 리소스 활성/비활성 등을 모범 사례로 공개해두었다. 물론 그대로 가져다 사용하는 것보다는 프로비저닝하려는 상황에 맞게 참고하는 것을 권장한다.
- 작성된 모듈은 공개 또는 비공개로 게시해 팀 또는 커뮤니티와 공유하기를 제안한다. 모듈의 사용성을 높이고 피드백을 통해 더 발전된 모듈을 구성할 수 있는 자극이 된다.
😃 모듈 실습해보기
- 모듈 없이 먼저 테스트
✅ 디렉토리 생성
mkdir -p 06-module-traning/modules/terraform-random-pwgen
✅ main.tf 생성
cat <<EOT > main.tf
resource "random_pet" "name" {
keepers = {
ami_id = timestamp()
}
}
resource "random_password" "password" {
length = var.isDB ? 16 : 10
special = var.isDB ? true : false
override_special = "!#$%*?"
}
EOT
✅ variable.tf 생성
cat <<EOT > variable.tf
# variable.tf
variable "isDB" {
type = bool
default = false
description = "패스워드 대상의 DB 여부"
}
EOT
✅ output.tf 생성
cat <<EOT > output.tf
# output.tf
output "id" {
value = random_pet.name.id
}
output "pw" {
value = nonsensitive(random_password.password.result)
}
EOT
✅ 실행 및 확인
#
cd 06-module-traning/modules/terraform-random-pwgen
#
ls *.tf
terraform init && terraform plan
# 테스트를 위해 apply 시 변수 지정
terraform apply -auto-approve -var=isDB=true
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
id = "knowing-aardvark"
pw = "Y5eeP0i2KLLE9gBa"
# 확인
terraform state list
terraform state show random_pet.name
terraform state show random_password.password
# tfstate에 모듈 정보 확인
cat terraform.tfstate | grep module
# graph 확인
terraform graph > graph.dot
- 리소스를 module 사용 없이 배포한 경우 다음과 같이 tfstate에 module 관련 상태값이 없음
- 반대로 module 사용하여 자식 모듈 구성 해보고 비교해보자
- 아래 코드를 따라 해보자
✅ 자식 모듈 디렉토리 생성
mkdir -p 06-module-traning/06-01-basic
✅ 모듈을 활용하여 리소스 배포 ( 반복적으로 사용하기 좋음 )
#main.tf
module "mypw1" {
source = "../modules/terraform-random-pwgen"
}
module "mypw2" {
source = "../modules/terraform-random-pwgen"
isDB = true
}
output "mypw1" {
value = module.mypw1
}
output "mypw2" {
value = module.mypw2
}
#
cd 06-module-traning/06-01-basic
#
terraform init && terraform plan && terraform apply -auto-approve
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
mypw1 = {
"id" = "equipped-mustang"
"pw" = "OXST1EYqQc"
}
mypw2 = {
"id" = "diverse-impala"
"pw" = "y8mEbOJhS6dCTiK#"
}
# 확인
terraform state list
# tfstate에 모듈 정보 확인
cat terraform.tfstate | grep module
# terraform init 시 생성되는 modules.json 파일 확인
tree .terraform
.terraform
├── modules
│ └── modules.json
...
## 모듈로 묶여진 리소스는 module이라는 정의를 통해 단순하게 재활용하고 반복 사용할 수 있다.
## 모듈의 결과 참조 형식은 module.<모듈 이름>.<output 이름>으로 정의된다.
cat .terraform/modules/modules.json | jq
{
"Modules": [
{
"Key": "",
"Source": "",
"Dir": "."
},
{
"Key": "mypw1",
"Source": "../modules/terraform-random-pwgen",
"Dir": "../modules/terraform-random-pwgen"
},
{
"Key": "mypw2",
"Source": "../modules/terraform-random-pwgen",
"Dir": "../modules/terraform-random-pwgen"
}
]
}
# graph 확인
terraform graph > graph.dot
- 자식 모듈 사용시 tfstate에 모듈 관련 State가 생성된것을 볼수 있음
모듈 Best Practice 실습해보기
https://www.terraform-best-practices.com/examples/terraform/large-size-infrastructure-with-terraform
- 위 링크를 들어가보면 git 주소를 하나 준다. 이를 clone해서 우선 배포해보자
$ git clone https://github.com/antonbabenko/terraform-best-practices.git
tree -l
.
├── README.md
├── modules
│ └── network
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
├── prod
│ ├── main.tf
│ ├── outputs.tf
│ ├── terraform.tfvars
│ └── variables.tf
└── stage
├── main.tf
├── outputs.tf
├── terraform.tfvars
└── variables.tf
5 directories, 12 files
- 여기서 우선 우리가 배운 개념이 나온다. 최상단에 루트 모듈 (modules)와 차일드 모듈( prod,stage) 디렉토리로 구분됨
# 디렉토리 변경 (루트모듈)
cd ~/Desktop/toy/terraform-best-practices/examples/large-terraform/modules/network
# 테라폼 준비
terraform init
# .terraform 에 registry 모듈이 생성됨 plan을 실행하면 여러가지 에러가 발생
terraform plan
│ Error: Unsupported argument
│
│ on .terraform/modules/vpc/main.tf line 35, in resource "aws_vpc" "this":
│ 35: enable_classiclink = null # https://github.com/hashicorp/terraform/issues/31730
│
│ An argument named "enable_classiclink" is not expected here.
╵
╷
│ Error: Unsupported argument
│
│ on .terraform/modules/vpc/main.tf line 36, in resource "aws_vpc" "this":
│ 36: enable_classiclink_dns_support = null # https://github.com/hashicorp/terraform/issues/31730
│
│ An argument named "enable_classiclink_dns_support" is not expected here.
╵
╷
│ Error: Unsupported argument
│
│ on .terraform/modules/vpc/main.tf line 1246, in resource "aws_default_vpc" "this":
│ 1246: enable_classiclink = null # https://github.com/hashicorp/terraform/issues/31730
│
│ An argument named "enable_classiclink" is not expected here.
- ec2-classic 링크는 지원 중단됨
- 외부 레지스트리 모듈을 terraform init하면 다음과 같이 디렉토리에 해당 모듈을 클론해서 오는데 여기를 수정해준다.
- main.tf 변경 35줄 36줄 1244줄 제거
- 이후 재시도 - 실패
terraform plan
│ Error: expected "cidr_block" to contain a network Value with between 16 and 28 significant bits, got: 0
│
│ with module.vpc.aws_vpc.this[0],
│ on .terraform/modules/vpc/main.tf line 23, in resource "aws_vpc" "this":
│ 23: cidr_block = var.use_ipam_pool ? null : var.cidr
│
- 이번에는 우리가 처음 작성한 루트모듈의 variable.tf를 확인해보자
variable "cidr" {
description = "The CIDR block for the VPC. Default value is a valid CIDR, but not acceptable by AWS and should be overriden"
type = string
default = "0.0.0.0/0"
}
# 여기 0.0.0.0/16비트로 수정
variable "cidr" {
description = "The CIDR block for the VPC. Default value is a valid CIDR, but not acceptable by AWS and should be overriden"
type = string
default = "10.0.0.0/16"
}
- 테라폼 apply
$ terraform apply
...
Enter a value: yes
module.vpc.aws_vpc.this[0]: Creating...
module.vpc.aws_vpc.this[0]: Creation complete after 1s [id=vpc-03389bacdeaf0dcdc]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
vpc_id = "vpc-03389bacdeaf0dcdc"
- 성공
'DevOps' 카테고리의 다른 글
[AWS EKS] EKS IaC with Terraform (1) (0) | 2024.04.23 |
---|---|
[AWS EKS] EKS CICD (0) | 2024.04.15 |
[AWS EKS] EKS Security (Kyverno) (0) | 2024.04.13 |
[AWS EKS] EKS Security (IRSA) (0) | 2024.04.11 |
[AWS EKS] EKS Security ( IAM Authenticator) (0) | 2024.04.08 |