[본투비엔지니어] 나에게 베어본만 주어진다면?? (6)
지난 글에서 Proxmox 서버 내부에 Rocky Linux 10 클라우드 이미지를 다운로드하고, 이를 템플릿(Template)으로 변환하는 작업을 완료했습니다. 이로써 서버 측면에서의 물리적, 논리적 준비는 모두 끝났습니다.
우리의 목표는 매번 Proxmox 웹 콘솔에 접속해 마우스를 클릭하는 것이 아니라, 로컬 컴퓨터에서 코드를 작성하고 실행하는 것만으로 서버를 생성하는 것입니다. 이를 위해 인프라 자동화 도구인 테라폼(Terraform)을 로컬 환경에 설치하고, Proxmox와 통신할 수 있도록 연동하는 과정을 진행하겠습니다.
1. Terraform 설치
# 1. HashiCorp 공식 탭(저장소) 추가
brew tap hashicorp/tap
# 2. Terraform 패키지 설치
brew install hashicorp/tap/terraform
# 3. 설치 확인 (버전 정보가 출력되면 성공)
terraform -version
2. Provider 설정
Terraform 자체는 인프라를 생성하는 '엔진'일 뿐, 실제로 어떤 플랫폼(AWS, Azure, Proxmox 등)을 제어할지는 Provider(플러그인)가 결정합니다.
provider.tf 파일을 생성하고, Proxmox 연동을 위한 설정을 작성합니다.
terraform {
required_providers {
proxmox = {
source = "Telmate/proxmox"
version = "3.0.1-rc3"
}
}
}
provider "proxmox" {
# Proxmox API 주소 (https 필수, 포트 8006, /api2/json 경로 포함)
pm_api_url = var.proxmox_api_url
# API Token 인증 정보 (변수 처리)
pm_api_token_id = var.proxmox_api_token_id
pm_api_token_secret = var.proxmox_api_token_secret
# 사설 인증서 검증 무시 (홈랩 환경에서는 필수)
pm_tls_insecure = true
}
3. 자격 증명 분리
변수 선언 파일
variables.tf 사용할 변수의 이름과 타입을 정의합니다.
variable "proxmox_api_url" {
type = string
}
variable "proxmox_api_token_id" {
type = string
sensitive = true
}
variable "proxmox_api_token_secret" {
type = string
sensitive = true
}
실제 값 입력 파일
terraform.tfvars 이곳에 Proxmox API Token 정보를 입력합니다. 이 파일은 .gitignore 등에 포함하여 외부에 노출되지 않도록 관리하는 것이 원칙입니다.
Proxmox API Token 생성하기
Proxmox 웹 대시보드에서 진행합니다.
- 위치 이동:
- 왼쪽 상단 Datacenter 클릭.
- 중앙 메뉴에서 Permissions -> API Tokens 클릭.
- [Add] 버튼 클릭.
- 토큰 정보 입력:
- User: root@pam (최고 관리자 권한을 줍니다.)
- Token ID: terraform (이름은 맘대로 지어도 됩니다.)
- Privilege Separation: [체크 해제]
- (중요: 이걸 체크하면 권한을 따로 줘야 해서 복잡합니다. 학습용이니 체크를 풀어서 root의 전권을 위임합니다.)
- [Add] 클릭.
- Secret 복사:
- 화면에 Token ID와 Secret이 뜹니다.
- Secret 값(UUID처럼 긴 문자열)은 한 번만 보여줍니다. 창 닫으면 다시는 못 봅니다.
- 예: root@pam!terraform (ID)
- 예: 8f3b2a1c-.... (Secret)

# 예: https://192.168.219.200:8006/api2/json
proxmox_api_url = "https://[Proxmox-IP]:8006/api2/json"
# 예: root@pam!terraform
proxmox_api_token_id = "[Proxmox에서-생성한-Token-ID]"
# 예: 8f3b2a1c-xxxx-xxxx...
proxmox_api_token_secret = "[복사해둔-Secret-Key]"
4. 연결 초기화
Terraform에게 "Proxmox 플러그인을 다운로드하고 준비하라"는 명령을 내립니다.
terraform init

5. 인프라 정의
Terraform의 핵심인 main.tf 파일을 생성합니다. 이곳에 우리가 원하는 서버의 사양(Spec)과 개수를 코드로 정의합니다.
# 1. Master Node
resource "proxmox_vm_qemu" "k8s_master" {
vmid = 120
name = "k8s-master"
target_node = "pve-cluster"
clone = "rocky-10-template"
full_clone = true
cores = 4
sockets = 1
cpu = "host"
memory = 8192
scsihw = "virtio-scsi-pci"
agent = 1
network {
model = "virtio"
bridge = "vmbr0"
}
os_type = "cloud-init"
ipconfig0 = "ip=192.168.219.120/24,gw=192.168.219.1"
ciuser = "root"
cipassword = "password1234"
bootdisk = "scsi0"
disks {
scsi {
scsi0 {
disk {
storage = "local-lvm"
size = "40G"
}
}
}
ide {
ide2 {
cloudinit {
storage = "local-lvm"
}
}
}
}
}
# 2. Worker Nodes
resource "proxmox_vm_qemu" "k8s_worker" {
count = 4
vmid = 121 + count.index
name = "k8s-worker-${count.index + 1}"
target_node = "pve-cluster"
clone = "rocky-10-template"
full_clone = true
cores = 4
sockets = 1
cpu = "host"
memory = 10240
scsihw = "virtio-scsi-pci"
agent = 1
network {
model = "virtio"
bridge = "vmbr0"
}
os_type = "cloud-init"
ipconfig0 = "ip=192.168.219.12${count.index + 1}/24,gw=192.168.219.1"
ciuser = "root"
cipassword = "password1234"
bootdisk = "scsi0"
disks {
scsi {
scsi0 {
disk {
storage = "local-lvm"
size = "100G"
}
}
}
ide {
ide2 {
cloudinit {
storage = "local-lvm"
}
}
}
}
}
6. 계획 확인
terraform plan

