- Added GPU passthrough configuration for NVIDIA GTX 1070 - Dynamic hostpci block with OVMF BIOS and q35 machine type - EFI disk support when GPU is enabled - Configurable via enable_gpu_passthrough and gpu_pci_id variables - Added NFS mount support for Proxmox host media directories - Mounts 11 media directories from Proxmox host to VM - Configurable source path and mount point - Persistent mounts via /etc/fstab - NFS client installation via cloud-init - Added multi-OS support (Ubuntu, AlmaLinux, Debian) - Separate cloud-init templates for Ubuntu and AlmaLinux - OS-specific package installation (apt vs dnf) - OS type validation via variable - Updated terraform.tfvars.example with new configuration options - Updated README.md with comprehensive documentation: - AlmaLinux cloud template creation steps - GPU passthrough setup for AMD Ryzen + NVIDIA - NFS server configuration on Proxmox host - Troubleshooting for GPU and NFS issues
289 lines
14 KiB
HCL
289 lines
14 KiB
HCL
terraform {
|
|
required_version = ">= 1.6"
|
|
|
|
required_providers {
|
|
proxmox = {
|
|
source = "bpg/proxmox"
|
|
version = "~> 0.50"
|
|
}
|
|
}
|
|
}
|
|
|
|
provider "proxmox" {
|
|
endpoint = var.pm_api_url
|
|
|
|
api_token = var.pm_api_token_secret != "" ? "${var.pm_api_token_id}=${var.pm_api_token_secret}" : null
|
|
|
|
# For self-signed certificates
|
|
insecure = var.pm_tls_insecure
|
|
|
|
ssh {
|
|
agent = true
|
|
}
|
|
}
|
|
|
|
resource "proxmox_virtual_environment_vm" "docker_host" {
|
|
name = var.vm_name
|
|
description = "Docker host for homelab services - Managed by OpenTofu"
|
|
node_name = var.proxmox_node
|
|
|
|
# Clone from template (must exist in Proxmox)
|
|
clone {
|
|
vm_id = var.template_vm_id
|
|
full = true
|
|
}
|
|
|
|
# BIOS type - OVMF required for GPU passthrough
|
|
bios = var.enable_gpu_passthrough ? "ovmf" : "seabios"
|
|
|
|
# Machine type - q35 required for GPU passthrough
|
|
machine = var.enable_gpu_passthrough ? "q35" : "pc"
|
|
|
|
# CPU configuration
|
|
cpu {
|
|
cores = var.vm_cores
|
|
type = "host" # Use host CPU type for best performance
|
|
}
|
|
|
|
# Memory configuration
|
|
memory {
|
|
dedicated = var.vm_memory
|
|
}
|
|
|
|
# EFI disk (required for OVMF BIOS when GPU passthrough is enabled)
|
|
dynamic "efi_disk" {
|
|
for_each = var.enable_gpu_passthrough ? [1] : []
|
|
content {
|
|
datastore_id = var.storage
|
|
type = "4m"
|
|
}
|
|
}
|
|
|
|
# GPU passthrough configuration
|
|
dynamic "hostpci" {
|
|
for_each = var.enable_gpu_passthrough ? [1] : []
|
|
content {
|
|
device = "hostpci0"
|
|
mapping = var.gpu_pci_id
|
|
pcie = true
|
|
rombar = true
|
|
xvga = false
|
|
}
|
|
}
|
|
|
|
# Network interface
|
|
network_device {
|
|
bridge = var.network_bridge
|
|
model = "virtio"
|
|
}
|
|
|
|
# Disk configuration
|
|
disk {
|
|
datastore_id = var.storage
|
|
size = var.disk_size
|
|
interface = "scsi0"
|
|
discard = "on" # Enable TRIM for SSDs
|
|
iothread = true
|
|
}
|
|
|
|
# Cloud-init configuration
|
|
initialization {
|
|
ip_config {
|
|
ipv4 {
|
|
address = var.vm_ip_address == "dhcp" ? "dhcp" : "${var.vm_ip_address}/${var.vm_ip_netmask}"
|
|
gateway = var.vm_gateway
|
|
}
|
|
}
|
|
|
|
user_account {
|
|
username = var.vm_username
|
|
keys = var.vm_ssh_keys
|
|
password = var.vm_password
|
|
}
|
|
|
|
user_data_file_id = proxmox_virtual_environment_file.cloud_init_user_data.id
|
|
}
|
|
|
|
# Start VM on boot
|
|
on_boot = true
|
|
|
|
# Tags for organization
|
|
tags = ["terraform", "docker", "homelab"]
|
|
}
|
|
|
|
# Cloud-init user data for Docker installation
|
|
resource "proxmox_virtual_environment_file" "cloud_init_user_data" {
|
|
content_type = "snippets"
|
|
datastore_id = "local"
|
|
node_name = var.proxmox_node
|
|
|
|
source_raw {
|
|
data = var.vm_os_type == "almalinux" ? local.cloud_init_almalinux : local.cloud_init_ubuntu
|
|
|
|
file_name = "cloud-init-docker-${var.vm_name}.yaml"
|
|
}
|
|
}
|
|
|
|
# Cloud-init configuration for Ubuntu
|
|
locals {
|
|
cloud_init_ubuntu = <<-EOF
|
|
#cloud-config
|
|
hostname: ${var.vm_name}
|
|
manage_etc_hosts: true
|
|
|
|
# Install Docker and dependencies
|
|
package_update: true
|
|
package_upgrade: true
|
|
|
|
packages:
|
|
- apt-transport-https
|
|
- ca-certificates
|
|
- curl
|
|
- gnupg
|
|
- lsb-release
|
|
- git
|
|
- vim
|
|
- htop
|
|
- net-tools
|
|
${var.mount_media_directories ? "- nfs-common" : ""}
|
|
|
|
# Docker installation and NFS mount setup
|
|
runcmd:
|
|
# Install Docker
|
|
- mkdir -p /etc/apt/keyrings
|
|
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
- chmod a+r /etc/apt/keyrings/docker.gpg
|
|
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
- apt-get update
|
|
- apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
- systemctl enable docker
|
|
- systemctl start docker
|
|
- usermod -aG docker ${var.vm_username}
|
|
- docker network create homelab || true
|
|
|
|
# Create media directories
|
|
- mkdir -p ${var.media_mount_path}/{audiobooks,books,comics,complete,downloads,homemovies,incomplete,movies,music,photos,tv}
|
|
|
|
${var.mount_media_directories ? "# Mount NFS shares from Proxmox host" : ""}
|
|
${var.mount_media_directories ? "- systemctl enable nfs-client.target" : ""}
|
|
${var.mount_media_directories ? "- systemctl start nfs-client.target" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/audiobooks ${var.media_mount_path}/audiobooks" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/books ${var.media_mount_path}/books" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/comics ${var.media_mount_path}/comics" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/complete ${var.media_mount_path}/complete" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/downloads ${var.media_mount_path}/downloads" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/homemovies ${var.media_mount_path}/homemovies" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/incomplete ${var.media_mount_path}/incomplete" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/movies ${var.media_mount_path}/movies" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/music ${var.media_mount_path}/music" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/photos ${var.media_mount_path}/photos" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/tv ${var.media_mount_path}/tv" : ""}
|
|
|
|
- chown -R ${var.vm_username}:${var.vm_username} ${var.media_mount_path}
|
|
- chmod -R 755 ${var.media_mount_path}
|
|
|
|
${var.clone_homelab_repo ? "- su - ${var.vm_username} -c 'cd ~ && git clone https://github.com/${var.github_username}/homelab.git'" : ""}
|
|
|
|
${var.mount_media_directories ? "# Make NFS mounts persistent" : ""}
|
|
${var.mount_media_directories ? "write_files:" : ""}
|
|
${var.mount_media_directories ? " - path: /etc/fstab" : ""}
|
|
${var.mount_media_directories ? " append: true" : ""}
|
|
${var.mount_media_directories ? " content: |" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/audiobooks ${var.media_mount_path}/audiobooks nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/books ${var.media_mount_path}/books nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/comics ${var.media_mount_path}/comics nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/complete ${var.media_mount_path}/complete nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/downloads ${var.media_mount_path}/downloads nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/homemovies ${var.media_mount_path}/homemovies nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/incomplete ${var.media_mount_path}/incomplete nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/movies ${var.media_mount_path}/movies nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/music ${var.media_mount_path}/music nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/photos ${var.media_mount_path}/photos nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/tv ${var.media_mount_path}/tv nfs defaults 0 0" : ""}
|
|
|
|
# Set timezone
|
|
timezone: ${var.vm_timezone}
|
|
|
|
# Reboot after setup
|
|
power_state:
|
|
mode: reboot
|
|
condition: true
|
|
EOF
|
|
|
|
cloud_init_almalinux = <<-EOF
|
|
#cloud-config
|
|
hostname: ${var.vm_name}
|
|
manage_etc_hosts: true
|
|
|
|
# Install Docker and dependencies
|
|
package_update: true
|
|
package_upgrade: true
|
|
|
|
packages:
|
|
- curl
|
|
- ca-certificates
|
|
- git
|
|
- vim
|
|
- htop
|
|
- net-tools
|
|
${var.mount_media_directories ? "- nfs-utils" : ""}
|
|
|
|
# Docker installation and NFS mount setup
|
|
runcmd:
|
|
# Install Docker
|
|
- dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
|
- dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
- systemctl enable docker
|
|
- systemctl start docker
|
|
- usermod -aG docker ${var.vm_username}
|
|
- docker network create homelab || true
|
|
|
|
# Create media directories
|
|
- mkdir -p ${var.media_mount_path}/{audiobooks,books,comics,complete,downloads,homemovies,incomplete,movies,music,photos,tv}
|
|
|
|
${var.mount_media_directories ? "# Mount NFS shares from Proxmox host" : ""}
|
|
${var.mount_media_directories ? "- systemctl enable nfs-client.target" : ""}
|
|
${var.mount_media_directories ? "- systemctl start nfs-client.target" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/audiobooks ${var.media_mount_path}/audiobooks" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/books ${var.media_mount_path}/books" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/comics ${var.media_mount_path}/comics" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/complete ${var.media_mount_path}/complete" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/downloads ${var.media_mount_path}/downloads" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/homemovies ${var.media_mount_path}/homemovies" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/incomplete ${var.media_mount_path}/incomplete" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/movies ${var.media_mount_path}/movies" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/music ${var.media_mount_path}/music" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/photos ${var.media_mount_path}/photos" : ""}
|
|
${var.mount_media_directories ? "- mount -t nfs ${var.proxmox_host_ip}:${var.media_source_path}/tv ${var.media_mount_path}/tv" : ""}
|
|
|
|
- chown -R ${var.vm_username}:${var.vm_username} ${var.media_mount_path}
|
|
- chmod -R 755 ${var.media_mount_path}
|
|
|
|
${var.clone_homelab_repo ? "- su - ${var.vm_username} -c 'cd ~ && git clone https://github.com/${var.github_username}/homelab.git'" : ""}
|
|
|
|
${var.mount_media_directories ? "# Make NFS mounts persistent" : ""}
|
|
${var.mount_media_directories ? "write_files:" : ""}
|
|
${var.mount_media_directories ? " - path: /etc/fstab" : ""}
|
|
${var.mount_media_directories ? " append: true" : ""}
|
|
${var.mount_media_directories ? " content: |" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/audiobooks ${var.media_mount_path}/audiobooks nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/books ${var.media_mount_path}/books nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/comics ${var.media_mount_path}/comics nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/complete ${var.media_mount_path}/complete nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/downloads ${var.media_mount_path}/downloads nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/homemovies ${var.media_mount_path}/homemovies nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/incomplete ${var.media_mount_path}/incomplete nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/movies ${var.media_mount_path}/movies nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/music ${var.media_mount_path}/music nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/photos ${var.media_mount_path}/photos nfs defaults 0 0" : ""}
|
|
${var.mount_media_directories ? " ${var.proxmox_host_ip}:${var.media_source_path}/tv ${var.media_mount_path}/tv nfs defaults 0 0" : ""}
|
|
|
|
# Set timezone
|
|
timezone: ${var.vm_timezone}
|
|
|
|
# Reboot after setup
|
|
power_state:
|
|
mode: reboot
|
|
condition: true
|
|
EOF
|
|
}
|