Proxmox¶
이 문서는 tirosh-home site에서 Proxmox node를 준비하고, Ubuntu cloud image 기반 VM template을 만든 뒤, OpenTofu로 site VM을 관리하는 흐름을 설명합니다.
1. 전체 흐름¶
1-1. 구성 단계¶
Proxmox 작업은 크게 세 단계로 나뉩니다.
Proxmox node 준비
|
v
Ubuntu cloud image template 생성
|
v
site VM catalog 적용
1-2. 기본 실행 순서¶
처음 구성할 때는 아래 순서로 진행합니다.
make site/inventory/render SITE=tirosh-home
make proxmox/bootstrap SITE=tirosh-home ASK_PASS=true
make proxmox/template/apply SITE=tirosh-home ASK_PASS=true
make proxmox/vms/plan SITE=tirosh-home
make proxmox/vms/apply SITE=tirosh-home
1-3. 도구별 책임¶
proxmox/bootstrap과 proxmox/template/apply는 Ansible로 Proxmox node에 SSH 접속합니다. proxmox/vms/*는 OpenTofu로 Proxmox API를 호출합니다.
2. site 설정과 inventory¶
Proxmox 작업에는 두 종류의 대상이 함께 등장합니다.
- Ansible이 SSH로 접속할 Proxmox node
- OpenTofu가 Proxmox API로 생성하고 관리할 VM
그래서 Proxmox 관련 설정은 한 파일에 몰아두지 않습니다. profile.toml은 Make command가 사용할 실행 기본값을 정하고, inventory.toml은 사람이 관리하는 host catalog가 됩니다. 실제 template 설정과 VM catalog는 각각 proxmox/ 하위 파일과 vms.tfvars에 둡니다.
sites/tirosh-home/
profile.toml Make command 실행 기본값
inventory.toml 사람이 편집하는 host catalog
inventory.yml Ansible이 읽는 렌더링 결과
vms.tfvars OpenTofu가 읽는 VM catalog
proxmox/
bootstrap.vars.yml Ansible bootstrap 변수
ubuntu-cloud-template.vars.yml Ansible template 생성 변수
vars.tfvars OpenTofu Proxmox 공통 변수
vms.secrets.tfvars OpenTofu secret 변수
각 파일의 책임을 더 풀면 아래와 같습니다.
| 파일 | 누가 읽나 | 역할 |
|---|---|---|
profile.toml |
Make | SITE=tirosh-home일 때 어떤 target, vars file, tfvars file을 기본으로 쓸지 정합니다. |
inventory.toml |
site/inventory/render |
사람이 편집하는 source입니다. Proxmox node, GPU host, VM host의 SSH 정보를 둡니다. |
inventory.yml |
Ansible | 렌더링 결과입니다. playbook 실행 대상 group과 host alias를 제공합니다. |
proxmox/bootstrap.vars.yml |
Ansible | Proxmox node repository, package, 필수 command를 준비합니다. |
proxmox/ubuntu-cloud-template.vars.yml |
Ansible | Ubuntu cloud template 생성에 필요한 storage, bridge, template ID를 정합니다. |
proxmox/vars.tfvars |
OpenTofu | Proxmox API endpoint, node, 기본 datastore, network 같은 VM 생성 공통값을 둡니다. |
vms.tfvars |
OpenTofu | site에서 만들 VM 목록과 VM별 CPU, memory, disk, IP, user를 둡니다. |
proxmox/vms.secrets.tfvars |
OpenTofu | Proxmox API token이나 VM password 같은 secret을 둡니다. |
2-1. profile 기본값¶
profile.toml은 인프라 상태를 직접 선언하는 파일이라기보다, Make command가 각 도구를 호출할 때 사용할 기본 인자를 정하는 파일입니다.
예를 들어 사람은 아래처럼 site만 지정합니다.
make proxmox/template/apply SITE=tirosh-home
그러면 Make는 sites/tirosh-home/profile.toml을 읽어서 다음 값들을 채웁니다.
- 어느 Proxmox node에 SSH로 붙을지
- 어떤 Ansible vars file을 넘길지
- OpenTofu가 어떤 tfvars file을 읽을지
- secret tfvars file의 기본 경로가 어디인지
즉 profile.toml은 “이 site에서 Proxmox 작업을 실행할 때의 기본 실행 context”입니다.
[proxmox]
target_name = "pve1"
vars = "sites/tirosh-home/proxmox/ubuntu-cloud-template.vars.yml"
bootstrap_vars = "sites/tirosh-home/proxmox/bootstrap.vars.yml"
vm_vars = "sites/tirosh-home/proxmox/vars.tfvars"
vm_catalog = "sites/tirosh-home/vms.tfvars"
vm_secrets = "sites/tirosh-home/proxmox/vms.secrets.tfvars"
각 값은 아래처럼 사용됩니다.
| key | 기본 의미 | 사용 예 |
|---|---|---|
target_name |
Ansible이 접속할 기본 Proxmox host alias | make proxmox/bootstrap의 TARGET_NAME |
vars |
Ubuntu cloud template 생성 변수 | make proxmox/template/apply |
bootstrap_vars |
Proxmox node bootstrap 변수 | make proxmox/bootstrap |
vm_vars |
OpenTofu Proxmox 공통 변수 | make proxmox/vms/plan |
vm_catalog |
OpenTofu VM catalog | make proxmox/vms/plan |
vm_secrets |
OpenTofu secret 변수 | make proxmox/vms/plan |
아래 명령을 실행하면 Make는 profile.toml의 proxmox.target_name, proxmox.bootstrap_vars, inventory.yml을 사용해 pve1에 접속합니다.
make proxmox/bootstrap SITE=tirosh-home
다른 Proxmox node를 지정해야 하면 실행 시 override합니다. 이 override는 일회성이고, profile.toml을 바꾸지는 않습니다.
make proxmox/bootstrap SITE=tirosh-home TARGET_NAME=pve2
반대로 어떤 site에서 항상 pve2를 기본 Proxmox node로 쓰고 싶다면 profile.toml의 proxmox.target_name을 바꿉니다.
2-2. inventory 등록¶
Proxmox node는 Ansible이 SSH로 접속해야 하는 물리 host입니다. 그래서 inventory.toml의 baremetals에 등록합니다.
[baremetals.pve1]
ansible_host = "192.168.219.250"
ansible_user = "root"
ansible_become_user = "root"
workloads = ["proxmox"]
여기서 pve1은 사람이 부르는 host alias입니다. Make의 TARGET_NAME=pve1과 Ansible의 --limit pve1이 이 이름을 사용합니다.
각 필드의 의미는 아래와 같습니다.
| key | 의미 |
|---|---|
ansible_host |
실제 SSH 접속 주소 |
ansible_user |
SSH 로그인 계정 |
ansible_become_user |
권한 상승 후 작업을 실행할 계정 |
workloads |
이 host가 어떤 Ansible group에 들어갈지 정하는 source |
workloads = ["proxmox"]는 해당 host를 Ansible proxmox group에 넣기 위한 선언입니다. 사람이 직접 inventory.yml의 group hierarchy를 편집하지 않고, source인 inventory.toml을 수정한 뒤 렌더링합니다.
make site/inventory/render SITE=tirosh-home
렌더링 후 inventory.yml에는 아래 group이 생겨야 합니다.
proxmox:
hosts:
pve1: {}
정리하면 inventory.toml은 사람이 편집하는 입력이고, inventory.yml은 Ansible이 읽는 출력입니다. Proxmox node IP나 SSH 계정이 바뀌면 inventory.toml을 수정한 뒤 반드시 다시 렌더링합니다.
3. Proxmox node bootstrap¶
bootstrap은 Proxmox node 자체의 repository와 host package를 준비합니다.
make proxmox/bootstrap SITE=tirosh-home ASK_PASS=true
3-1. bootstrap 설정¶
설정은 sites/<site_id>/proxmox/bootstrap.vars.yml에서 관리합니다.
proxmox_disable_enterprise_repository: true
proxmox_enable_no_subscription_repository: true
proxmox_manage_ceph_repository: true
proxmox_ceph_release: squid
proxmox_disable_ceph_enterprise_repository: true
proxmox_enable_ceph_no_subscription_repository: false
proxmox_bootstrap_packages:
- libguestfs-tools
proxmox_bootstrap_required_commands:
- qm
- sha256sum
- awk
- virt-customize
기본 bootstrap은 아래 작업을 수행합니다.
- Proxmox enterprise repository 비활성화
- Proxmox no-subscription repository 활성화
- Ceph enterprise repository 비활성화
- template 생성에 필요한 package 설치
qm,virt-customize같은 필수 command 확인
Proxmox subscription을 사용하는 운영 환경에서는 enterprise repository를 끄지 않도록 설정합니다.
proxmox_disable_enterprise_repository: false
proxmox_enable_no_subscription_repository: false
3-2. 로컬 실행 환경¶
bootstrap과 template 생성은 Ansible이 필요합니다.
brew install ansible
SSH password를 사용할 경우 로컬에 sshpass도 필요합니다.
# macOS
brew install hudochenkov/sshpass/sshpass
# Debian/Ubuntu
sudo apt install sshpass
SSH key를 사용한다면 inventory.toml 또는 렌더링된 inventory.yml에 ansible_ssh_private_key_file을 넣어 password prompt 없이 실행할 수 있습니다.
4. Ubuntu cloud template¶
Ubuntu cloud image 기반 template은 VM clone의 기준점입니다. OpenTofu가 VM을 만들 때는 매번 OS image를 새로 설치하지 않고, Proxmox에 미리 만들어 둔 template을 clone합니다.
Ubuntu cloud image
|
v
image customize
qemu-guest-agent, SSH 설정, clone state 정리
|
v
Proxmox VM 생성
disk import, cloud-init drive, guest agent option
|
v
VM template 변환
|
v
OpenTofu VM clone
이 단계의 목표는 “clone해도 안전한 VM 원본”을 만드는 것입니다. template 안에는 VM별로 달라져야 하는 값, 예를 들어 machine-id, SSH host key, cloud-init state, IP 주소, user password를 고정으로 남기지 않습니다. VM별 값은 clone 시점에 cloud-init으로 주입합니다.
make proxmox/template/apply SITE=tirosh-home ASK_PASS=true
4-1. template 변수¶
설정은 sites/<site_id>/proxmox/ubuntu-cloud-template.vars.yml에서 관리합니다.
이 파일은 “어떤 Ubuntu image를 가져와서, Proxmox의 어느 storage와 bridge를 사용해, 어떤 VM ID/name으로 template을 만들지”를 정합니다.
proxmox_storage: local-lvm
proxmox_cloudinit_storage: local-lvm
proxmox_bridge: vmbr0
template_id: 9001
template_name: ubuntu-cloud
template_memory: 2048
template_cores: 2
자주 보는 값은 아래처럼 이해하면 됩니다.
| key | 의미 |
|---|---|
proxmox_storage |
imported disk가 들어갈 Proxmox storage |
proxmox_cloudinit_storage |
cloud-init drive가 들어갈 Proxmox storage |
proxmox_bridge |
template VM의 기본 network bridge |
template_id |
Proxmox template VM ID |
template_name |
Proxmox에 표시될 template 이름 |
template_memory |
template VM 기본 memory |
template_cores |
template VM 기본 CPU core 수 |
여기서 설정한 값은 template 자체의 기본값입니다. 실제 clone VM의 CPU, memory, disk, IP, bridge는 vms.tfvars에서 VM별로 다시 지정할 수 있습니다.
대상 Proxmox node에는 아래 command가 필요합니다. bootstrap을 먼저 실행했다면 보통 준비되어 있습니다.
qmsha256sumawkvirt-customize
virt-customize는 cloud image 안에 package를 넣거나 파일을 수정하는 데 사용합니다. Debian/Ubuntu 기반 Proxmox node에서는 보통 libguestfs-tools 패키지에 포함됩니다.
4-2. template 생성 작업¶
infra/ansible/playbooks/proxmox/ubuntu-cloud-template.yml은 아래 작업을 수행합니다.
- Ubuntu cloud image 다운로드
- image checksum 검증
qemu-guest-agent설치- clone별로 달라져야 하는 image state 정리
- SSH password authentication 활성화
- Proxmox VM 생성
- disk import
- cloud-init 기본값 설정
- guest agent와 disk 기본 option 설정
- VM template 변환
실행 결과는 Proxmox UI에서 template_name으로 보이는 VM template입니다. 이후 OpenTofu VM workflow는 이 template ID를 참조해서 clone VM을 만듭니다.
template 생성은 idempotent하게 동작하도록 설계되어 있습니다. 이미 custom image cache가 있으면 기본적으로 다시 커스터마이징하지 않습니다. template 설정을 바꿨고 기존 cache를 버리고 싶으면 site vars에서 켭니다.
template_rebuild_custom_image: true
기존 Proxmox template 자체를 자동 삭제하거나 교체하지는 않습니다. 운영 중인 VM이 어떤 template에서 만들어졌는지 추적하기 쉽도록, template 교체가 필요하면 기존 template을 확인한 뒤 수동으로 삭제하거나 새 template_id/template_name을 사용합니다.
4-3. image 정리 기준¶
template 생성 전에 clone별로 달라져야 하는 값을 정리합니다.
/etc/machine-id/var/lib/dbus/machine-id- SSH host keys
- cloud-init state and logs
- persistent udev network rule
- apt cache and package lists
- temporary files
machine-id는 비워둔 상태로 template에 넣습니다. clone된 VM의 첫 부팅 시 systemd/cloud-init이 새 값을 생성합니다.
DHCP client-id/DUID가 machine-id 기반이면 clone 간 IP 충돌이 날 수 있습니다. template은 systemd-networkd DUID를 NIC MAC 기반으로 설정합니다.
template_clean_machine_id: true
template_configure_networkd_dhcp_duid: true
template_networkd_dhcp_duid_type: link-layer
SSH host keys도 삭제합니다. clone된 VM은 첫 부팅 과정에서 새 host key를 생성합니다.
이 정리 작업을 하지 않으면 여러 clone VM이 같은 machine-id, 같은 SSH host key, 같은 cloud-init state를 공유할 수 있습니다. 그런 상태는 DHCP lease 충돌, SSH host key 경고, cloud-init 재실행 실패처럼 나중에 보기 어려운 문제로 이어집니다.
특별한 이유로 image 정리를 끄고 싶다면 site vars에서 설정할 수 있습니다.
template_clean_image: false
4-4. disk와 boot option¶
현재 기본값은 cloud image template에 무난한 값만 켭니다.
template_agent_options: enabled=1,fstrim_cloned_disks=1template_scsi_controller: virtio-scsi-pcitemplate_disk_discard: "on"template_disk_ssd: truetemplate_disk_iothread: falsetemplate_disk_cache: ""
discard=on은 thin provisioning storage에서 guest의 TRIM 정보를 storage로 전달하는 데 도움이 됩니다.
ssd=1은 guest에 disk를 SSD처럼 보이게 합니다. 현장 storage가 HDD 중심이거나 이 옵션을 원하지 않으면 site vars에서 template_disk_ssd: false로 바꿉니다.
iothread=1은 기본으로 켜지 않습니다. Proxmox에서 SCSI disk에 IO thread를 쓰려면 template_scsi_controller: virtio-scsi-single 조합이 필요하므로, 명확히 필요할 때만 site vars에서 둘 다 켭니다.
정리하면 기본값은 “얇게 provision되는 local-lvm 같은 storage에서 무난하고 예측 가능한 template”에 맞춰져 있습니다. 성능 튜닝은 storage 종류와 workload가 명확해진 뒤 VM별 또는 site별로 조정합니다.
4-5. network와 SSH password¶
network는 Ubuntu cloud image의 기본 netplan 설정을 유지합니다. 50-cloud-init.yaml을 지우면 환경에 따라 DHCP가 늦거나 실패할 수 있습니다.
template 단계에서는 고정 IP를 박아 넣지 않습니다. template은 여러 VM의 원본이므로 특정 IP를 넣으면 clone들이 같은 주소를 가지게 됩니다. VM별 고정 IP는 vms.tfvars에서 cloud-init network 값으로 지정합니다.
systemd-networkd-wait-online.service는 기본으로 비활성화합니다. 이 서비스는 DHCP나 network-online 판정이 늦을 때 부팅을 오래 붙잡을 수 있습니다. 네트워크 자체를 끄는 설정은 아니며, cloud-init/networkd의 DHCP 설정은 그대로 유지합니다.
template_disable_network_wait_online: true
사내망 운영 편의를 위해 기본 template은 SSH password authentication을 켭니다.
template_enable_ssh_password_auth: true
이 설정은 guest의 cloud-init과 SSH daemon이 password authentication을 받을 수 있게 하는 설정입니다. 실제 password는 template에 저장하지 않고, VM clone 시 cloud-init 계정에 주입합니다.
즉 password 관련 책임은 아래처럼 나뉩니다.
template
SSH password authentication 허용
VM clone
cloud-init user/password 주입
OpenTofu state
password를 넣는 경우 민감정보 접근 권한 관리 필요
password auth를 끄려면 site vars에서 설정합니다.
template_enable_ssh_password_auth: false
clone VM에서 적용 여부를 확인하려면 VM console에서 실행합니다.
sudo sshd -T | grep -E 'passwordauthentication|kbdinteractiveauthentication'
sudo passwd -S <cloud-init-user>
cloud-init status --wait
기대값은 passwordauthentication yes이고, cloud-init user의 password 상태가 locked가 아니어야 합니다.
4-6. template 확인과 재실행¶
template이 만들어졌는지 Proxmox node에서 확인할 수 있습니다.
qm config <template-id>
template을 다시 만들어야 할 때는 먼저 기존 template이 사용 중인지 확인합니다. 삭제해도 되는 template임을 확인한 뒤 Proxmox에서 수동 cleanup을 수행하고, 같은 site 설정으로 template 생성 playbook을 다시 실행합니다.
make proxmox/template/apply SITE=tirosh-home
template 생성이 끝난 뒤 바로 VM을 만들려면 다음 단계의 OpenTofu workflow로 넘어갑니다.
5. VM catalog와 OpenTofu¶
VM 생성은 sites/<site_id>/vms.tfvars의 catalog를 기준으로 합니다. Proxmox API endpoint, node, 기본 datastore 같은 공통 변수는 sites/<site_id>/proxmox/vars.tfvars에 둡니다.
sites/tirosh-home/
vms.tfvars
proxmox/
vars.tfvars
vms.secrets.tfvars
5-1. VM 선언¶
예시는 Argo CD management cluster용 VM입니다.
vms = {
argocd = {
name = "argocd"
vm_id = 1001
tags = ["ubuntu", "k3s", "argocd"]
cpu_cores = 4
memory_mb = 4096
disk = {
datastore_id = "local-lvm"
size_gb = 40
}
network = {
bridge = "vmbr1"
}
ipv4 = {
address = "172.31.0.10/24"
gateway = "172.31.0.1"
}
dns_servers = [
"172.31.0.1",
"1.1.1.1",
]
user_account = {
username = "tirosh"
}
}
}
VM별 고정 IP는 cloud-init network 설정으로 들어갑니다. VM이 만들어진 뒤 Ansible이 이 VM에 접속해야 한다면 inventory.toml의 ansible_host도 같은 IP로 맞춥니다.
5-2. plan과 apply¶
처음 실행하거나 provider lock/workspace가 바뀐 경우 init을 실행합니다.
make proxmox/vms/init SITE=tirosh-home
변경 내용을 확인합니다.
make proxmox/vms/plan SITE=tirosh-home
문제가 없으면 적용합니다.
make proxmox/vms/apply SITE=tirosh-home
5-3. secret과 state¶
Proxmox API token이나 VM password는 vms.tfvars에 직접 넣지 않습니다. 기본 경로는 아래 파일입니다.
sites/tirosh-home/proxmox/vms.secrets.tfvars
예시는 아래 파일에서 확인합니다.
sites/tirosh-home/proxmox/vms.secrets.tfvars.example
OpenTofu state는 현재 local backend를 사용합니다. state에는 provider가 관리하는 민감한 값이 남을 수 있으므로 git에 커밋하지 않고, 접근 권한을 따로 관리합니다.
6. 문제 확인¶
작업이 실패하면 어떤 계층에서 실패했는지 먼저 분리합니다.
6-1. Ansible 접속 확인¶
bootstrap/template 단계가 실패하면 먼저 Proxmox node SSH 접속과 inventory target을 확인합니다.
make proxmox/bootstrap SITE=tirosh-home TARGET_NAME=pve1 ASK_PASS=true
TARGET_NAME은 inventory.yml의 host alias와 매칭됩니다. source는 inventory.toml이므로 host를 추가하거나 IP를 바꾼 뒤에는 inventory를 다시 렌더링합니다.
make site/inventory/render SITE=tirosh-home
6-2. template 교체¶
custom image cache가 이미 있으면 playbook은 기본적으로 다시 커스터마이징하지 않습니다. template 설정을 바꿨고 기존 cache를 버리고 싶으면 site vars에서 켭니다.
template_rebuild_custom_image: true
기존 Proxmox template 자체의 갱신은 자동으로 처리하지 않습니다. 운영 중인 VM이 어떤 template에서 만들어졌는지 추적하기 쉽도록, template 교체가 필요하면 Proxmox에서 기존 template을 확인한 뒤 수동으로 삭제하거나 새 template_id/template_name을 사용합니다.
qm config <template-id>
삭제해도 되는 template임을 확인한 뒤 template 생성 playbook을 다시 실행합니다.
make proxmox/template/apply SITE=tirosh-home
6-3. VM 생성 실패¶
VM plan/apply가 실패하면 Proxmox API credential, template ID, datastore, bridge, VM ID 충돌을 확인합니다.
make proxmox/vms/plan SITE=tirosh-home
VM 생성 후 SSH 접속이 안 되면 아래 순서로 확인합니다.
vms.tfvars의ipv4.address- Proxmox VM Cloud-Init 탭
- VM console의
ip addr inventory.toml의ansible_hostmake site/inventory/render SITE=tirosh-home실행 여부
7. 다음 단계¶
7-1. 후속 workflow¶
VM이 준비되면 목적에 맞는 상위 workflow를 진행합니다.
- Argo CD management VM: Argo CD on k3s
- bare-metal 또는 VM static IP 변경: Host Network
- RKE2 GPU workload cluster: RKE2 GPU Cluster