Terraform
Lumie 플랫폼의 인프라는 Terraform을 사용하여 Oracle Cloud Infrastructure(OCI)에 프로비저닝됩니다. 멀티 테넌시 환경을 지원하며, 두 개의 OCI 계정에 걸쳐 K3s 클러스터를 구성합니다.
아키텍처 개요
멀티 계정 구성
프로바이더 구성
# 0214 계정 (마스터 + 워커)
provider "oci" {
alias = "account_0214"
region = var.region
config_file_profile = "DEFAULT"
}
# 0213 계정 (워커 전용)
provider "oci" {
alias = "account_0213"
region = var.region
config_file_profile = "SECOND"
}
네트워크 구성
VCN 및 서브넷
0214 계정 (마스터 계정)
resource "oci_core_vcn" "vcn_0214" {
compartment_id = var.compartment_0214_ocid
cidr_blocks = ["10.0.0.0/16"]
display_name = "k3s-vcn"
dns_label = "k3svcn"
}
resource "oci_core_subnet" "subnet_0214" {
compartment_id = var.compartment_0214_ocid
vcn_id = oci_core_vcn.vcn_0214.id
cidr_block = "10.0.0.0/24"
display_name = "k3s-public-subnet"
prohibit_public_ip_on_vnic = false
}
0213 계정 (워커 계정)
resource "oci_core_vcn" "vcn_0213" {
compartment_id = var.compartment_0213_ocid
cidr_blocks = ["10.1.0.0/16"]
display_name = "k3s-vcn-0213"
dns_label = "k3svcn0213"
}
resource "oci_core_subnet" "subnet_0213" {
compartment_id = var.compartment_0213_ocid
vcn_id = oci_core_vcn.vcn_0213.id
cidr_block = "10.1.0.0/24"
display_name = "k3s-public-subnet"
prohibit_public_ip_on_vnic = false
}
VCN 피어링
두 계정 간의 VCN을 연결하기 위해 Local Peering Gateway를 사용합니다:
# 0214 계정의 LPG (요청자)
resource "oci_core_local_peering_gateway" "lpg_0214" {
provider = oci.account_0214
compartment_id = var.compartment_0214_ocid
vcn_id = oci_core_vcn.vcn_0214.id
display_name = "lpg-to-0213"
peer_id = oci_core_local_peering_gateway.lpg_0213.id
}
# 0213 계정의 LPG
resource "oci_core_local_peering_gateway" "lpg_0213" {
provider = oci.account_0213
compartment_id = var.compartment_0213_ocid
vcn_id = oci_core_vcn.vcn_0213.id
display_name = "lpg-to-0214"
}
보안 그룹
K3s 클러스터에 필요한 포트를 허용하는 보안 규칙을 설정합니다:
# SSH (22)
ingress_security_rules {
protocol = "6"
source = "0.0.0.0/0"
tcp_options {
min = 22
max = 22
}
}
# K3s API Server (6443)
ingress_security_rules {
protocol = "6"
source = "0.0.0.0/0"
tcp_options {
min = 6443
max = 6443
}
}
# Kubelet API (10250)
ingress_security_rules {
protocol = "6"
source = "0.0.0.0/0"
tcp_options {
min = 10250
max = 10250
}
}
# Flannel VXLAN (8472 UDP)
ingress_security_rules {
protocol = "17"
source = "0.0.0.0/0"
udp_options {
min = 8472
max = 8472
}
}
컴퓨트 인스턴스
인스턴스 사양
모든 인스턴스는 ARM64 기반의 VM.Standard.A1.Flex 셰이프를 사용합니다:
resource "oci_core_instance" "nodes_0214" {
for_each = var.nodes_0214
compartment_id = var.compartment_0214_ocid
availability_domain = data.oci_identity_availability_domains.ads_0214.availability_domains[0].name
display_name = "k3s-${each.key}"
shape = "VM.Standard.A1.Flex"
shape_config {
ocpus = each.value.ocpus
memory_in_gbs = each.value.memory_in_gbs
}
source_details {
source_type = "image"
source_id = data.oci_core_images.ubuntu_arm64_0214.images[0].id
boot_volume_size_in_gbs = 50
}
}
노드 구성
변수를 통해 노드 구성을 정의합니다:
# terraform.tfvars (실제 현행 구성)
nodes_0214 = {
"master" = {
ocpus = 2
memory_in_gbs = 12
role = "master"
}
"worker-2" = {
ocpus = 2
memory_in_gbs = 12
role = "worker"
}
}
nodes_0213 = {
"worker-3" = {
ocpus = 2
memory_in_gbs = 12
role = "worker"
}
"worker-4" = {
ocpus = 2
memory_in_gbs = 12
role = "worker"
}
}
worker-1은 2026-04 비용 최적화로 제거되었습니다. 해당 50GB MinIO 디스크는 master 노드로 이전되었습니다(free tier 한도 정렬).
Network Load Balancer
애플리케이션 NLB (0214 계정)
nlb_0214.tf에 정의된 Layer 4 TCP NLB입니다. 고정 IP 168.107.42.253에 Cloudflare가 프록시됩니다.
resource "oci_core_public_ip" "nlb_public_ip_0214" {
lifetime = "RESERVED"
display_name = "k3s-nlb-public-ip"
# OCI 프로바이더 버그 #1708 워크어라운드 — private_ip_id 변경을 무시하지 않으면
# terraform apply 시 NLB IP 연결이 해제되어 TCP :443 타임아웃 발생
lifecycle {
ignore_changes = [private_ip_id]
}
}
백엔드: 0214 worker-2 + 0213 worker-3/4 (LPG 경유). 마스터는 제외됩니다.
Teleport 전용 NLB (0213 계정)
nlb_teleport_0213.tf에 정의된 전용 NLB입니다. 고정 IP 158.180.89.154에 Cloudflare DNS-only 레코드로 연결됩니다.
- 포트: TCP :443 → NodePort 30443
- 백엔드: worker-3, worker-4 (0213 VCN 로컬)
- TLS 처리: L4 TCP passthrough, Teleport proxy pod이 TLS 종료
lifecycle { ignore_changes = [private_ip_id] }동일하게 적용
스토리지
블록 볼륨
MinIO용 50GB 블록 볼륨 배분:
| 계정 | 노드 | 볼륨 |
|---|---|---|
| OCI-0214 | master, worker-2 | 각 50GB (worker-1 디스크 master로 이전됨) |
| OCI-0213 | worker-3, worker-4 | 각 50GB |
각 워커 노드에는 MinIO용 50GB 블록 볼륨이 연결됩니다:
resource "oci_core_volume" "volumes_0214" {
for_each = local.worker_nodes_0214
compartment_id = var.compartment_0214_ocid
availability_domain = data.oci_identity_availability_domains.ads_0214.availability_domains[0].name
display_name = "k3s-${each.key}-minio"
size_in_gbs = 50
vpus_per_gb = 10
}
resource "oci_core_volume_attachment" "attachments_0214" {
for_each = local.worker_nodes_0214
attachment_type = "paravirtualized"
instance_id = oci_core_instance.nodes_0214[each.key].id
volume_id = oci_core_volume.volumes_0214[each.key].id
is_read_only = false
is_shareable = false
}
변수 구성
필수 변수
# OCI 계정 정보
variable "tenancy_0214_ocid" {
description = "0214 Account Tenancy OCID"
type = string
}
variable "compartment_0214_ocid" {
description = "0214 Account Compartment OCID"
type = string
}
variable "tenancy_0213_ocid" {
description = "0213 Account Tenancy OCID"
type = string
}
variable "compartment_0213_ocid" {
description = "0213 Account Compartment OCID"
type = string
}
# SSH 키
variable "ssh_public_key" {
description = "SSH public key for instance access"
type = string
}
네트워크 변수
variable "vcn_0214_cidr" {
description = "0214 VCN CIDR block"
type = string
default = "10.0.0.0/16"
}
variable "vcn_0213_cidr" {
description = "0213 VCN CIDR block"
type = string
default = "10.1.0.0/16"
}
출력값
Ansible 통합
Terraform 출력값은 Ansible 동적 인벤토리에서 사용됩니다:
output "master_info" {
description = "K3s master node information"
value = {
name = "master"
public_ip = oci_core_instance.nodes_0214["master"].public_ip
private_ip = oci_core_instance.nodes_0214["master"].private_ip
k3s_url = "https://${oci_core_instance.nodes_0214["master"].private_ip}:6443"
}
}
output "workers_info" {
description = "K3s worker nodes information"
value = merge(
{
for name, instance in oci_core_instance.nodes_0214 :
name => {
account = "0214"
public_ip = instance.public_ip
private_ip = instance.private_ip
}
if name != "master"
},
{
for name, instance in oci_core_instance.nodes_0213 :
name => {
account = "0213"
public_ip = instance.public_ip
private_ip = instance.private_ip
}
}
)
}
배포 과정
1. 사전 준비
# OCI CLI 구성 확인
oci iam user list --profile DEFAULT
oci iam user list --profile SECOND
# SSH 키 생성 (필요한 경우)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519