Ir al contenido
  1. Posts/

Creando Máquinas Virtuales en Proxmox con Terraform

·1568 palabras·8 mins· loading · loading ·
Proxmox Terraform Infraestructura proxmox terraform infraestructura
Autor
Enmanuel Moreira
Ingeniero DevOps de día y aprendiz de Barman en mis tiempos libres, con experiencia en Kubernetes, Cloud, y DevOps. También disfruta de hacer stream de juegos, hablar de CI/CD, desplegar en producción un viernes con Terraform y automatizar tareas aburridas con Ansible.

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 200.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:

DigitalOcean Referral Badge

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:

Creando Rol
Creando Rol

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:

Creando usuario
Creando usuario

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:

Añadiendo Rol al Usuario terraform
Añadiendo Rol al Usuario terraform

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:

Creando Token
Creando Token

Nos mostrará una sola vez el Token obtenido, debemos reservarlo en un lugar seguro y ser tratado como dato sensible.

Creando Token
Creando Token

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!