この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
2장에서 코드를 직접 써보고 3장에서 모듈 등 다른 기능에 대해서 알아보았습니다.
그런데 작성한 코드를 보면 중복된 내용이 들어가는 부분이 상당히 많습니다.
## public Seucurity Group
resource "aws_security_group" "publicSG01" {
name = "public-SG-01"
description = "Allow all HTTP"
vpc_id = aws_vpc.test.id
ingress {
cidr_blocks = [ "0.0.0.0/0" ]
from_port = 80
protocol = "tcp"
to_port = 80
}
egress {
cidr_blocks = [ "0.0.0.0/0" ]
from_port = 0
protocol = "-1"
to_port = 0
}
}
## private Security Group
resource "aws_security_group" "privateEC2SG01" {
---
}
resource "aws_security_group" "privateRDSSG01" {
---
}
(변수 값만 조금씩 다른 리소스의 코드 블록이 많다..)
이렇게 코드를 작성하면 문제가 발견해도 찾지 못한다거나 코드가 길어져서 바로 이해하기 힘들어지는 등 관리하기가 힘들어집니다.
이전 글에서 알게 된 모듈이나 워크스페이스 등을 사용하여 이러한 문제를 해결해보도록 하겠습니다.
환경
전체적인 구성 자체는 저번 구성에서 Nat Gateway만을 추가하였습니다.
단 환경에 따라 변수를 다르게 조정하여 각 리소스의 스펙은 다르게 설정하겠습니다.
코드 작성
흐름
다음과 같은 흐름으로 작업을 진행합니다.
- 환경 나누기(dev/prd)
- 모듈, 환경 코드 작동 확인
- 모듈 및 환경 코드 작성
- 리소스 생성 확인 후 삭제
- prd 환경 코드 작성
환경 나누기
환경을 나누기 위해서는 크게 2가지 방법이 있습니다.
첫 번째는 환경 별로 다른 디렉터리를 만들고 파일을 관리하는 방법입니다.
- env
- dev
- main.tf
- outputs.tf
- variables.tf
- terraform.tfvars
- prd
- main.tf
- outputs.tf
- variables.tf
- terraform.tfvars
- modules
- iam
- main.tf
- variables.tf
- outputs.tf
- ec2
- main.tf
- variables.tf
- outputs.tf
- ...
이렇게 관리하면 두 환경이 섞일 일이 없이 확실히 구분이 가능합니다. 또한 모듈만 완성 되면 다른 환경에서는 변수만 바꾸면 됩니다.
하지만 파일 수가 너무 많이 늘어나는 등 단점도 존재합니다.
이번 글에서는 prd 와 dev 라는 2개의 직접 환경 폴더를 나누어 관리하도록 하겠습니다.
다른 방법으로는 테라폼에서 제공하고 있는 워크스페이스기능을 이용하는 것 입니다. 워크스페이스를 이용하면 같은 코드라도 환경을 나누어 사용할 수 있습니다.
resource "foo" "bar" {
name = "${terraform.workspace == "prd" ? "prd-resource" : "dev-resource"}"
}
이와 같이 workspace 라는 파라미터로 적용할 값을 설정할 수 있습니다.
모듈, 환경 코드 작동 확인
서두에서 언급한대로 이전에 작성했던 코드를 보면 하나의 tf 파일에 모든 내용이 작성되어 있습니다.
이렇게 하나의 파일에 서비스에 관한 모든 리소스를 작성하면 코드가 너무 길어져 관리가 어렵게 됩니다. 또한 재사용도 할 수 없게 됩니다.
모듈화를 하면 이러한 문제점을 해결할 수 있습니다.
이전의 코드는 깃허브를 참고해주세요.
우선 디렉터리를 다음과 같이 환경(env)과 모듈(modules)로 나눕니다.
- env
- dev
- prd
- modules
- network
- ec2
- ...
modules 아래에는 모듈화 할 서비스(EC2, RDS 등)나 기능(network 등) 단위로 디렉터리를 나눕니다. env 아래에는 사용할 환경 별로 디렉터리를 생성합니다.
그리고 아래와 같이 각 디렉터리 아래에 main.tf, variables.tf, outputs.tf, terraform.tfvars(환경 디렉터리만)
을 생성합니다.
- env
- dev
- main.tf
- outputs.tf
- variables.tf
- terraform.tfvars
- prd
- ...
- modules
- network
- main.tf
- variables.tf
- outputs.tf
- ec2
- ...
- ...
우선 잘 작동하는지 테스트하기 위해 간단하게 VPC를 작성하고 테스트 해보겠습니다.
모듈의 main.tf
에는 해당 모듈로 작성할 리소스(전체적인 틀)을 작성합니다.
# modules/network의 main.tf
# VPC
resource "aws_vpc" "vpc" {
cidr_block = var.vpc_cidr
tags = {
"name" = "${var.env}-vpc"
}
}
# Subnets
resource "aws_subnet" "subnet" {
vpc_id = aws_vpc.vpc.id
cidr_block = var.subnet_cidr
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
"name" = "${var.env}-vpc"
}
}
data "aws_availability_zones" "available" {
state = "available"
}
그리고 variables.tf
에는 main.tf
에서 이용하는 변수를 입력합니다.
이 때 모듈의 main.tf
에서 이용하는 변수는 해당 모듈 디렉터리의 variables.tf
와 환경 디렉터리의 variables.tf
양쪽에 정의되어 있어야합니다.
모듈 디렉터리의 variables.tf
는 빈 값으로 설정해도 괜찮습니다.
# modules/network/variables.tf
variable "vpc_cidr" {}
variable "env" {}
variable "subnet_cidr" {}
# env/dev/variables.tf
variable "env" {
description = "env name"
default = ""
}
variable "vpc_cidr" {
description = "vpc cidr"
}
variable "subnet_cidr" {
description = "subnets cidr"
}
여기까지 작성이 완료되었다면 dev
디렉터리 아래의 main.tf
을 다음과 같이 작성합니다.
위에서 모듈화 한 내용들을 main.tf
에서 불러와서 필요한 값만 지정해줍니다.
# env/dev/main.tf
terraform {
required_version = "~> 1.0.9"
required_providers {
aws = "~> 4.0"
}
}
provider "aws" {
region = "ap-northeast-1"
}
module "network" {
source = "../../modules/network"
vpc_cidr = var.vpc_cidr
subnet_cidr = var.subnet_cidr
env = var.env
}
변수의 실제 값은 terraform.tfvars
에 정의합니다.
# env/dev/terraform.tfvars
env = "dev"
vpc_cidr = "202.2.0.0/16"
subnet_cidr = "202.2.0.0/24"
여기까지 작성이 완료되었으면 dev
디렉터리에서 terraform init
으로 참조된 모듈을 정의한 후 terraform plan
으로 제대로 작동되는지 확인해봅시다.
모듈 및 환경 코드 작성
이후로 나머지 리소스(EC2, SecurityGroup, RDS ...)을 똑같이 모듈화 한 뒤 환경의 main.tf
에서 해당 모듈을 불러오고 설정하는 작업의 반복입니다.
기존의 코드를 어떤식으로 나누면 되는지 network 모듈을 예로 들어 설명하겠습니다.
network
모듈에는 VPC, Subnet, VPC Endpoint 등 네트워크와 관련된 리소스를 정의합니다.
이전의 코드를 확인해보면 서브넷이나 라우팅 테이블 연결 등 반복되는 부분이 많습니다.
# Subnets
## public subnet
resource "aws_subnet" "publicSubnet1" {
...
}
...
resource "aws_subnet" "privateSubnet2" {
...
}
### subnet associate
resource "aws_route_table_association" "publicRTbAssociation01" {
...
}
...
resource "aws_route_table_association" "privateRTbAssociation04" {
...
}
이렇게 반복되는 count
를 이용하여 간단하게 정의할 수 있습니다.
# modules/network/main.tf
# 서브넷 생성의 반복
resource "aws_subnet" "public_subnet" {
count = var.sub_count
vpc_id = aws_vpc.vpc.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
"Name" = "${var.env}-public-subnet-${count.index + 1}"
}
}
# 라우팅 테이블 연결의 반복
resource "aws_route_table_association" "public_rtb_association" {
count = var.sub_count
subnet_id = aws_subnet.public_subnet[count.index].id
route_table_id = aws_route_table.public_rtb.id
}
코드에 사용되는 sub_count
라는 변수는 위에서 설명한대로 variables.tf
에 정의할 필요가 있습니다.
이렇게 생성되는 리소스의 실제 스펙을 모듈에 정의해두면 환경 디렉터리의 main.tf
에서는 몇 개의 변수만 입력하면 몇 번이고 해당 모듈을 재사용 할 수 있습니다.
# env/dev/main.tf
module "network" {
source = "../../modules/network"
vpc_cidr = var.vpc_cidr
sub_count = var.resource_count
env = var.env
}
모듈을 정의한 후 terraform init
명령어로 설정 파일에 모듈을 등록합니다.
이 후 terraform plan -> terraform apply
로 리소스의 생성을 확인합니다.
이렇게 이전에 작성한 코드에서 반복의 정리 및 코드의 재사용 가능성을 고려하여 코드를 작성해나갑니다.
작성한 코드는 깃허브를 참고해주세요.
리소스 생성 확인 후 삭제
모든 코드를 작성한 후 terraform apply
를 실행하여 리소스가 전부 잘 생성되는지 확인하고 문제없이 생성되었다면 필요없는 비용이 발생하지 않도록 terraform destory
로 리소스를 삭제해줍니다.
prd 환경 코드 작성
dev 환경에서 모든 작업이 완료되었다면 env아래에 prd 디렉터리를 생성하여 dev 환경의 내용을 그대로 복사합니다. 그리고 terraform.tfvars
의 변수 값만 수정하면 간단하게 prd 환경의 리소스를 생성할 수 있습니다.
이렇게 간단하게 새로운 환경의 리소스를 작성할 수 있는게 모듈화의 장점입니다.
마치며
이번 글에서는 IAM 등의 리소스 작성은 하지 않았습니다. 필요에 따라 모듈을 생성해주세요.
모듈화를 잘 사용하면 재사용성을 높여 효율적인 리소스 관리가 가능해집니다.
저도 아직 많이 실력이 부족하여 코드가 아주 효율적이지는 못합니다. 모두 같이 노력하여 테라폼 마스터가 되도록 합시다!
긴 글 읽어주셔서 감사합니다.
오탈자 및 내용 피드백은 언제나 환영합니다. must01940 지메일로 연락 주시면 감사합니다!
본 블로그 게시글을 보시고 문의 사항이 있으신 분들은
클래스메소드코리아 (info@classmethod.kr)로 연락 주시면 빠른 시일 내 담당자가 회신 드릴 수 있도록 하겠습니다 !