Aller au contenu principal

Proxmox Infrastructure with Terraform

🔴Advanced Estimated duration: 60 minutes

This tutorial shows you how to deploy and manage a Proxmox VE infrastructure using Terraform and the claude-base tools.

Objectives​

By the end of this tutorial, you will know how to:

  • Use /ops:ops-proxmox to manage Proxmox
  • Use /ops:ops-infra-code for Infrastructure as Code
  • Create VMs and LXC containers with Terraform
  • Set up monitoring and backups

Prerequisites​

  • Proxmox VE server installed and accessible
  • Terraform installed locally
  • Proxmox API token created
  • Basic knowledge of virtualization

Context​

We will create a complete infrastructure including:

  • 2 Ubuntu VMs for a web application
  • 1 LXC container for the database
  • Network configuration with VLAN
  • Automated monitoring and backups

Step 1: Configure Proxmox access​

Create an API token​

In Proxmox:

  1. Datacenter > Permissions > API Tokens
  2. Create a token for your user
  3. Note the ID and the secret

Configure Terraform​

/ops:ops-infra-code "Configure the Proxmox provider with the bpg/proxmox provider"

providers.tf

terraform {
required_version = ">= 1.5.0"

required_providers {
proxmox = {
source = "bpg/proxmox"
version = "~> 0.50.0"
}
}
}

provider "proxmox" {
endpoint = var.proxmox_endpoint
api_token = var.proxmox_api_token
insecure = var.proxmox_insecure

ssh {
agent = true
username = "root"
}
}

variables.tf

variable "proxmox_endpoint" {
description = "Proxmox API URL"
type = string
}

variable "proxmox_api_token" {
description = "Proxmox API token (user@realm!token=secret)"
type = string
sensitive = true
}

variable "proxmox_insecure" {
description = "Skip SSL verification"
type = bool
default = false
}

variable "target_node" {
description = "Target Proxmox node"
type = string
default = "pve"
}

terraform.tfvars.example

proxmox_endpoint = "https://proxmox.example.com:8006"
proxmox_api_token = "root@pam!terraform=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
proxmox_insecure = true
target_node = "pve"

Step 2: Create the VMs with cloud-init​

/ops:ops-proxmox "Create 2 Ubuntu 22.04 VMs with cloud-init for a web application"

modules/vm/main.tf

resource "proxmox_virtual_environment_vm" "vm" {
name = var.name
node_name = var.node_name
vm_id = var.vm_id

tags = var.tags

agent {
enabled = true
}

cpu {
cores = var.cores
type = "x86-64-v2-AES"
}

memory {
dedicated = var.memory
}

disk {
datastore_id = var.datastore
file_id = var.cloud_image_id
interface = "scsi0"
size = var.disk_size
discard = "on"
ssd = true
}

network_device {
bridge = var.bridge
vlan_id = var.vlan_id
}

initialization {
ip_config {
ipv4 {
address = var.ip_address
gateway = var.gateway
}
}

user_account {
username = var.username
keys = var.ssh_keys
}

user_data_file_id = proxmox_virtual_environment_file.cloud_config.id
}

lifecycle {
ignore_changes = [
initialization[0].user_data_file_id,
]
}
}

resource "proxmox_virtual_environment_file" "cloud_config" {
content_type = "snippets"
datastore_id = "local"
node_name = var.node_name

source_raw {
data = <<-EOF
#cloud-config
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
- curl
- wget
- htop
runcmd:
- systemctl enable qemu-guest-agent
- systemctl start qemu-guest-agent
EOF

file_name = "${var.name}-cloud-config.yaml"
}
}

main.tf (root)

# Ubuntu cloud-init template
resource "proxmox_virtual_environment_download_file" "ubuntu_cloud_image" {
content_type = "iso"
datastore_id = "local"
node_name = var.target_node
url = "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img"
file_name = "ubuntu-22.04-cloudimg-amd64.img"
}

# Web VM 1
module "web_vm_1" {
source = "./modules/vm"

name = "web-01"
node_name = var.target_node
vm_id = 100
cores = 2
memory = 2048
disk_size = 20
datastore = "local-lvm"
cloud_image_id = proxmox_virtual_environment_download_file.ubuntu_cloud_image.id
bridge = "vmbr0"
vlan_id = 10
ip_address = "10.0.10.11/24"
gateway = "10.0.10.1"
username = "ubuntu"
ssh_keys = [file("~/.ssh/id_rsa.pub")]
tags = ["web", "production"]
}

# Web VM 2
module "web_vm_2" {
source = "./modules/vm"

name = "web-02"
node_name = var.target_node
vm_id = 101
cores = 2
memory = 2048
disk_size = 20
datastore = "local-lvm"
cloud_image_id = proxmox_virtual_environment_download_file.ubuntu_cloud_image.id
bridge = "vmbr0"
vlan_id = 10
ip_address = "10.0.10.12/24"
gateway = "10.0.10.1"
username = "ubuntu"
ssh_keys = [file("~/.ssh/id_rsa.pub")]
tags = ["web", "production"]
}

Step 3: Create the LXC container for the database​

/ops:ops-proxmox "Create an LXC container for PostgreSQL"

