지난 글에서 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 생성 후 접속까지 성공했습니다.
'project > 본투비엔지니어' 카테고리의 다른 글
| [본투비엔지니어] 나에게 베어본만 주어진다면?? (8) (0) | 2026.01.29 |
|---|---|
| [본투비엔지니어] 나에게 베어본만 주어진다면?? (7) (0) | 2026.01.29 |
| [본투비엔지니어] 나에게 베어본만 주어진다면?? (5) (0) | 2026.01.28 |
| [본투비엔지니어] 나에게 베어본만 주어진다면?? (4) (0) | 2026.01.27 |
| [본투비엔지니어] 나에게 베어본만 주어진다면?? (3) (0) | 2026.01.27 |