들어가며
* 본 스터디의 자료는 아래의 책을 기반으로 합니다.
테라폼으로 시작하는 IaC | 김민수, 김재준, 이규석, 이유종 | 링크
이번 주차에서는 테라폼 모듈과 Runner에 대해 학습했습니다. 지난 스터디와 다르게 Runner 파트에서는 Atlantis라는 도구를 이용하여 GitOps처럼 comment를 통해 repository에 저장된 테라폼 코드를 기반으로 프로비저닝 하는 법을 배웠는데 너무 신기했습니다. 여러 명과 테라폼 인프라를 기반으로 협업할 때 많은 도움이 될 것 같았습니다.
모듈
테라폼 모듈은 테라폼에서 자주 사용하는 구성요소를 재사용 가능하게 만드는 코드 블록입니다. 이러한 테라폼 모듈을 사용하면 코드 작성시 표준화와 유지보수성을 높일 수 있습니다.
출처 - 링크
테라폼 스터디 책에서 제안하는 모듈 작성의 기본 원칙은 다음과 같습니다.
- terraform-<프로바이더 이름>-<모듈 이름> 형식을 제안
테라폼 클라우드와 엔터프라이즈에서도 사용되는 방식으로 "디렉토리 또는 레지스트리 이름"이 "어떤 리소스를 포함"하고 있으며, "부여된 이름이 무엇인지 판별" 할 수 있도록 함 - 테라폼 구성은 궁극적으로 모듈화가 가능한 구조로 작성
- 각각의 모듈을 독립적으로 관리하기를 제안함
실습 - 모듈 작성
프로비저닝에서 사용자와 패스워드를 여러번 구성해야 하는 경우 이름과 패스워드를 자동으로 생성합니다.
random_password는 random 프로바이더를 통해 난수로 패스워드를 생성합니다.
#모듈 디렉토리 하위에 †erraform-random-pwgen 생성
mkdir -p 06-module-traning/modules/terraform-random-pwgen
cd 06-module-traning/modules/terraform-random-pwgen
# 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 = "!#$%*?"
}
# variable.tf
variable "isDB" {
type = bool
default = false
description = "패스워드 대상의 DB 여부"
}
# output.tf
output "id" {
value = random_pet.name.id
}
output "pw" {
value = nonsensitive(random_password.password.result)
}
해당 코드를 실행하면 다음과 같이 랜덤한 id, pw가 생성됩니다.
실습 - 모듈 호출
모듈을 활용하면 반복되는 리소스의 묶음을 최소화할 수 있습니다. 이전 실습에서 생성한 모듈을 호출하여 실행하면 다음과 같이 정상작동 하는 것을 확인할 수 있습니다.
mkdir -p 06-module-traning/06-01-basic
cd 06-module-traning/06-01-basic
touch 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
}
terraform.tfstate를 살펴보면 resources 부분에 mypw1, mypw2 모듈이 추가되었음을 확인할 수 있습니다.
그래프를 확인해보면 다음과 같이 리소스들의 중간에 모듈이 추가된 것을 확인할 수 있습니다.
모듈 사용방식
기본 사용법
모듈에서 사용하는 프로바이더를 공통으로 할 것인지 디렉터리를 나눌 것인지 고민이 되는 이슈는 루트 모듈에서 프로바이더를 정의하는 형태로 진행하는 게 좋습니다. 프로바이더를 모듈 내 리소스와 데이터에 자연스럽게 일괄 적용하고, 자식 모듈에 대한 반복문 사용을 자유롭게 할 수 있기 때문입니다.
실습 - 모듈과 프로바이더
먼저 다음과 같이 AWS 인스턴스를 생성하는 자식 모듈을 생성합니다.
mkdir -p 06-module-traning/modules/terraform-aws-ec2/
cd 06-module-traning/modules/terraform-aws-ec2/
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
}
}
resource "aws_default_vpc" "default" {}
data "aws_ami" "default" {
most_recent = true
owners = ["amazon"]
filter {
name = "owner-alias"
values = ["amazon"]
}
filter {
name = "name"
values = ["amzn2-ami-hvm*"]
}
}
resource "aws_instance" "default" {
depends_on = [aws_default_vpc.default]
ami = data.aws_ami.default.id
instance_type = var.instance_type
tags = {
Name = var.instance_name
}
}
# variable.tf
variable "instance_type" {
description = "vm 인스턴스 타입 정의"
default = "t2.micro"
}
variable "instance_name" {
description = "vm 인스턴스 이름 정의"
default = "my_ec2"
}
# output.tf
output "private_ip" {
value = aws_instance.default.private_ip
}
작성된 모듈을 사용할 루트 모듈 디렉터리와 실행 파일을 생성합니다.
mkdir -p 06-module-traning/multi_provider_for_module/
cd 06-module-traning/multi_provider_for_module/
touch main.tf output.tf
# main.tf
provider "aws" {
region = "ap-southeast-1"
}
provider "aws" {
alias = "seoul"
region = "ap-northeast-2"
}
module "ec2_singapore" {
source = "../modules/terraform-aws-ec2"
}
module "ec2_seoul" {
source = "../modules/terraform-aws-ec2"
providers = {
aws = aws.seoul
}
instance_type = "t3.small"
}
# output.tf
output "module_output_singapore" {
value = module.ec2_singapore.private_ip
}
output "module_output_seoul" {
value = module.ec2_seoul.private_ip
}
cd 06-module-traning/multi_provider_for_module/
terraform init
cat .terraform/modules/modules.json | jq
#
terraform apply -auto-approve
terraform output
terraform state list
terraform state show module.ec2_seoul.data.aws_ami.default
terraform state show module.ec2_singapore.data.aws_ami.default
# tfstate에 모듈 정보 확인 : VSCODE에서 terraform.tfstate 파일 확인
cat terraform.tfstate | grep module
# graph 확인
terraform graph > graph.dot
다음과 같이 모듈을 사용하여 두개의 인스턴스가 생선 된 것을 확인할 수 있습니다.
모듈 반복문
모듈을 구성하는 리소스에서 반복문을 사용하듯 구성이 가능합니다. count를 사용하여 모듈 안에 반복 수량을 설정할 수 있습니다.
mkdir -p 06-module-traning/module_loop_count/
cd 06-module-traning/module_loop_count/
touch main.tf
provider "aws" {
region = "ap-northeast-2"
}
module "ec2_seoul" {
count = 2
source = "../modules/terraform-aws-ec2"
instance_type = "t3.small"
}
output "module_output" {
value = module.ec2_seoul[*].private_ip
}
terraform apply -auto-approve
terraform output
terraform state list
# tfstate에 모듈 정보 확인 : VSCODE에서 terraform.tfstate 파일 확인
cat terraform.tfstate | grep module
# graph 확인
terraform graph > graph.dot
다음과 같이 모듈이 잘 적용된 것을 확인할 수 있습니다.
도전 - 각자 모듈을 활용해서 반복리소스 배포
실습 - 동일한 모듈에 개발과 상용에 대한 입력 변수를 다르게 처리하는 방식
동일한 리소스를 반복적으로 생성하는 모듈을 사용할 경우 필요한 인수가 다를경우 for_each를 활용합니다.
locals {
env = {
dev = {
type = "t3.micro"
name = "dev_ec2"
}
prod = {
type = "t3.medium"
name = "prod_ec2"
}
}
}
module "ec2_seoul" {
for_each = local.env
source = "../modules/terraform-aws-ec2"
instance_type = each.value.type
instance_name = each.value.name
}
output "module_output" {
value = [
for k in module.ec2_seoul: k.private_ip
]
}
실습 - Terraform Tutorials (Fundamentals) - Modules
테라폼 모듈 사용법에 대한 hashicorp 사의 예제를 실습해 보았습니다.
git clone https://github.com/hashicorp/learn-terraform-modules-use.git
cd learn-terraform-modules-use
tree
ls *.tf
cat main.tf
https://github.com/hashicorp/learn-terraform-modules-use
디렉토리는 main.tf, outputs.tf, terrform.tf, variables.tf로 구성되어 있습니다. terraform-aws-modules를 기반으로 2개의 ec2 인스턴스를 기반으로 VPC와 서브넷, 라우팅 테이블 등을 생성합니다.
Terraform Runner
Terraform을 GitOps처럼 리포지토리를 기반으로 상태를 관리하는 것을 의미합니다. 워크플로우라고 하기도하는데, Runner라고 하는 툴들 중 아틀란티스를 주로 사용하고 있는 것 같습니다. 개발자는 github에 테라폼 코드를 업로드하고, PR comment를 통해 인프라 프로비저닝을 수행할 수 있도록 합니다. 다른 개발자들은 github의 pr을 통해 인프라를 리뷰 및 승인할 수 있습니다. Github는 Atlantis Server를 통해 인프라를 생성 및 변경할 수 있습니다.
Atlantis
Atlantis는 Hootsuite에서 사용하던 Terraform에서 협업하기 위한 도구입니다. Atlantis의 핵심 기능을 통해 개발자와 운영자는 Terraform 풀 리퀘스트에서 직접 실행 terraform plan, apply 할 수 있습니다. 그런 다음 Atlantis는 명령의 출력으로 풀 리퀘스트에 다시 주석을 달 수 있습니다.
실습 - Atlantis 사용해 보기
클라우드포메이션을 이용하여 t101-atlantis-ec2.yaml 파일을 배포합니다.
CloudFormation 스택 상태를 확인합니다.
설치가 잘 완료되면 아틀란티스 서버의 접속주소를 확인하여 접속할 수 있습니다.
다음으로는 아틀란티스로 관리할 테라폼 코드 리포지토리와 웹훅 셋팅을 합니다.
Github → Settings → Developer settings ⇒ Personal access tokens : Tokens (classic)에서 Repo 기능 을 선택한 후 토큰을 발급받습니다.
다음으로는 노출된 아틀란티스 서버 주소를 통해 웹훅을 연결합니다.
아틀란티스 서버에 접속하면 다음과 같은 메인 화면을 볼 수 있습니다.
작업 1 : null 프로바이더 추가
git clone https://github.com/gasida/t101-cicd && cd t101-cicd && tree
# feature branch 생성
git branch test && git checkout test && git branch
# main.tf 파일 작성
echo 'resource "null_resource" "example" {}' > main.tf
# add commit push
git add main.tf && git commit -m "add main.tf" && git push origin test
레포지토리에서 다음과 같이 PR 생성 알람을 확인할 수 있습니다.
Create Pull request 를 수행하면 다음과 같이 아틀란티스 서버의 로그에서 해당 내용을 수행하기 위한 절차들이 수행되는 것을 확인할 수 있습니다.
PR comment 등록합니다.
atlantis plan -d . 를 코멘트로 등록하면 다음과 같이 Details를 클릭했을 때 plan이 수행된 것을 확인할 수 있습니다.
아틀란티스 서버에서도 plan을 수행한 내용이 나오고 status가 Locked로 변경됩니다.
이제 apply -d 를 수행해 봅니다.
Merge pull reuest를 confirm merge 합니다.
그렇게 되면 아틀란티스서버에서 apply가 수행된 상황을 확인할 수 있고 Locking 상태가 풀려있음을 관찰할 수 있습니다.
#
git checkout main
ls
git pull
ls
cat main.tf
작업 2 - aws iam user 생성
작업 2를 실습하면서 terraform Backend State 를 저장하기 위한 S3를 생성합니다.
# feature branch 생성
git branch iam && git checkout iam && git branch
# 디렉터리 생성
mkdir iam && cd iam
# main.tf 파일 작성
vi main.tf
----------
terraform {
backend "s3" {
bucket = "devlos-t101"
key = "terraform.tfstate"
region = "ap-northeast-2"
}
}
resource "aws_iam_user" "myuser" {
name = "t101user"
}
# add commit push
git add main.tf && git commit -m "add main.tf" && git push origin iam
atlantis plan -d iam 를 수행하면 iam프로젝트가 plan이 수행되고 Locking 되는 것을 확인할 수 있습니다.
destroy를 수행하면 명령어를 인식할 수 없다고 나옵니다.
apply를 수행합니다.
aws s3 확인해 보면 tfstate가 생성된 것을 확인할 수 있습니다.
Merge pull request → Confirm merge를 통해 변경사항을 동기화합니다.
실제 aws 콘솔에 들어가 보면 유저가 생성된 것을 확인할 수 있습니다.
작업 3 - 리소스 삭제
리소스를 삭제하는 작업입니다. 테라폼 코드에서 resource를 삭제한 후 이를 동기화시켜 리소스를 삭제하는 형태입니다.
# feature branch 생성
git branch deleteiam && git checkout deleteiam && git branch
# 디렉터리 생성
mkdir deleteiam && cd deleteiam
# main.tf 파일 작성
vi main.tf
----------
terraform {
backend "s3" {
bucket = "devlos-t101"
key = "terraform.tfstate"
region = "ap-northeast-2"
}
}
# IAM리소스 삭제
----------
# add commit push
git add main.tf && git commit -m "add main.tf" && git push origin deleteiam
해당 내용을 atlantis apply -d deleteiam 시키면 다음과 같이 iam 리소스가 삭제되는 것을 확인할 수 있습니다.
마치며
이번 주차에서는 테라폼 모듈과 runner에 대한 설명과 실습을 통해 테라폼 코드를 협업관점에서 관리하는 방법에 대해 학습했습니다. 실습 및 여러 가지 복합적인 설정들이 많아서 난이도가 꽤 있었던 것 같지만.. 무사히 잘 실습을 마치게 된 것 같습니다!
그럼 다음 주 스터디에서 뵙겠습니다!
감사합니다.
'클라우드 컴퓨팅 & NoSQL > [T101] 테라폼 4기 스터디' 카테고리의 다른 글
[7주차 - 테라폼으로 AWS EKS 배포 ] T101 4기 스터디 (24.07.21) (0) | 2024.07.26 |
---|---|
[6주차 - Well-Architected 방식으로 워크로드를 안전하게 마이그레이션 및 현대화하기 Workshop ] T101 4기 스터디 (24.07.14) (0) | 2024.07.17 |
[4주차 - Provider & State] T101 4기 스터디 (24.06.30) (0) | 2024.07.04 |
[3주차 - 기본사용#3] T101 4기 스터디 (24.06.23) (0) | 2024.06.29 |
[2주차 - 기본사용#2] T101 4기 스터디 (24.06.16) (0) | 2024.06.22 |