콘텐츠로 이동

배포

모든 Terraform 파일은 terraform/ 디렉터리에 있습니다. 리포지터리를 클론하고 직접 배포하세요:

Terminal window
git clone https://github.com/f5-sales-demo/cdn-simulator.git
cd cdn-simulator/terraform
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your Azure subscription ID and origin server

terraform 디렉터리에는 데모 리소스 표준을 따르는 9개의 파일이 포함되어 있습니다:

  • versions.tf — Terraform 및 프로바이더 버전 제약 조건 (azurerm ~> 4.0, azuread ~> 3.0)
  • providers.tf — Azure RM 및 Azure AD 프로바이더 구성
  • data.tf — 배포자 자동 해석을 위한 Azure AD 데이터 소스
  • locals.tf — 배포자 해석, Azure Cloud Adoption Framework 리소스 명명, 표준 태그
  • main.tf — 리소스 그룹 (이름: rg-cdn-simulator-{environment}-{deployer})
  • variables.tf — 모든 입력 변수 (필수 3개, 선택 8개)
  • network.tf — VNet (10.100.0.0/16), 서브넷, 공인 IP, NSG (포트 22/80/443), NIC
  • vm.tf — templatefile()을 통한 cloud-init이 포함된 Ubuntu 24.04 VM
  • outputs.tf — 17개 출력값 (표준 15개 + 구성 요소별 2개)

variables.tf는 일반, 컴퓨팅, 구성 요소별 섹션으로 구성된 11개의 입력 변수를 정의합니다. deployer 식별자는 Azure AD 계정에서 자동으로 해석됩니다 — subscription_id, origin_server, origin_host만 설정하면 됩니다:

# ---------------------------------------------------------
# General
# ---------------------------------------------------------
variable "subscription_id" {
description = "Azure subscription ID"
type = string
}
variable "deployer" {
description = "Override for deployer identifier (auto-resolved from Azure AD if empty). Required for service principal or managed identity authentication."
type = string
default = ""
}
variable "location" {
description = "Azure region for all resources"
type = string
default = "eastus2"
}
variable "environment" {
description = "Environment label used in resource group naming and tags"
type = string
default = "lab"
}
variable "tags" {
description = "Additional tags merged with standard tags (component, environment, deployer, managed_by)"
type = map(string)
default = {}
}
# ---------------------------------------------------------
# Compute
# ---------------------------------------------------------
variable "vm_size" {
description = "Azure VM size — F-series compute-optimized recommended (F4s_v2 for lab, F16s_v2 for load testing, F32s_v2 for production)"
type = string
default = "Standard_F4s_v2"
}
variable "admin_username" {
description = "SSH admin username for the VM"
type = string
default = "azureuser"
}
variable "ssh_public_key_path" {
description = "Path to the SSH public key file"
type = string
default = "~/.ssh/id_ed25519.pub"
}
variable "disk_size_gb" {
description = "OS disk size in GB"
type = number
default = 30
}
# ---------------------------------------------------------
# Component-Specific
# ---------------------------------------------------------
variable "origin_server" {
description = "Origin server URL for cache miss forwarding (e.g., an HTTPS VIP or a direct HTTP origin IP)"
type = string
}
variable "origin_host" {
description = "Origin server host:port for NGINX upstream (no scheme). Use IP:443 for HTTPS or IP:80 for HTTP."
type = string
}

network.tf는 VNet, 서브넷, 공인 IP, NSG (포트 22/80/443), NIC를 생성합니다:

