Terraform 코드를 사용하여 다수의 리눅스 VM 생성 및 LB 연동
- 리소스 그룹 - azuredev-rg (생성되어 있는 그룹 사용)
- VNET 이름 - azuredev-vnet (신규 생성)
- SUBNET 이름 - azuredev-subnet (신규 생성)
- 공인 IP - azuredev1-pip (신규 생성)
- VM 이름 - azuredev1 (신규 생성)
- SSH 접근은 사용자 계정 azuser로 패스워드 인증 사용
- LB 이름 - azuredev-lb (신규 생성)
- LB 공인 IP - azuredev-lb-pip (신규 생성)
추가적으로 SSH 및 80 포트 접속을 위한 NSG 구성 및 포트 설정이 필요(NSG 이름 - azuredev-nsg) -> 수동 구성
디렉토리 구조
각 파일의 내용
- 메인 구성 - main.tf
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "4.4.0"
}
}
}
variable "subscription_id" {}
variable "client_id" {}
variable "client_secret" {}
variable "tenant_id" {}
provider "azurerm" {
# Configuration options
features {}
subscription_id = var.subscription_id
client_id = var.client_id
client_secret = var.client_secret
tenant_id = var.tenant_id
}
# 리소스 그룹 신규 구성 시
# resource "azurerm_resource_group" "rg" {
# location = var.location
# name = "azuredev-rg"
# }
# 기존 리소스 그룹 사용 시
data "azurerm_resource_group" "rg" {
name = "azuredev-rg"
}
module "networking" {
source = "./modules/networking"
resource_group_name = data.azurerm_resource_group.rg.name
location = data.azurerm_resource_group.rg.location
vnet_name = "azuredev-vnet"
subnet_name = "azuredev-subnet"
}
module "loadbalancer" {
source = "./modules/loadbalancer"
resource_group_name = data.azurerm_resource_group.rg.name
location = data.azurerm_resource_group.rg.location
lb_name = "azuredev-lb"
subnet_id = module.networking.subnet_id
}
module "vm" {
count = 3
source = "./modules/vm"
resource_group_name = data.azurerm_resource_group.rg.name
location = data.azurerm_resource_group.rg.location
subnet_id = module.networking.subnet_id
vm_name = "azuredev-${count.index + 1}"
admin_username = "azuser"
admin_password = var.admin_password
lb_backend_pool_id = module.loadbalancer.backend_pool_id
}
- 변수 - variables.tf
variable "admin_password" {
description = "Password for the admin user"
type = string
}
- 출력 - outputs.tf
output "vm_public_ips" {
value = module.vm[*].public_ip_address
}
output "lb_public_ip" {
value = module.loadbalancer.public_ip_address
}
- 네트워킹 모듈 - modules/networking/main.tf
resource "azurerm_virtual_network" "vnet" {
name = var.vnet_name
address_space = ["10.0.0.0/16"]
location = var.location
resource_group_name = var.resource_group_name
}
resource "azurerm_subnet" "subnet" {
name = var.subnet_name
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.101.0/24"]
}
- 네트워킹 모듈 변수 - modules/networking/variables.tf
variable "resource_group_name" {
description = "Name of the resource group"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "vnet_name" {
description = "Name of the virtual network"
type = string
}
variable "subnet_name" {
description = "Name of the subnet"
type = string
}
- 네트워킹 모듈 출력 - modules/networking/outputs.tf
output "subnet_id" {
value = azurerm_subnet.subnet.id
}
- 로드밸런스 모듈 - modules/loadbalancer/main.tf
resource "azurerm_public_ip" "lb_public_ip" {
name = "${var.lb_name}-pip"
location = var.location
resource_group_name = var.resource_group_name
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_lb" "lb" {
name = var.lb_name
location = var.location
resource_group_name = var.resource_group_name
sku = "Standard"
frontend_ip_configuration {
name = "PublicIPAddress"
public_ip_address_id = azurerm_public_ip.lb_public_ip.id
}
}
resource "azurerm_lb_backend_address_pool" "backend_pool" {
loadbalancer_id = azurerm_lb.lb.id
name = "BackEndAddressPool"
}
resource "azurerm_lb_probe" "probe" {
loadbalancer_id = azurerm_lb.lb.id
name = "http-probe"
port = 80
}
resource "azurerm_lb_rule" "rule" {
loadbalancer_id = azurerm_lb.lb.id
name = "http"
protocol = "Tcp"
frontend_port = 80
backend_port = 80
frontend_ip_configuration_name = "PublicIPAddress"
backend_address_pool_ids = [azurerm_lb_backend_address_pool.backend_pool.id]
probe_id = azurerm_lb_probe.probe.id
}
- 로드밸런스 모듈 변수 - modules/loadbalancer/variables.tf
variable "resource_group_name" {
description = "Name of the resource group"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "lb_name" {
description = "Name of the load balancer"
type = string
}
variable "subnet_id" {
description = "ID of the subnet"
type = string
}
- 로드밸런스 모듈 출력 - modules/loadbalancer/outputs.tf
output "backend_pool_id" {
value = azurerm_lb_backend_address_pool.backend_pool.id
}
output "public_ip_address" {
value = azurerm_public_ip.lb_public_ip.ip_address
}
- VM 모듈 - modules/vm/main.tf
resource "azurerm_public_ip" "vm_public_ip" {
name = "${var.vm_name}-pip"
location = var.location
resource_group_name = var.resource_group_name
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_network_interface" "nic" {
name = "${var.vm_name}-nic"
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "internal"
subnet_id = var.subnet_id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.vm_public_ip.id
}
}
resource "azurerm_linux_virtual_machine" "vm" {
name = var.vm_name
resource_group_name = var.resource_group_name
location = var.location
size = "Standard_B1s"
admin_username = var.admin_username
admin_password = var.admin_password
disable_password_authentication = false
network_interface_ids = [
azurerm_network_interface.nic.id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "ubuntu-24_04-lts"
sku = "server"
version = "latest"
}
}
resource "azurerm_network_interface_backend_address_pool_association" "example" {
network_interface_id = azurerm_network_interface.nic.id
ip_configuration_name = "internal"
backend_address_pool_id = var.lb_backend_pool_id
}
- VM 모듈 변수 - modules/vm/variables.tf
variable "resource_group_name" {
description = "Name of the resource group"
type = string
}
variable "location" {
description = "Azure region"
type = string
}
variable "subnet_id" {
description = "ID of the subnet"
type = string
}
variable "vm_name" {
description = "Name of the virtual machine"
type = string
}
variable "admin_username" {
description = "Admin username"
type = string
}
variable "admin_password" {
description = "Admin password"
type = string
}
variable "lb_backend_pool_id" {
description = "ID of the load balancer backend pool"
type = string
}
- VM 모듈 출력 - modules/vm/outputs.tf
output "public_ip_address" {
value = azurerm_public_ip.vm_public_ip.ip_address
}
VM 리소스 생성
1. 초기화
terraform init
2. 계획 확인
- plan 실행 시 azuser 계정이 사용할 패스워드(Password123!)를 함께 등록
terraform plan -var="admin_password=Password123!"
3. 리소스 생성
- apply 실행 시 azuser 계정이 사용할 패스워드 (Password123!)를 함께 등록
terraform apply -var="admin_password=Password123!"
VM 리소스 확인
VM 접속 확인
접속 테스트
1. apache2 설치
2. 외부 접근을 위한 NSG 설정
- 100번 - SSH 접근을 위한 포트 오픈
- 110번 - 웹 페이지 접근을 위한 포트 오픈 (LB 공인 IP)
- 120번 - 개별 VM HTTP 포트 오픈 (VM 사설 IP)
- "외부 -> LB -> VM" 통신의 경우 LB IP 뿐만 아니라 VM IP도 오픈이 필요함
3. LB 접속 테스트
"외부 -> LB -> VM" 통신의 경우 LB IP 뿐만 아니라 VM IP도 오픈이 필요한 이유