Creando Máquinas Virtuales en Proxmox con Terraform
Tabla de contenido
Como bien sabemos, Terraform es nuestra herramienta predilecta de infraestructura como código que nos permite desplegar recursos con distintos proveedores de servicio. Esto lo logra utilizando los Providers de Terraform que no es mas que una interfaz en la cual usa la API de los proveedores de computación en la nube, como AWS, o en servicios on-premise como Proxmox o VMWare.
Lamentablemente, a la fecha de hoy no hay provider oficial de Proxmox asi que estaremos utilizando el Provider Telmate. Esta, sin embargo, es lo suficientemente estable para poder hacer despliegues en al comodidad de nuestro homelab.
PROMO DigitalOcean #
Antes de comenzar, quería contarles que hay una promoción en DigitalOcean donde te dan un crédito de USD 100.00 durante 60 días para que puedas probar los servicios que este Proveedor Cloud ofrece. Lo único que tienes que hacer es suscribirte a DigitalOcean con el siguiente botón:
O a través del siguiente enlace: https://bit.ly/digitalocean-itsm
Instalando Terraform #
Podemos instalar Terraform en la mayoría de los Sistemas Operativos mas comunes, pero, para el propósito de este post, lo instalaré en mi distro Fedora 38:
- Instalamos dependencias:
sudo dnf install -y dnf-plugins-core
- Agregamos el repositorio oficial:
sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/fedora/hashicorp.repo
- Instalamos Terraform:
sudo dnf -y install terraform
Para mas métodos de instalación, les dejo la Documentación de Terraform: https://developer.hashicorp.com/terraform/downloads
Preparando Proxmox #
Configuremos nuestro host de Proxmox para permitir que Terraform pueda conectarse e el a través de la API y desplegar nuestra máquina virtual. Lo primero que haremos es crear un Rol que se llame terraform-role
con los privilegios adecuados, que son los siguientes:
- Datastore.AllocateSpace
- Datastore.Audit
- VM.Allocate
- VM.Audit
- VM.Clone
- VM.Config.CDROM
- VM.Config.CPU
- VM.Config.Cloudinit
- VM.Config.Disk
- VM.Config.HWType
- VM.Config.Memory
- VM.Config.Network
- VM.Config.Options
- VM.Monitor
- VM.PowerMgmt
Si lo hacemos por la UI de Proxmox, tenemos que ir a en el Menu Datacenter -> Permissions -> Roles y luego Create:
Y ahi tendremos nuestro Rol creado:
Por la linea de comandos el equivalente seria el siguiente:
pveum role add terraform-role -privs "VM.Allocate VM.Clone VM.Config.CDROM VM.Config.CPU VM.Config.Cloudinit VM.Config.Disk VM.Config.HWType VM.Config.Memory VM.Config.Network VM.Config.Options VM.Monitor VM.Audit VM.PowerMgmt Datastore.AllocateSpace Datastore.Audit"
Lo siguiente será crear el usuario terraform
, por la UI vamos al menu Permissions -> Users:
Por la CLI:
pveum user add terraform@pve
Asignamos los permisos del rol terraform-role
al usuario terraform@pve
, para esto vamos a Permissions -> Add -> User Permission:
Por la CLI:
pveum aclmod / -user terraform@pve -role terraform-role
Lo comprobamos yendo a Permissions -> Users, selecionar el usuario terraform
y damos click en el botón Permissiones en la parte superior:
Y creamos el Token que nos servirá para autenticarnos contra Proxmox, por la UI en el menú Permissions -> API Tokens:
Nos mostrará una sola vez el Token obtenido, debemos reservarlo en un lugar seguro y ser tratado como dato sensible.
Por la CLI:
pveum user token add terraform@pve terraform-token --privsep=0
Después de ejecutar los comandos, obtendremos el Token, debemos reservarlo en un lugar seguro y debe ser tratado como dato sensible:
┌──────────────┬──────────────────────────────────────┐
│ key │ value │
╞══════════════╪══════════════════════════════════════╡
│ full-tokenid │ terraform@pve!terraform-token │
├──────────────┼──────────────────────────────────────┤
│ info │ {"privsep":"0"} │
├──────────────┼──────────────────────────────────────┤
│ value │ XXXXX-XXXXX-XXXXX-XXXXX-XXXXX │
└──────────────┴──────────────────────────────────────┘
Codeando las Recetas #
Desplegaremos la MV desde nuestra máquina local, por lo que vamos a crear una carpeta donde vamos a almacenar nuestras recetas de Terraform, por ejemplo, terraform-proxmox
y dentro de esta carpeta crearemos 4 archivos a lo menos: main.tf
, variables.tf
, provider.tf
y terraform.tfvars
:
terraform-proxmox
├── main.tf
├── provider.tf
├── terraform.tfvars
└── variables.tf
En el archivo terraform.tfvars
vamos a guardar las variables sensibles, como usuario y token de Proxmox, el cual debemos excluir de subir a cualquier servicio de almacenamiento de código como GitLab, GitHub, etc.
proxmox_api_url = "https://ip-nodo-proxmox:8006/api2/json"
proxmox_user = "terraform@pve!terraform"
proxmox_token = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"
En el archivo provider.tf
vamos a invocar el proveedor que nos permitirá conectarnos a nuestro host de Proxmox y la versión requerida de Terraform:
# Provider information
terraform {
required_version = ">= 0.15.0"
required_providers {
proxmox = {
source = "Telmate/proxmox"
version = "2.9.11"
}
}
}
# Configuration options
provider "proxmox" {
pm_api_url = var.proxmox_api_url
pm_api_token_id = var.proxmox_user
pm_api_token_secret = var.proxmox_token
pm_tls_insecure = true
pm_log_enable = true
pm_log_file = "terraform-plugin-proxmox.log"
pm_log_levels = {
_default = "debug"
_capturelog = ""
}
}
Necesitaremos declarar una serie de variables que se utilizarán para la configuración de los parámetros de la MV (como cpu, memoria, nodo donde vamos a levantarla, etc.). Esto iria en el archivo variables.tf
:
variable "proxmox_node" {
type = string
default = "pve"
description = "Proxmox host address"
}
variable "proxmox_api_url" {
type = string
default = ""
description = "Proxmox API URL"
sensitive = true
}
variable "proxmox_user" {
type = string
default = ""
description = "Proxmox user"
sensitive = true
}
variable "proxmox_token" {
type = string
default = ""
description = "Proxmox token"
sensitive = true
}
variable "ssh_key_terraform" {
type = string
default = "LLAVE-SSH-PUBLICA"
description = "Public ssh node key"
}
variable "template_name" {
type = string
default = "ubuntu-2204-cloudinit-template"
description = "OS Template"
}
Como puedes observar, en cada valor de variable tenemos el argumento default
, ahi colocaremos el valor por defecto de la variable. En el caso de las variables proxmox_api_url
, proxmox_user
y proxmox_token
las dejamos vacías ya que Terraform es suficientemente inteligente para detectar nuestras variables sensibles contenidas en el archivo terraform.tfvars
.
El argumento sensitive = true
permite que las mencionadas variables no aparezcan en los logs ni en el debug de la consola de Terraform.
En la variable template_name
, le estamos indicando a Terraform que use ese template de Ubuntu que ya tenemos en nuestro host de Proxmox para que cree la MV. Si quieres saber más como automatizar la construcción de templates con Packer, te dejo el siguiente artículo: https://blog.enmanuelmoreira.com/como-construir-una-imagen-de-ubuntu-22.04-para-proxmox-con-packer-y-subiquity/
Ahora bien, en el archivo main.tf
vamos a configurar los parametros de nuestra maquina virtual. Para instanciar un recurso, debemos utilizar la palabra reservada resource
con el tipo de recursos (en este caso instanciar la MV con proxmox_vm_qemu
), seguido del nombre de este recurso: ubuntu
:
resource "proxmox_vm_qemu" "ubuntu" {
name = "ubuntu-vm"
desc = "Nuestra primera maquina virtual"
vmid = "101"
target_node = var.proxmox_host
os_type = "cloud-init"
qemu_os = "l26"
clone = var.template_name
full_clone = true
# Que la maquina inicie automaticamente
oncreate = true
onboot = true
# Activamos agente de qemu por defecto
agent = 1
# Configuracion de CPU 1 socket, 2 nucleos
sockets = 1
cores = 2
cpu = "host"
memory = 2048
# Tipo de Red
network {
bridge = "vmbr0"
model = "virtio"
}
# Tipo de Disco y en cual medio de almacenamiento
disk {
type = "virtio"
storage = "local-lvm"
iothread = 0
size = "30G"
}
lifecycle {
ignore_changes = [
network,
]
}
ipconfig0 = "ip=192.168.110.20/24,gw=192.168.110.1"
nameserver = "8.8.8.8"
ciuser = "ubuntu"
sshkeys = <<EOF
${var.ssh_key_terraform}
EOF
tags = "ubuntu,mv,test"
}
Ejecutando Terraform #
Ahora que tenemos lo necesario, podemos proceder a inicializar la configuracion y finalmente desplegar nuestra maquina.
Inicializando Terraform #
Ejecutamos el comando terraform init
como primer paso. Este comando lo hará es descargar los archivos necesarios del Provider e inicializará la configuración de Terraform.
terraform init
Initializing the backend...
Initializing provider plugins...
- Finding telmate/proxmox versions matching "2.9.11"...
- Installing telmate/proxmox v2.9.11...
- Installed telmate/proxmox v2.9.11 (self-signed, key ID A9EBBE091B35AFCE)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
Planning #
Ya que hemos inicializado el proyecto, ejecutaremos el comando terraform plan
el cual nos entregará un resumen de todos los recursos que van a ser añadidos, actualizados o destruidos por Terraform.
Es buena idea guardar el plan en un archivo para poder analizar con mas detalles los cambios realizados, para ello podemos ejecutarlo con el argumento -out plan.txt
:
terraform plan -out plan.txt
Aplicando los Cambios #
Revisando el plan, finalmente aplicamos los cambios realizados con el comando terraform apply
Asumiendo que todo salió correcto, deberiamos poder recibir el siguiente output:
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Y de esta manera vemos que la MV se levantó exitosamente y verla desde la UI de Proxmox.
Limpiando la Casa #
Debemos deshacernos de la MV en caso que no la vayamos a utilizar, para esto debemos tener en cuenta que tenemos que estar en la misma carpeta de nuestro proyecto (en nuestro caso terraform-proxmox
) y eliminarla es simplemente ejecutar el comando:
terraform destroy
Nos pedirá confirmación y estarán los cambios realizados una vez nos muestre el siguiente mensaje:
Destroy complete! Resources: 1 destroyed.
Conclusión #
Terraform nos permite automatizar y guardar el estado actual de nuestra infraestructura en Proxmox y poder mantener nuestra flota de MV’s sin error humano y de manera homogénea.
Espero les haya gustado y nos vemos en la próxima!