resource "azurerm_virtual_network" "main" {
name = local.name.virtual_network
address_space = ["10.100.0.0/16"]
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
tags = azurerm_resource_group.main.tags
}
resource "azurerm_subnet" "main" {
name = local.name.subnet
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.100.1.0/24"]
}
resource "azurerm_public_ip" "main" {
name = local.name.public_ip
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
allocation_method = "Static"
sku = "Standard"
tags = azurerm_resource_group.main.tags
}
resource "azurerm_network_security_group" "main" {
name = local.name.nsg
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
security_rule {
name = "AllowHTTP"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "80"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "AllowHTTPS"
priority = 110
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "443"
source_address_prefix = "*"
destination_address_prefix = "*"
}
security_rule {
name = "AllowSSH"
priority = 120
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
tags = azurerm_resource_group.main.tags
}
resource "azurerm_network_interface" "main" {
name = local.name.network_interface
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.main.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.main.id
}
tags = azurerm_resource_group.main.tags
}
resource "azurerm_network_interface_security_group_association" "main" {
network_interface_id = azurerm_network_interface.main.id
network_security_group_id = azurerm_network_security_group.main.id
}

vm.tf는 Ubuntu 24.04 VM을 생성합니다. SSH 공개 키 경로는 ~를 처리하기 위해 pathexpand()를 통해 확장됩니다. Cloud-init 템플릿은 origin_serverorigin_host 변수를 받습니다:

resource "azurerm_linux_virtual_machine" "main" {
name = local.name.virtual_machine
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
size = var.vm_size
admin_username = var.admin_username
disable_password_authentication = true
admin_ssh_key {
username = var.admin_username
public_key = file(pathexpand(var.ssh_public_key_path))
}
network_interface_ids = [azurerm_network_interface.main.id]
os_disk {
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
disk_size_gb = var.disk_size_gb
}
source_image_reference {
publisher = "Canonical"
offer = "ubuntu-24_04-lts"
sku = "server"
version = "latest"
}
custom_data = base64encode(templatefile("${path.module}/cloud-init.yaml", {
origin_server = var.origin_server
origin_host = var.origin_host
}))
boot_diagnostics {}
tags = azurerm_resource_group.main.tags
}

cloud-init.yaml은 커널 튜닝, systemd 제한, 성능 최적화 구성이 적용된 NGINX, 128 MB 캐시 키 존, 업스트림 keepalive 풀, gzip 압축, 67개 이상의 CDN 벤더 헤더로 VM을 프로비저닝합니다. 공유 헬퍼 라이브러리(/usr/local/lib/cloud-init-helpers.sh)는 재시도 로직과 /var/log/cloud-init-progress.log에 대한 진행 로깅을 제공합니다.

cloud-init은 업스트림 구성을 위해 Terraform 템플릿 변수인 ${origin_server}${origin_host}를 사용합니다. ${request_id}와 같은 NGINX 변수는 Terraform templatefile에서 $${request_id}로 이스케이프됩니다.

