π₯οΈ Automated Virtual Machine Provisioning
This homelab supports two provisioning workflows for creating virtual machines on Proxmox:
- Pure Ansible provisioning
- Hybrid Terraform + Ansible provisioning
Both workflows produce the same final VM state. The difference is in how the VM is created and which tool manages the lifecycle. Everything after VM creation (cloudβinit, boot sequencing, cleanup, SSH hardening) is identical.
This page documents the architecture, workflow, and module/tooling used by each approach.
βIMPORTANT: Virtual Machine Templates Provisioning a virtual machine relies on using a virtual machine template that is cloned during provisioning. For more information on how virtual machine templates are generated, π see the Contributor Guide for Adding New Cloud-Init VM Templates.
π§ Provisioning Modes
| Mode | Description | When to Use |
|---|---|---|
| Ansibleβonly | Uses Proxmox API modules to clone and configure the VM directly. | Simple, transparent, minimal dependencies. |
| Terraform + Ansible | Terraform creates and configures the VM; Ansible handles cloudβinit and postβprovision tasks. | When you want declarative VM definitions and Terraform state. |
Both modes are fully supported.
π§ HighβLevel Workflow
Regardless of provisioning mode, the VM follows the same lifecycle:
βββββββββββββββββββββββββββββ
β Generate cloud-init β
β snippets β
β (user-data, meta-data) β
ββββββββββββββββ¬βββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Clone VM from template β
ββββββββββββββββ¬ββββββββββββ
β
β
β ββββββββββββββββββββββββββββββββ
ββββΆβ Optional: migrate VM to β
β correct node/storage β
ββββββββββββββββ¬ββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Attach cloud-init disk β
β (inject snippets) β
ββββββββββββββββ¬ββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Start VM β
β (cloud-init begins) β
ββββββββββββββββ¬ββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Wait for cloud-init to β
β complete β
ββββββββββββββββ¬ββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Remove cloud-init disk β
ββββββββββββββββ¬ββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Reboot VM β
β (finalize configuration) β
ββββββββββββββββ¬ββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββ
β Update known_hosts β
β (SSH trust bootstrap) β
ββββββββββββββββ¬ββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββ
β VM ready for postβprovision β
β (Python bootstrap, venv, β
β agents, config mgmt, etc.)β
βββββββββββββββββββββββββββββββ
π§± Shared Architecture
Both workflows use the same components:
CloudβInit
Used for firstβboot configuration:
- users and SSH keys
- packages
- network configuration
- write_files
- firstβboot commands
CloudβInit snippets are generated by Ansible in both workflows. For more information on how a Cloud-Init image is created,
π See: Cloud-Init
Boot Sequencing
After the VM exists:
- Start VM
- Wait for cloudβinit to finish
- Remove cloudβinit disk
- Reboot
- Update known_hosts
This ensures a stable, predictable VM state.
𧬠What Differs Between the Two Workflows
VM Creation
AnsibleβOnly
Uses the Proxmox API via:
community.proxmox.proxmox_kvmcommunity.proxmox.proxmox
Ansible performs:
- cloning
- CPU/RAM configuration
- disk/NIC configuration
- cloudβinit disk attachment
Terraform Workflow
Terraform performs:
- cloning
- hardware configuration
- cloudβinit disk attachment
- optional additional disks
Ansible takes over after the VM exists.
π¦ ProxmoxβRelated Modules
| Module | Purpose |
|---|---|
| community.proxmox.proxmox_kvm | Clone VMs, configure CPU/RAM/disks/NICs, manage cloudβinit, start/stop VMs |
| community.proxmox.proxmox | General Proxmox API interactions, node/storage queries, lifecycle operations |
π Provisioning Entry Point
The playbook that selects the provisioning mode:
playbooks/vms/provision_vm.yml
Selection logic:
vms_use_terraform: true # Terraform + Ansible
vms_use_terraform: false # Pure Ansible
This keeps the interface simple while allowing two backends.
π§© Contributor Notes
- Both workflows share the same cloudβinit, boot, cleanup, and SSH tasks.
- Only the VM creation step differs.
- New features should be added to both workflows unless they are specific to Terraform or Ansible.
- The role is intentionally modular: each step is its own task file.
- Terraform workflow is a dropβin alternative, not a fork.