modules/lxc/main.tf

resource "proxmox_virtual_environment_container" "container" {
node_name = var.node_name
vm_id = var.vm_id

description = var.description
tags = var.tags

initialization {
hostname = var.hostname

ip_config {
ipv4 {
address = var.ip_address
gateway = var.gateway
}
}

user_account {
keys = var.ssh_keys
}
}

cpu {
cores = var.cores
}

memory {
dedicated = var.memory
swap = var.swap
}

disk {
datastore_id = var.datastore
size = var.disk_size
}

network_interface {
name = "eth0"
bridge = var.bridge
vlan_id = var.vlan_id
}

operating_system {
template_file_id = var.template_id
type = "ubuntu"
}

features {
nesting = true
}

unprivileged = true
start_on_boot = true
}

Add to main.tf

# Ubuntu LXC template
resource "proxmox_virtual_environment_download_file" "ubuntu_lxc_template" {
content_type = "vztmpl"
datastore_id = "local"
node_name = var.target_node
url = "http://download.proxmox.com/images/system/ubuntu-22.04-standard_22.04-1_amd64.tar.zst"
file_name = "ubuntu-22.04-standard_22.04-1_amd64.tar.zst"
}

# PostgreSQL container
module "db_container" {
source = "./modules/lxc"

node_name = var.target_node
vm_id = 200
hostname = "db-01"
description = "PostgreSQL Database Server"
cores = 2
memory = 4096
swap = 512
disk_size = 50
datastore = "local-lvm"
template_id = proxmox_virtual_environment_download_file.ubuntu_lxc_template.id
bridge = "vmbr0"
vlan_id = 20
ip_address = "10.0.20.11/24"
gateway = "10.0.20.1"
ssh_keys = [file("~/.ssh/id_rsa.pub")]
tags = ["database", "production"]
}

Step 4: Configure backups​

/ops:ops-backup "Configure automated Proxmox backups"

backup.tf

# Daily backup job
resource "proxmox_virtual_environment_cluster_backup" "daily_backup" {
schedule = "0 2 * * *" # Every day at 2am

backup_target_storage = "backup-storage"
compression = "zstd"
mode = "snapshot"
notification_mode = "failure"

vm_ids = [
module.web_vm_1.vm_id,
module.web_vm_2.vm_id,
module.db_container.vm_id,
]

retention {
daily = 7
weekly = 4
monthly = 3
}
}

Step 5: Add monitoring​

/ops:ops-monitoring "Add monitoring for the Proxmox infrastructure"

Installation script on each VM:

#!/bin/bash
# install-monitoring.sh

# Node Exporter for Prometheus
wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
tar xvfz node_exporter-1.7.0.linux-amd64.tar.gz
sudo mv node_exporter-1.7.0.linux-amd64/node_exporter /usr/local/bin/

# systemd service
cat <<EOF | sudo tee /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
After=network.target

[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter

[Install]
WantedBy=default.target
EOF

sudo useradd -rs /bin/false node_exporter
sudo systemctl daemon-reload
sudo systemctl enable node_exporter
sudo systemctl start node_exporter

Step 6: Deploy the infrastructure​

# Initialize Terraform
terraform init

# Check the plan
terraform plan

# Apply
terraform apply

Verify the deployment​

# List the created resources
terraform state list

# View the outputs
terraform output

# Connect to a VM
ssh ubuntu@10.0.10.11

Step 7: Useful outputs​

outputs.tf

output "web_vms" {
description = "Web VMs information"
value = {
web_01 = {
id = module.web_vm_1.vm_id
ip = "10.0.10.11"
name = "web-01"
}
web_02 = {
id = module.web_vm_2.vm_id
ip = "10.0.10.12"
name = "web-02"
}
}
}

output "db_container" {
description = "DB container information"
value = {
id = module.db_container.vm_id
ip = "10.0.20.11"
name = "db-01"
}
}

output "ssh_commands" {
description = "SSH commands to connect"
value = {
web_01 = "ssh ubuntu@10.0.10.11"
web_02 = "ssh ubuntu@10.0.10.12"
db_01 = "ssh root@10.0.20.11"
}
}

Step 8: Commit​

/work:work-commit

Suggested message:

feat(infra): add Proxmox infrastructure with Terraform

- Add provider configuration for bpg/proxmox
- Add VM module with cloud-init support
- Add LXC container module
- Create 2 web VMs and 1 database container
- Configure daily backups with retention policy
- Add monitoring setup with node_exporter

Final structure​

infrastructure/
├── main.tf # Main resources
├── providers.tf # Terraform configuration
├── variables.tf # Variables
├── outputs.tf # Outputs
├── terraform.tfvars # Values (not committed)
├── backup.tf # Backup configuration
├── modules/
│ ├── vm/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── lxc/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── scripts/
└── install-monitoring.sh

Useful commands​

CommandDescription
terraform planView the changes
terraform applyApply the changes
terraform destroyDestroy the infrastructure
terraform state listList the resources
terraform outputView the outputs

Next steps​


Infrastructure as Code

Always version your Terraform code and use a remote backend (S3, Consul) for the state when working as a team.