#cloud-config
package_update: true
package_upgrade: true
bootcmd:
- mkdir -p /var/cache/nginx/cdn
- chown www-data:www-data /var/cache/nginx/cdn 2>/dev/null || true
packages:
- nginx
- irqbalance
write_files:
# ── Kernel tuning ──────────────────────────────────────────────
- path: /etc/sysctl.d/99-cdn-tuning.conf
content: |
net.core.somaxconn = 262144
net.core.netdev_max_backlog = 262144
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_max_tw_buckets = 8000000
fs.file-max = 8388608
vm.swappiness = 10
# ── Systemd override for NGINX file descriptor limits ──────────
- path: /etc/systemd/system/nginx.service.d/override.conf
content: |
[Service]
LimitNOFILE=262144
LimitNPROC=262144
# ── OS-level limits for www-data (NGINX worker user) ───────────
- path: /etc/security/limits.d/99-nginx.conf
content: |
www-data soft nofile 262144
www-data hard nofile 262144
# ── NGINX main config ──────────────────────────────────────────
- path: /etc/nginx/nginx.conf
content: |
user www-data;
worker_processes auto;
worker_rlimit_nofile 262144;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
use epoll;
worker_connections 32768;
multi_accept on;
accept_mutex off;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
types_hash_max_size 2048;
server_tokens off;
client_max_body_size 50m;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format cdn '$remote_addr [$time_local] "$request" $status $body_bytes_sent $upstream_cache_status $request_time';
access_log /var/log/nginx/access.log cdn;
keepalive_timeout 65;
keepalive_requests 100000;
proxy_buffering on;
proxy_buffer_size 16k;
proxy_buffers 128 16k;
proxy_busy_buffers_size 256k;
gzip on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_vary on;
gzip_proxied any;
gzip_types text/plain text/css text/javascript text/xml
application/json application/javascript application/xml
application/xml+rss application/atom+xml
application/ld+json application/manifest+json
image/svg+xml;
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
include /etc/nginx/conf.d/*.conf;
}
# ── CDN edge proxy config ──────────────────────────────────────
- path: /etc/nginx/conf.d/cdn-edge.conf
content: |
proxy_cache_path /var/cache/nginx/cdn
levels=1:2
keys_zone=cdn_cache:128m
max_size=25g
inactive=24h
use_temp_path=off;
upstream origin_backend {
server ${origin_host};
keepalive 1024;
keepalive_timeout 60s;
keepalive_requests 100000;
}
map $request_id $cdn_ray_id {
default "$${request_id}-SJC";
}
map $request_id $cdn_azure_ref {
default "0$${request_id}AAAAAA";
}
map $request_id $cdn_amz_cf_id {
default "E1$${request_id}==";
}
map $http_user_agent $is_mobile {
default "false";
"~*Mobile|Android|iPhone|iPod|BlackBerry|Opera Mini|IEMobile" "true";
}
map $http_user_agent $is_tablet {
default "false";
"~*iPad|Android(?!.*Mobile)|Tablet|Kindle|PlayBook" "true";
}
map $http_user_agent $is_desktop {
default "true";
"~*Mobile|Android|iPhone|iPod|BlackBerry|Opera Mini|IEMobile|iPad|Tablet|Kindle|PlayBook" "false";
}
server {
listen 80 reuseport;
server_name _;
location /health {
access_log off;
return 200 '{"status":"healthy","component":"cdn-edge","engine":"nginx","vendor_profiles":["akamai","cloudflare","cloudfront","fastly","azure-front-door"]}';
add_header Content-Type application/json;
}
location / {
proxy_pass https://origin_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_ssl_server_name on;
proxy_ssl_name csd.bankexample.com;
proxy_ssl_verify off;
proxy_read_timeout 180s;
proxy_connect_timeout 10s;
proxy_send_timeout 15s;
# Standard
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Via "1.1 cdn-simulator";
proxy_set_header Forwarded "for=$remote_addr;proto=$scheme;host=$host";
proxy_set_header CDN-Loop "cdn-simulator";
# Akamai
proxy_set_header True-Client-IP $remote_addr;
proxy_set_header X-Akamai-Edgescape "georegion=263,country_code=US,region_code=CA,city=SANJOSE,dma=807,pmsa=7400,msa=7362,areacode=408,county=SANTACLARA,fips=06085,lat=37.3353,long=-121.8938,timezone=PST,zip=95113-95196,continent=NA,throughput=vhigh,bw=5000,network=att.net,asnum=7018,network_type=broadband";
proxy_set_header X-Akamai-Device-Characteristics "brand_name=Generic;model_name=Browser;is_mobile=$is_mobile;is_tablet=$is_tablet;is_wireless_device=$is_mobile;device_os=Linux;device_os_version=1.0;resolution_width=1920;resolution_height=1080";
proxy_set_header X-Akamai-Request-ID $request_id;
# Cloudflare
proxy_set_header CF-Connecting-IP $remote_addr;
proxy_set_header CF-IPCountry "US";
proxy_set_header cf-ipcity "San Jose";
proxy_set_header cf-ipcontinent "NA";
proxy_set_header cf-iplatitude "37.3353";
proxy_set_header cf-iplongitude "-121.8938";
proxy_set_header cf-region "California";
proxy_set_header cf-region-code "CA";
proxy_set_header cf-metro-code "807";
proxy_set_header cf-postal-code "95113";
proxy_set_header cf-timezone "America/Los_Angeles";
proxy_set_header Cf-Ray $cdn_ray_id;
proxy_set_header CF-Visitor '{"scheme":"https"}';
proxy_set_header cf-bot-score "85";
proxy_set_header cf-verified-bot "false";
proxy_set_header cf-ja3-hash "e7d705a3286e19ea42f587b344ee6865";
proxy_set_header cf-ja4 "t13d1516h2_8daaf6152771_b0da82dd1658";
# CloudFront
proxy_set_header CloudFront-Viewer-Address "$remote_addr:$remote_port";
proxy_set_header CloudFront-Viewer-Country "US";
proxy_set_header CloudFront-Viewer-Country-Name "United States";
proxy_set_header CloudFront-Viewer-Country-Region "CA";
proxy_set_header CloudFront-Viewer-Country-Region-Name "California";
proxy_set_header CloudFront-Viewer-City "San Jose";
proxy_set_header CloudFront-Viewer-Postal-Code "95113";
proxy_set_header CloudFront-Viewer-Latitude "37.33530";
proxy_set_header CloudFront-Viewer-Longitude "-121.89300";
proxy_set_header CloudFront-Viewer-Time-Zone "America/Los_Angeles";
proxy_set_header CloudFront-Viewer-Metro-Code "807";
proxy_set_header CloudFront-Viewer-ASN "7018";
proxy_set_header CloudFront-Viewer-Http-Version "2.0";
proxy_set_header CloudFront-Forwarded-Proto "https";
proxy_set_header CloudFront-Viewer-TLS "TLSv1.3:TLS_AES_128_GCM_SHA256:sessionResumed";
proxy_set_header CloudFront-Viewer-JA3-Fingerprint "e7d705a3286e19ea42f587b344ee6865";
proxy_set_header CloudFront-Is-Desktop-Viewer $is_desktop;
proxy_set_header CloudFront-Is-Mobile-Viewer $is_mobile;
proxy_set_header CloudFront-Is-Tablet-Viewer $is_tablet;
proxy_set_header CloudFront-Is-SmartTV-Viewer "false";
proxy_set_header X-Amz-Cf-Id $cdn_amz_cf_id;
# Fastly
proxy_set_header Fastly-Client-IP $remote_addr;
proxy_set_header Fastly-SSL "1";
proxy_set_header Fastly-Client "1";
proxy_set_header Fastly-FF "cache-sjc3120-SJC";
proxy_set_header X-Geo-Country-Code "US";
proxy_set_header X-Geo-Country-Code3 "USA";
proxy_set_header X-Geo-Country-Name "United States";
proxy_set_header X-Geo-City "San Jose";
proxy_set_header X-Geo-Region "CA";
proxy_set_header X-Geo-Continent-Code "NA";
proxy_set_header X-Geo-Latitude "37.3353";
proxy_set_header X-Geo-Longitude "-121.8938";
proxy_set_header X-Geo-Postal-Code "95113";
proxy_set_header X-Geo-Metro-Code "807";
proxy_set_header X-Geo-ASN "7018";
proxy_set_header X-Geo-Conn-Speed "broadband";
proxy_set_header X-Geo-Conn-Type "wired";
# Azure Front Door
proxy_set_header X-Azure-ClientIP $remote_addr;
proxy_set_header X-Azure-SocketIP $remote_addr;
proxy_set_header X-Azure-Ref $cdn_azure_ref;
proxy_set_header X-Azure-FDID "a0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1";
proxy_set_header X-Azure-RequestChain "hops=1";
# Cache
proxy_set_header Host csd.bankexample.com;
proxy_cache cdn_cache;
proxy_cache_methods GET HEAD;
proxy_cache_valid 200 301 302 4h;
proxy_cache_valid 404 1m;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_lock on;
proxy_cache_lock_age 3s;
proxy_cache_lock_timeout 3s;
proxy_cache_background_update on;
proxy_cache_use_stale updating error timeout http_500 http_502 http_503 http_504;
proxy_ignore_headers Set-Cookie Cache-Control Expires Vary;
proxy_hide_header X-Cache-Status;
proxy_hide_header Vary;
add_header X-Cache-Status $upstream_cache_status always;
add_header X-CDN-Edge "cdn-simulator" always;
add_header X-CDN-POP "SJC" always;
add_header X-Served-By "cache-sjc3120-SJC" always;
add_header X-Request-ID $request_id always;
}
}
- path: /etc/nginx/conf.d/default.conf
content: ""
- path: /usr/local/lib/cloud-init-helpers.sh
permissions: "0644"
content: |
#!/bin/sh
PROGRESS_LOG="/var/log/cloud-init-progress.log"
log_phase() {
_phase="$1"; shift
_msg="$${*:-started}"
_ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
printf '[%s] [%s] %s\n' "$_ts" "$_phase" "$_msg" | tee -a "$PROGRESS_LOG" >&2
}
retry_cmd() {
_max="$1"; _base="$2"; shift 2
_attempt=1
while [ "$_attempt" -le "$_max" ]; do
if "$@"; then return 0; fi
if [ "$_attempt" -lt "$_max" ]; then
_wait=$(( _base * _attempt ))
log_phase "retry" "attempt $_attempt/$_max failed ($1) — retrying in $${_wait}s"
sleep "$_wait"
fi
_attempt=$(( _attempt + 1 ))
done
log_phase "retry" "FAILED after $_max attempts: $1"
return 1
}
runcmd:
- |
. /usr/local/lib/cloud-init-helpers.sh
log_phase "init" "cdn-simulator provisioning started"
- sysctl -p /etc/sysctl.d/99-cdn-tuning.conf || exit 1
- systemctl daemon-reload
- rm -f /etc/nginx/sites-enabled/default
- chown -R www-data:www-data /var/cache/nginx/cdn
- nginx -t || exit 1
- systemctl enable nginx
- systemctl restart nginx
- systemctl enable irqbalance
- systemctl start irqbalance
- |
. /usr/local/lib/cloud-init-helpers.sh
NIC=$(ip -o link show | awk -F': ' '/state UP/{print $2}' | grep -v lo | head -1)
if [ -n "$NIC" ]; then
log_phase "nic" "configuring RPS/RFS for $NIC"
echo 65536 > /proc/sys/net/core/rps_sock_flow_entries 2>/dev/null || true
for i in $(seq 0 $(($(nproc)-1))); do
echo 8192 > /sys/class/net/$NIC/queues/rx-$i/rps_flow_cnt 2>/dev/null || true
done
else
log_phase "nic" "no active NIC found — skipping RPS/RFS"
fi
- |
. /usr/local/lib/cloud-init-helpers.sh
log_phase "complete" "cdn-simulator provisioned"

outputs.tf는 데모 리소스 표준을 따르는 17개의 출력값을 노출합니다 — 모든 데모 리소스가 공유하는 표준 출력값 15개 (deployer, public_ip, private_ip, ssh_command, resource_group_name, vm_name, nsg_name, vnet_name, subnet_id, component, environment, resource_group_id, vm_id, nsg_id, location) 및 구성 요소별 출력값 2개 (edge_url, health_check_url):

# ---------------------------------------------------------
# Standard Outputs (present in every demo resource)
# ---------------------------------------------------------
output "deployer" {
description = "Resolved deployer identifier"
value = local.deployer
}
output "resource_group_name" {
description = "Name of the resource group"
value = azurerm_resource_group.main.name
}
output "resource_group_id" {
description = "Resource ID of the resource group"
value = azurerm_resource_group.main.id
}
output "location" {
description = "Azure region"
value = azurerm_resource_group.main.location
}
output "public_ip" {
description = "Public IP address of the VM"
value = azurerm_public_ip.main.ip_address
}
output "private_ip" {
description = "Private IP address of the VM"
value = azurerm_network_interface.main.private_ip_address
}
output "ssh_command" {
description = "SSH command to connect to the VM"
value = "ssh ${var.admin_username}@${azurerm_public_ip.main.ip_address}"
}
output "vm_name" {
description = "Name of the virtual machine"
value = azurerm_linux_virtual_machine.main.name
}
output "vm_id" {
description = "Resource ID of the virtual machine"
value = azurerm_linux_virtual_machine.main.id
}
output "nsg_name" {
description = "Name of the network security group"
value = azurerm_network_security_group.main.name
}
output "nsg_id" {
description = "Resource ID of the network security group"
value = azurerm_network_security_group.main.id
}
output "vnet_name" {
description = "Name of the virtual network"
value = azurerm_virtual_network.main.name
}
output "subnet_id" {
description = "Resource ID of the subnet"
value = azurerm_subnet.main.id
}
output "component" {
description = "Component name"
value = local.component
}
output "environment" {
description = "Environment label"
value = var.environment
}
# ---------------------------------------------------------
# Component-Specific Outputs
# ---------------------------------------------------------
output "edge_url" {
description = "HTTP URL of the CDN edge node"
value = "http://${azurerm_public_ip.main.ip_address}"
}
output "health_check_url" {
description = "Health check endpoint"
value = "http://${azurerm_public_ip.main.ip_address}/health"
}

terraform.tfvars.exampleterraform.tfvars로 복사하고 값을 입력하세요. .gitignore는 자격 증명 커밋을 방지하기 위해 terraform.tfvars를 제외합니다:

# Copy this file to terraform.tfvars and fill in your values.
# terraform.tfvars is gitignored — never commit real credentials.
# --- Required ---
subscription_id = "00000000-0000-0000-0000-000000000000"
origin_server = "http://your-origin-ip"
origin_host = "your-origin-ip:80"
# --- Optional overrides (defaults shown) ---
# deployer = "" # auto-resolved from Azure AD
# location = "eastus2"
# environment = "lab"
# vm_size = "Standard_F4s_v2"
# disk_size_gb = 30
# admin_username = "azureuser"
# ssh_public_key_path = "~/.ssh/id_ed25519.pub"
# tags = {}
Terminal window
# Initialize Terraform
terraform init
# Review the plan
terraform plan
# Apply
terraform apply

배포가 성공적으로 완료되면 Terraform은 공인 IP, SSH 명령, 엣지 URL을 출력합니다.

F-시리즈 컴퓨팅 최적화 VM은 CPU 바운드 NGINX 프록시 워크로드에 권장됩니다. 기본값인 Standard_F4s_v2 (4 vCPU, 8 GiB)는 랩 및 데모 사용에 적합합니다. 부하 테스트 또는 프로덕션 벤치마킹 시나리오에서는 vm_size 변수를 재정의하세요. Cloud-init 커널 튜닝과 NGINX 구성은 vCPU 수에 따라 자동으로 확장됩니다 (worker_processes auto).

terraform apply가 완료된 후, NGINX 설치 및 구성을 마치기 위해 cloud-init이 2~3분간 실행되도록 기다려 주세요. 헬스 엔드포인트를 확인하세요:

Terminal window
curl -s "http://$(terraform output -raw public_ip)/health" | jq .

예상 응답:

{
"status": "healthy",
"component": "cdn-edge",
"engine": "nginx",
"vendor_profiles": [
"akamai",
"cloudflare",
"cloudfront",
"fastly",
"azure-front-door"
]
}

업스트림 구성 요소에서 연결하기

섹션 제목: “업스트림 구성 요소에서 연결하기”

CDN 시뮬레이터는 배포된 오리진 서버가 필요합니다. 오리진 서버의 terraform 출력값을 사용하여 필수 변수를 채우세요:

Terminal window
cd ../origin-server/terraform
origin_ip=$(terraform output -raw public_ip)
cd ../../cdn-simulator/terraform
cat > terraform.tfvars <<EOF
subscription_id = "your-subscription-id"
origin_server = "http://${origin_ip}"
origin_host = "${origin_ip}:80"
EOF
필수 변수소스형식
origin_server오리진 서버 public_ip 출력값http://<ip> (스킴 포함)
origin_host오리진 서버 public_ip 출력값<ip>:80 (스킴 제외, 포트 포함)

사용자 정의 옵션은 NGINX 구성으로 이동하거나 캐시 테스트는 확인으로 이동하세요.