<aside> 🙇♀️ Kakaoenterprise 인턴 수행 중 진행했던 발표 자료입니다.
</aside>
<aside> ⚠️ Provider는 모듈 안에서 정의하는 게 아니라 모듈이 사용되는 곳에서 직접 정의를 해야할 부분이기 때문에 module의 main.tf에는 정의해주지 않는다.
</aside>
모듈 불러오기
module "webserver_cluster" {
source = "../../../modules/services/webserver-cluster"
}
모듈의 변경사항 동기화
plan과 apply 수행 전에 get
명령어 실행
일반적인 프로그래밍 언어에서 함수를 구성할 수 있게 하려면 해당 함수에 입력 매개변수를 추가해야 함.
테라폼에서 모듈은 입력 변수를 추가할 수 있음
3가지 입력변수 정의
variable "cluster_name" {
description = "The name to use for all the cluster resources"
}
variable "db_remote_state_bucket" {
description = "The name to use for S3 bucket for the database's remote state"
}
variable "db_remote_state_key" {
description = "The path for the database's remote state in S3"
}
ELB 보안그룹 작성에서 “cluster_name” 동적으로 설정하기
resource "aws_security_group" "elb" {
name = "${var.cluster_name}-elb"
# 포트 80번 트래픽을 확인한 후, 연동
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # 인터넷이 연결된 어느곳에서라도 접속
}
# 상태체크를 요청하기 위해 내보내는 트래픽 허용
egress {
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}
terraform_remote_state 데이터 소스 업데이트
db_remote_state_bucket 및 db_remote_state_key를 각각의 버킷 및 키 매개변수로 사용하도록
data "terraform_remote_state" "db" {
backend = "s3"
config = {
bucket = "${var.db_remote_state_bucket}"
key = "${var.db_remote_state_key}"
region = "us-east-1"
}
}
스테이징 환경 수정 (Stage)
module "webserver_cluster" {
source = "../../../modules/services/webserver-cluster"
cluster_name = "webserver-stage"
db_remote_state_bucket = "lena-tf-state-bucket"
db_remote_state_key = "stage/datastores/mysql/terraform/tfstate"
}
상용 환경 수정 (Prod)
module "webserver_cluster" {
source = "../../../modules/services/webserver-cluster"
cluster_name = "webserver-prod"
db_remote_state_bucket = "lena-tf-state-bucket"
db_remote_state_key = "prod/datastores/mysql/terraform.tfstate"
}
이처럼 입력 변수는 모듈의 API 이며, 다른 환경에서 어떻게 동작할지 제어한다.
세가지 입력 변수 추가
variable "instance_type" {
description = "The type of EC2 Instances to run (e.g. t2.micro)"
}
variable "min_size" {
description = "The minimum number of EC2 Instances in the ASG"
}
variable "max_size" {
description = "The maximum number of EC2 Instancees in the ASG"
}
module의 변수 수정
## EC2 인스턴스를 ASG에 설정하는 시작 구성 ##
resource "aws_launch_configuration" "example"{
image_id = "ami-40d28157"
**instance_type = "${var.instance_type}"**
security_groups = ["${aws_security_group.elb.id}"]
# EC2 인스턴스에 포트 번호를 설정하는 비지박스 부분
# - EC2 인스턴스의 사용자 데이터 설정을 통해 "Hello, World" 스크립트를 인스턴스 기동시 수행할 수 있게 된다.
user_data = <<-EOF
#!/bin/bash
echo "Hello, World" >> index.html
echo "${data.terraform_remote_state.db.outputs.address}" >> index.html
echo "${data.terraform_remote_state.db.outputs.port}" >> index.html
nohup busybox httpd -f -p "${var.server_port}" &
EOF
lifecycle {
create_before_destroy = true
}
}
## ASG 생성 ##
resource "aws_autoscaling_group" "example" {
launch_configuration = "${aws_launch_configuration.example.id}"
availability_zones = "${data.aws_availability_zones.all.names}"
load_balancers = ["${aws_elb.example.name}"] # 인스턴스가 시작할 때 ELB에 각 인스턴스를 등록하도록 ASG에 요청
health_check_type = "ELB"
**max_size = "${var.max_size}"
min_size = "${var.min_size}"**
tag {
key = "Name"
value = "${var.cluster_name}"
propagate_at_launch = true
}
}
스테이징 환경 수정
## 모듈 활용 ##
module "webserver_cluster" {
source = "../../../modules/services/webserver-cluster"
cluster_name = "webserver-stage"
db_remote_state_bucket = "lena-tf-state-bucket"
db_remote_state_key = "stage/datastores/mysql/terraform/tfstate"
**instance_type = "t2.micro"
min_size = 2
max_size = 2**
}
모듈 환경 수정
## 모듈 활용 ##
module "webserver_cluster" {
source = "../../../modules/services/webserver-cluster"
cluster_name = "webserver-stage"
db_remote_state_bucket = "lena-tf-state-bucket"
db_remote_state_key = "stage/datastores/mysql/terraform/tfstate"
**instance_type = "t2.micro"
min_size = 2
max_size = 10**
}
만약 업무 시간 중에 클러스터 사용량이 더 높은 경우 자동 조정 일정을 사용하여 오전 9시에 서버 수를 늘리고 오후 5시에 서버수를 줄이고 싶다 하자
→ auto scaling schedule 사용
aws_autoscaling_schedule
resource
resource "aws_autoscaling_schedule" "scale_out_during_business_hours" {
scheduled_action_name = "scale-out-during-business-hours"
min_size = 2
max_size = 10
desired_capacity = 10
recurrence = "0 9 * * *" # 매일 오전 9시
autoscaling_group_name = ""
}
resource "aws_autoscaling_schedule" "scale-in-at-night" {
scheduled_action_name = "scale-in-at-night"
min_size = 2
max_size = 10
desired_capacity = 2
recurrence = "0 17 * * *" # 매일 오후 5시
autoscaling_group_name = ""
}
output "asg_name" {
value = "${aws_autoscaling_group.example.name}"
}
"${module.MODULE_NAME.OUTPUT_NAME}"
"${module.webserver_cluster.asg_name}"
resource "aws_autoscaling_schedule" "scale_out_during_business_hours" {
scheduled_action_name = "scale-out-during-business-hours"
min_size = 2
max_size = 10
desired_capacity = 10
recurrence = "0 9 * * *" # 매일 오전 9시
**autoscaling_group_name = "${module.webserver_cluster.asg_name}"**
}
resource "aws_autoscaling_schedule" "scale-in-at-night" {
scheduled_action_name = "scale-in-at-night"
min_size = 2
max_size = 10
desired_capacity = 2
recurrence = "0 17 * * *" # 매일 오후 5시
**autoscaling_group_name = "${module.webserver_cluster.asg_name}"**
}
output "elb_dns_name" {
value = "${aws_elb.example.dns_name}"
}
stage에 출력 전달
output "elb_dns_name" {
value = "${module.webserver_cluster.elb_dns_name}"
}
일부 테라폼 리소스 구성은 인라인 블록 또는 별도의 리소스로 정의
모듈을 작성할 떄는 인라인 블록 대신 별도의 리소스로 작성
⚠️ 인라인 블록으로 작성한 트래픽 규칙은 작동되지 않는다.
수정 전, elb의 보안 그룹
resource "aws_security_group" "elb" {
name = "${var.cluster_name}-elb"
# 포트 80번 트래픽을 확인한 후, 연동
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # 인터넷이 연결된 어느곳에서라도 접속
}
# 상태체크를 요청하기 위해 내보내는 트래픽 허용
egress {
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}
다음과 같이 모듈 변경 가능
resource "aws_security_group" "elb" {
name = "${var.cluster_name}-elb"
}
resource "**aws_security_group_rule**" "allow_http_inbound" {
type = "ingress"
security_group_id = "${aws_security_group.elb.id}"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
resource "**aws_security_group_rule**" "allow_all_outbound" {
type = "egress"
security_group_id = "${aws_security_group.elb.id}"
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
별도의 리소스 (aws_security_group_rule)을 사용한 경우,
stage 환경에서 검증을 위해 추가 포트를 열어야 할 경우
필요한 출력 변수를 만들고
output "elb_security_group_id" {
value = "${aws_security_group.elb.id}"
}
aws_security_group_rule
리소스를 추가만 하면 됨
resource "aws_security_group_rule" "allow_testing_inbound" {
type = "ingress"
security_group_id = "${module.webserver_cluster.elb_security_group_id}"
from_port = 12345
protocol = "tcp"
to_port = 12345
cidr_blocks = ["0.0.0.0/0"]
}
포트 추가 확인
<aside>
📌 aws_security_group
/ aws_security_group_rule
aws_route_table
/ aws_route
aws_network_acl
/ aws_network_acl_rule
aws_elb
/ aws_elb_attachment
</aside>
이전 폴더 구조
**tf-aws-provider**
ㄴ 📁 global
ㄴ 📁 s3 # Remote State Storage(s3 bucket)
ㄴ 📄 main.tf
ㄴ 📄 output.tf
ㄴ 📁 stage
ㄴ 📁 datastores
ㄴ 📁 mysql # Database
ㄴ 📄 main.tf
ㄴ 📄 var.tf
ㄴ 📄 output.tf
ㄴ 📁 services
ㄴ 📁 webserver-cluster # ASG(EC2 instances) + ELB
ㄴ 📄 main.tf
ㄴ 📄 var.tf
ㄴ 📄 data.tf
ㄴ 📄 output.tf
모듈 생성
**tf-aws-provider
ㄴ 📁 modules
ㄴ 📁 services
ㄴ 📁 webserver-cluster
ㄴ 📄 var.tf
ㄴ 📄 data.tf
ㄴ 📄 output.tf
ㄴ 📄 main.tf**
ㄴ 📁 global
ㄴ 📁 s3 # Remote State Storage(s3 bucket)
ㄴ 📄 main.tf
ㄴ 📄 output.tf
ㄴ 📁 stage
ㄴ 📁 datastores
ㄴ 📁 mysql # Database
ㄴ 📄 main.tf
ㄴ 📄 var.tf
ㄴ 📄 output.tf
ㄴ 📁 services
ㄴ 📁 webserver-cluster # ASG(EC2 instances) + ELB
ㄴ 📄 main.tf
ㄴ 📄 var.tf
ㄴ 📄 data.tf
ㄴ 📄 output.tf
**ㄴ 📁 prod
ㄴ 📁 datastores
ㄴ 📁 mysql # Database
ㄴ 📄 main.tf
ㄴ 📄 var.tf
ㄴ 📄 output.tf
ㄴ 📁 services
ㄴ 📁 webserver-cluster # ASG(EC2 instances) + ELB
ㄴ 📄 main.tf
ㄴ 📄 var.tf
ㄴ 📄 data.tf
ㄴ 📄 output.tf**
→ global 에 있는 s3 버킷 생성 부분을 terraform apply 하지 않았었음
→ database도 apply 하고 했는데도 실제 stage에서 module을 사용할 때 어떠한 저장된 state도 없다고 뜸
→ modules의 변경사항을 get 해오는 부분을 stage working dir 에서 했었는데 아닌가 싶어서 module을 작성해둔 modules / services / webserver-cluster dir 에서 get → plan → apply
똑같음..
그냥 간단 예제로 한번 해보자 (보안그룹, 인스턴스)