마지막에 이렇게 문구가 나오면 성공입니다.
7. 적용 및 생성
terraform apply

40분을 기다리고 있어도 작업이 끝나지 않았습니다. 그래서 강제 종료하고 원인을 찾아보니 main.tf 파일에서 'target_node' 가 잘못 설정 되어 있어서 계속 멤돌고 있었습니다. 수정하고 다시 실행해 보니

rm terraform.tfstate terraform.tfstate.backup
위의 명령어로 상태 파일을 삭제하고 'terraform init', 'terraform apply' 로 다시 실행해도 똑같은 오류가 생겼습니다. 여러가지 방법을 시도 했는데 결국엔 원인은
proxmox 8.4 버전과 테라폼 2.9.4 버전이 호환이 되지 않았습니다.
테라폼 버전을 3.0.1 로 업그레이드하고, main.tf 파일의 문법을 수정하니

1분 만에 5개의 VM 을 만드는 것에 성공했습니다.
8.접속 테스트
# Master 노드 접속
ssh root@192.168.219.120
# (비밀번호: password1234)
하지만 접속이 안됐습니다.
이유를 찾아보니 Cloud-Init 이 제대로 안붙어서 계정 정보가 생기지 않았습니다.
Telmate 방법에서 BPG 방법으로 전환
- Telmate: Proxmox 7.x 버전을 기준으로 개발되었습니다. Proxmox 8.x 버전에서 변경된 API 응답(디스크 용량 데이터 타입 등)을 제대로 처리하지 못해 'Panic' 에러가 발생하거나 플러그인이 비정상 종료되는 문제가 잦습니다.
- BPG: 최신 Proxmox 버전을 지원하기 위해 개발되었습니다. Proxmox 8.x의 API를 올바르게 해석하므로 버전 충돌로 인한 에러가 발생하지 않습니다.
provider.tf
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = ">= 0.78.0"
}
}
}
provider "proxmox" {
endpoint = var.proxmox_api_url
api_token = "${var.proxmox_api_token_id}=${var.proxmox_api_token_secret}"
insecure = true
ssh {
agent = true
}
}
terraform.tfvars
# 예: https://192.168.219.200:8006/api2/json
proxmox_api_url = "https://[Proxmox-IP]:8006/"
# 예: root@pam!terraform
proxmox_api_token_id = "[Proxmox에서-생성한-Token-ID]"
# 예: 8f3b2a1c-xxxx-xxxx...
proxmox_api_token_secret = "[복사해둔-Secret-Key]"
main.tf
# 1. Master Node
resource "proxmox_virtual_environment_vm" "k8s_master" {
name = "k8s-master"
node_name = "pve-cluster"
vm_id = 120
# 기존 템플릿(9010)을 복제
clone {
vm_id = 9010
full = true
}
cpu {
cores = 4
type = "host"
}
memory {
dedicated = 8192
}
agent {
enabled = true
}
network_device {
bridge = "vmbr0"
model = "virtio"
}
initialization {
# IP 설정
ip_config {
ipv4 {
address = "192.168.219.120/24"
gateway = "192.168.219.1"
}
}
# 사용자 계정 설정 (자동으로 적용됨)
user_account {
username = "root"
password = "password1234"
# 맥북의 공개키 파일 등록
keys = [trimspace(file("~/.ssh/id_ed25519.pub"))]
}
}
}
# 2. Worker Nodes
resource "proxmox_virtual_environment_vm" "k8s_worker" {
count = 4
name = "k8s-worker-${count.index + 1}"
node_name = "pve-cluster"
vm_id = 121 + count.index
clone {
vm_id = 9010
full = true
}
cpu {
cores = 4
type = "host"
}
memory {
dedicated = 10240
}
agent {
enabled = true
}
network_device {
bridge = "vmbr0"
model = "virtio"
}
initialization {
ip_config {
ipv4 {
address = "192.168.219.12${count.index + 1}/24"
gateway = "192.168.219.1"
}
}
user_account {
username = "root"
password = "password1234"
keys = [trimspace(file("~/.ssh/id_ed25519.pub"))]
}
}
}
생성

접속 테스트

드디어 VM 생성 후 접속까지 성공했습니다.