Terraform으로 Azure 필수 리소스 배포 테스트를 진행
참고 문헌 : https://learn.microsoft.com/ko-kr/azure/developer/terraform/create-resource-group?tabs=azure-cli
빠른 시작: Terraform을 사용하여 Azure 리소스 그룹 만들기
이 문서에서는 Terraform을 사용하여 Azure 리소스 그룹을 만드는 방법을 알아봅니다.
learn.microsoft.com
배포 계획
구조: Hub-Spoke 네트워크 모델
- Hub: 공통 인프라 구성 (VPN Gateway, Firewall 등)
- Spoke: 업무별 구분된 네트워크 (Web, WAS, DB 등 리소스 배치)
보안 구성
- NSG (Network Security Group): 각 Spoke VNet 및 서브넷에 할당
- VPN Gateway: Hub VNet에 배치
- Firewall: Hub VNet에 배치 및 UDR과 연동
리소스 그룹 구조
- RG-NETWORK – 가상 네트워크 및 서브넷 등 네트워크 리소스
- RG-SECURITY – NSG, Firewall, VPN 등 보안 리소스
- RG-COMPUTE – 가상 머신 등 컴퓨트 리소스
- RG-STORAGE – Storage Account 등 저장소 리소스
Tag 구성
- Key : Value 예시
- ResourceName : vm-web-prd-01 등
- ServiceType : WEB, WAS, DB 등
- Environment : PRD, QA, DEV
- DeploymentDate : 2025-05-07 등
배포 테스트
1. Azure Cloud Shell > 현재 구독 확인
az account set --subscription "<subscription_id_or_subscription_name>"
# 변경 후 확인
az account show
2. Terraform 디렉토리 생성
mkdir terraform-test
cd terraform-test
3. Terraform 디렉토리 기본 구성
terraform/
│
├── provider.tf # Azure Provider 정의
├── variables.tf # 공통 변수 정의
├── outputs.tf # 필요한 출력 정의 (옵션)
│
├── network.tf # Hub-Spoke VNet, Subnet
├── security.tf # NSG, Firewall, VPN Gateway
├── compute.tf # VM 정의
├── database.tf # Azure Database for MySQL
├── tags.tf # 태그 관련 공통 모듈 (선택)
4. versions.tf
Terraform 및 Azure Provider 버전 고정
- vi 편집기로 tf 파일 생성
vi versions.tf
# 아래는 vi 편집기 입력 내용
terraform {
required_version = ">= 1.6.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
5. provider.tf
Azure 인증 및 초기화 설정
provider "azurerm" {
features {}
}
6. variables.tf
리소스 배포 시 유연성과 재사용성을 위해 다양한 입력값(예: 리전, 태그, 리소스명, VM 구성 정보 등)을 변수로 선언
# 리전
variable "location" {
description = "Azure region to deploy all resources"
type = string
default = "koreacentral"
}
# 리소스 그룹 이름 정의
variable "resource_groups" {
description = "Resource group names by purpose"
type = object({
network = string
security = string
compute = string
storage = string
})
default = {
network = "LJY-RG-NETWORK"
security = "LJY-RG-SECURITY"
compute = "LJY-RG-COMPUTE"
storage = "LJY-RG-STORAGE"
}
}
# VM 정의
# VM을 효율적으로 배포하려면 각 VM의 정보를 구조화된 variable로 관리하는 것이 좋음
# Web VM
variable "vms" {
description = "List of web virtual machines to deploy"
type = list(object({
name = string
environment = string
resource_name = string
deployment_date = string
tags = map(string)
size = string
admin_username = string
admin_password = string
}))
default = [
{
name = "prd-web-01"
environment = "PRD"
resource_name = "prd-web-01"
deployment_date = "2025-05-07"
size = "Standard_B2s"
admin_username = "azureuser"
admin_password = "P@ssw0rdWebPrd"
tags = {
ResourceName = "prd-web-01"
ServiceType = "WEB"
Environment = "PRD"
DeploymentDate = "2025-05-07"
}
},
{
name = "dev-web-01"
environment = "DEV"
resource_name = "dev-web-01"
deployment_date = "2025-05-07"
size = "Standard_B2s"
admin_username = "azureuser"
admin_password = "P@ssw0rdWebDev"
tags = {
ResourceName = "dev-web-01"
ServiceType = "WEB"
Environment = "DEV"
DeploymentDate = "2025-05-07"
}
}
]
}
# MySQL 정의
variable "mysql_servers" {
description = "Azure Database for MySQL Flexible Server instances"
type = list(object({
name = string
environment = string
resource_name = string
deployment_date = string
sku_name = string
version = string
admin_username = string
admin_password = string
storage_mb = number
tags = map(string)
}))
default = [
{
name = "prd-db-01"
environment = "PRD"
resource_name = "prd-db-01"
deployment_date = "2025-05-07"
sku_name = "Standard_D2ds_v4"
version = "8.0"
admin_username = "mysqladmin"
admin_password = "P@ssw0rdDbPrd"
storage_mb = 51200
tags = {
ResourceName = "prd-db-01"
ServiceType = "DB"
Environment = "PRD"
DeploymentDate = "2025-05-07"
}
},
{
name = "dev-db-01"
environment = "DEV"
resource_name = "dev-db-01"
deployment_date = "2025-05-07"
sku_name = "Standard_D2ds_v4"
version = "8.0"
admin_username = "mysqladmin"
admin_password = "P@ssw0rdDbDev"
storage_mb = 51200
tags = {
ResourceName = "dev-db-01"
ServiceType = "DB"
Environment = "DEV"
DeploymentDate = "2025-05-07"
}
}
]
}
7. outputs.tf (옵션)
Terraform이 리소스를 배포한 후 사용자에게 필요한 중요한 정보를 출력해주는 역할
예 ) VM IP, MySQL 접속 정보, 리소스 그룹 이름 등
해당 테스트에서는 생략
8. network.tf (Hub-Spoke 구성)
** subnet에는 tags 지원하지 않음
유형 | VNet 이름 | Subnet | 범위 |
Hub | vnet-hub 10.0.0.0/16 |
(VPN)Gateway Subnet Firewall Subnet |
10.0.1.0/27 10.0.2.0/26 |
PRD | vnet-prd 10.1.0.0/16 |
snet-prd-web snet-prd-db |
10.1.1.0/24 10.1.2.0/24 |
DEV | vnet-dev 10.2.0.0/16 |
snet-dev-web snet-dev-db |
10.2.1.0/24 10.2.2.0/24 |
#########################
# Resource Group for Storage
#########################
# storage account 배포안할거라 미리 RG만 여기서 함께 생성
resource "azurerm_resource_group" "storage_rg" {
name = var.resource_groups.storage
location = var.location
}
#########################
# Resource Group for Security
#########################
resource "azurerm_resource_group" "security_rg" {
name = var.resource_groups.security # variables에서 정의한 RG 이름 사용
location = var.location # variables에서 정의한 리전 사용
}
# Hub VNet
# Firewall과 subnet의 RG 위치가 같아야함
resource "azurerm_virtual_network" "hub_vnet" {
name = "vnet-hub"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.security_rg.location # security_rg로 변경
resource_group_name = azurerm_resource_group.security_rg.name # security_rg로 변경
tags = {
ResourceName = "hub-vnet"
DeploymentDate = "2025-05-07"
}
}
# Gateway Subnet (Required for VPN Gateway)
resource "azurerm_subnet" "hub_gateway_subnet" {
name = "GatewaySubnet"
resource_group_name = azurerm_resource_group.security_rg.name # security_rg로 변경
virtual_network_name = azurerm_virtual_network.hub_vnet.name
address_prefixes = ["10.0.1.0/27"]
}
# Firewall Subnet (Required for Azure Firewall)
resource "azurerm_subnet" "hub_firewall_subnet" {
name = "AzureFirewallSubnet"
resource_group_name = azurerm_resource_group.security_rg.name # security_rg로 변경
virtual_network_name = azurerm_virtual_network.hub_vnet.name
address_prefixes = ["10.0.2.0/26"]
}
#########################
# Resource Group for Network
#########################
resource "azurerm_resource_group" "network_rg" {
name = var.resource_groups.network # variables에서 정의한 RG 이름 사용
location = var.location # variables에서 정의한 리전 사용
}
# PRD VNet
resource "azurerm_virtual_network" "prd_vnet" {
name = "vnet-prd"
address_space = ["10.1.0.0/16"]
location = azurerm_resource_group.network_rg.location
resource_group_name = azurerm_resource_group.network_rg.name
tags = {
ResourceName = "vnet-prd"
DeploymentDate = "2025-05-07"
}
}
resource "azurerm_subnet" "prd_subnet_web" {
name = "prd-web-subnet"
resource_group_name = azurerm_resource_group.network_rg.name
virtual_network_name = azurerm_virtual_network.prd_vnet.name
address_prefixes = ["10.1.1.0/24"]
}
resource "azurerm_subnet" "prd_subnet_db" {
name = "prd-db-subnet"
resource_group_name = azurerm_resource_group.network_rg.name
virtual_network_name = azurerm_virtual_network.prd_vnet.name
address_prefixes = ["10.1.2.0/24"]
}
# DEV VNet
resource "azurerm_virtual_network" "dev_vnet" {
name = "vnet-dev"
address_space = ["10.2.0.0/16"]
location = azurerm_resource_group.network_rg.location
resource_group_name = azurerm_resource_group.network_rg.name
tags = {
ResourceName = "vnet-dev"
DeploymentDate = "2025-05-07"
}
}
resource "azurerm_subnet" "dev_subnet_web" {
name = "dev-web-subnet"
resource_group_name = azurerm_resource_group.network_rg.name
virtual_network_name = azurerm_virtual_network.dev_vnet.name
address_prefixes = ["10.2.1.0/24"]
}
resource "azurerm_subnet" "dev_subnet_db" {
name = "dev-db-subnet"
resource_group_name = azurerm_resource_group.network_rg.name
virtual_network_name = azurerm_virtual_network.dev_vnet.name
address_prefixes = ["10.2.2.0/24"]
}
#########################
# Hub ↔ PRD Peering
#########################
resource "azurerm_virtual_network_peering" "hub_to_prd" {
name = "hub-to-prd"
resource_group_name = azurerm_resource_group.security_rg.name
virtual_network_name = azurerm_virtual_network.hub_vnet.name
remote_virtual_network_id = azurerm_virtual_network.prd_vnet.id
allow_forwarded_traffic = true
allow_gateway_transit = false
use_remote_gateways = false
}
resource "azurerm_virtual_network_peering" "prd_to_hub" {
name = "prd-to-hub"
resource_group_name = azurerm_resource_group.network_rg.name
virtual_network_name = azurerm_virtual_network.prd_vnet.name
remote_virtual_network_id = azurerm_virtual_network.hub_vnet.id
allow_forwarded_traffic = true
allow_gateway_transit = false
use_remote_gateways = false
}
#########################
# Hub ↔ DEV Peering
#########################
resource "azurerm_virtual_network_peering" "hub_to_dev" {
name = "hub-to-dev"
resource_group_name = azurerm_resource_group.security_rg.name
# hub Vnet은 VPN, Firewall 용도로 Security RG에 위치!함을 주의
virtual_network_name = azurerm_virtual_network.hub_vnet.name
remote_virtual_network_id = azurerm_virtual_network.dev_vnet.id
allow_forwarded_traffic = true
allow_gateway_transit = false
use_remote_gateways = false
}
resource "azurerm_virtual_network_peering" "dev_to_hub" {
name = "dev-to-hub"
resource_group_name = azurerm_resource_group.network_rg.name
virtual_network_name = azurerm_virtual_network.dev_vnet.name
remote_virtual_network_id = azurerm_virtual_network.hub_vnet.id
allow_forwarded_traffic = true
allow_gateway_transit = false
use_remote_gateways = false
}
9. Terraform 설정 시작
- terraform init를 실행하여 Terraform 배포를 초기화
이 명령은 Azure 리소스를 관리하는 데 필요한 Azure 공급자(provider)를 다운로드함
terraform init -upgrade
- network.tf 작성 후 terraform validate를 통해 설정 유효성 검사
- terraform plan을 통해 리소스 생성 계획 확인
중략
- # az account show로 현재 구독 위치 확인
- terraform apply로 적용 (yes 입력)
중략
10. Azure 콘솔에서 Network 리소스 배포 확인
- 아래 명령어로 생성된 subnet까지 확인
az network vnet subnet list --resource-group <리소스_그룹_이름> --vnet-name <VNet_이름> --output table
- Vnet Peering 확인
'Cloud > AZURE' 카테고리의 다른 글
Terraform on Azure 정리 (7) - Azure 배포 테스트 : Firewall & UDR (0) | 2025.05.08 |
---|---|
Terraform on Azure 정리 (5) - Azure 배포 테스트 : VM (0) | 2025.05.08 |
Terraform on Azure 정리 (3) - tf 파일과 기본 명령어 (0) | 2025.05.07 |
Terraform on Azure 정리 (2) - MS 계정으로 Azure에 Terraform 인증 (0) | 2025.04.23 |
Terraform on Azure 정리 (1) - Cloud Shell에서 Terraform 구성 (0) | 2025.04.22 |