terraform을 이용하여 linode VM 이중화 구성 및 트래픽 분산 실습.
apache, nginx 서버를 각각 1대 생성하고 L4 switch를 이용하여 부하를 분산시키게 구성한다.

docker 설치, nginx, apache 컨테이너 생성 bash 스크립트를 작성하고, 이를 VM 생성 시 자동으로 실행할 수 있게 StackScript 리소스를 생성한다.
bash script
#!/bin/bash
#install docker
apt-get update -y
apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get install docker-ce docker-ce-cli containerd.io -y
#run nginx container
docker run --rm -d -p 3000:80 --name=nginx nginx
#!/bin/bash
#install docker
apt-get update -y
apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get install docker-ce docker-ce-cli containerd.io -y
#run apache container
docker run --rm -d -p 3000:80 --name=apache httpd
Stack Script
resource "linode_stackscript" "install_docker_nginx" {
label = "docker-nginx-ss"
description = "install docker and run nginx"
script = file("./files/install-docker-nginx.sh")
images = ["linode/ubuntu22.04"]
}
resource "linode_stackscript" "install_docker_apache" {
label = "docker-apache-ss"
description = "install docker and run apache"
script = file("./files/install-docker-apache.sh")
images = ["linode/ubuntu22.04"]
}
nginx, apache 컨테이너를 실행할 가상머신을 정의한다.
linode node balancer는 가상머신에 트래픽을 분산할 때 private ip를 대상으로 트래픽을 분산한다. 따라서 private_ip = true 속성을 사용하여 가상머신에 private ip를 할당한다.
private ip는 192.168.128.0/17 대역 안에서 동적으로 할당된다.
위에서 작성한 stack script id를 추가하여 가상머신 생성 시 정의한 stack script가 실행되도록 한다.
resource "linode_instance" "nginx" {
label = "nginx"
image = "linode/ubuntu22.04"
region = "jp-osa"
type = "g6-standard-1"
root_pass = var.instance_password
private_ip = true
stackscript_id = linode_stackscript.install_docker_nginx.id
}
resource "linode_instance" "apache" {
label = "apache"
image = "linode/ubuntu22.04"
region = "jp-osa"
type = "g6-standard-1"
root_pass = var.instance_password
private_ip = true
stackscript_id = linode_stackscript.install_docker_apache.id
}
로컬 PC에서 VM 인스턴스에 접속할 수 있게 22번 포트를 개방해주고, node balancer에서 오는 3000번 포트로의 트래픽을 허용한다.
linode node balancer는 자신의 private ip가 동적으로 바뀐다. 따라서 특정 ip만을 firewall에 허용해서 트래픽을 허용할 수 없다.
따라서 node balancer private ip 범위인 192.168.255.0/24 대역을 열어준다.
resource "linode_firewall" "backend_backend_firewall" {
label = "backend-fw"
inbound {
label = "allow-ssh"
action = "ACCEPT"
protocol = "TCP"
ports = "22"
ipv4 = ["0.0.0.0/0"]
ipv6. = ["::/0"]
}
inbound {
label = "allow-nb-traffic"
action = "ACCEPT"
protocol = "TCP"
ports = "3000"
ipv4 = ["192.168.255.0/24"]
}
inbound_policy = "DROP"
outbound_policy = "ACCEPT"
linodes = [linode_instance.nginx.id, linode_instance.apache.id]
}
node balancer는 80번 포트에서 오는 트래픽을 허용한다.
resource "linode_firewall" "nb_fw" {
label = "nb-fw"
inbound {
label = "allow-http"
action = "ACCEPT"
protocol = "TCP"
ports = "80"
ipv4 = ["0.0.0.0/0"]
ipv6 = ["::/0"]
}
inbound_policy = "DROP"
outbound_policy = "ACCEPT"
nodebalancers = [linode_nodebalancer.backend_nb.id]
}
80번 포트를 리스닝 하고 있도록 구성하고, 들어온 트래픽을 round robin 방식으로 2개의 서버에 분산시킨다.
resource "linode_nodebalancer" "backend_nb" {
label = "backend-nb"
region = "jp-osa"
}
resource "linode_nodebalancer_config" "backend_nb_config" {
nodebalancer_id = linode_nodebalancer.backend_nb.id
port = 80
protocol = "http"
check = "none"
stickiness = "none"
algorithm = "roundrobin"
}
vm 구성이 바뀌었을 때 terraform 반영이 실패하는 이슈가 linode provider 자체적으로 있어 lifecycle.replace_triggered_by meta-argument를 사용하여 강제로 재생성 하도록 구성한다.
resource "linode_nodebalancer_node" "nginx_nb_node" {
nodebalancer_id = linode_nodebalancer.backend_nb.id
config_id = linode_nodebalancer_config.backend_nb_config.id
address = "${linode_instance.nginx.private_ip_address}:3000"
label = "nginx-node"
lifecycle {
// Tell Terraform to implicitly recreate the NodeBalancer node when
// the target instance has been marked for recreation.
// See: https://github.com/linode/terraform-provider-linode/issues/1224
replace_triggered_by = [linode_instance.nginx.id]
}
}
resource "linode_nodebalancer_node" "apache_nb_node" {
nodebalancer_id = linode_nodebalancer.backend_nb.id
config_id = linode_nodebalancer_config.backend_nb_config.id
address = "${linode_instance.apache.private_ip_address}:3000"
label = "apache-node"
lifecycle {
// Tell Terraform to implicitly recreate the NodeBalancer node when
// the target instance has been marked for recreation.
// See: https://github.com/linode/terraform-provider-linode/issues/1224
replace_triggered_by = [linode_instance.apache.id]
}
}

새로고침을 누를 때마다 nginx, apache 서버 메인 화면이 번갈아 나오며 정상적으로 트래픽이 분산되는 것을 확인할 수 있다.
https://github.com/linode/terraform-provider-linode/issues/1224
https://github.com/junho100/terraform-linode-load-balancing
https://www.linode.com/docs/products/networking/nodebalancers/guides/backends/