Terraform+Proxmox, la experiencia en mi homelab, parte 3

En esta entrada veremos como interactuar con Terraform y los contenedores o CTs, como comúnmente los llamamos.

Nota: para este procedimiento se requiere la plantilla de CT de Debian11 para Proxmox, la cual se puede descargar por la interfaz de proxmox:

O por consola y copiarla en /var/lib/vz/template/cache:

wget -c http://download.proxmox.com/images/system/debian-11-standard_11.0-1_amd64.tar.gz -P /var/lib/vz/template/cache

Lo primero es crear una carpeta dónde vamos a trabajar, el nombre no importa cual sea, sólo que sea un identificativo para el trabajo que haremos. Crearemos un contenedor o CT, llamado test, que se encenderá automaticamente cuando encienda el sistema, y lo prepararemos para que haga ciertas funciones, que definiremos en un script que ejecutará después de que el CT esté completamente funcional.

mkdir test; cd test
nano providers.tf

Contenido:

terraform {
  required_providers {
    proxmox = {
      source  = "telmate/proxmox"
      version = "2.9.10"
    }
  }
}
# usando el provider
provider "proxmox" {
  pm_api_url = var.pve_host
  pm_user = var.pve_user
  pm_password = var.pve_pass
  pm_tls_insecure = true
}

Ahora bien, acá en providers.tf hemos definido el provider, que es el plugin telmate/proxmox, que ya descargamos y está en nuestro home, descrito en la parte 1 de esta serie.

Acá vemos también declaración de variables, que ahora mismo veremos donde están y cómo se usan. Para ello necesitaremos el archivo vars.tf:

nano vars.tf

Contenido:

# servidor proxmox, ajustar según las necesidades
variable "pve_host" {
  description = "Proxmox server"
  default = "https://192.168.0.250:8006/api2/json"
}
# usuario del proxmox
variable "pve_user" {
  description = "Proxmox username"
  type  = string
  sensitive = true
  default = "root@pam"
}
# password el proxmox se necesita para que terraform le pase parámetros por la API
variable "pve_pass" {
  description = "Proxmox password"
  type = string
  sensitive = true
  default = "ZmVjMjNQNmNlZpU2ZmQ2ZjkyNTMzZDdm"
}
# password del ct
variable "ct_pass" {
  description = "Container password"
  type = string
  sensitive = true
  default = "Admin*123"
}
# hostname del ct
variable "hostname" {
    default = "test"
}
# dns server
variable "dns_server" {
    default = "192.168.0.2"
}
# dominio
variable "dns_domain" {
    default = "inutil.cu"
}
# cat .ssh/id_rsa.pub
variable "ssh_key" {
  default = "ssh-rsa AAAAB3NzaC1yc2EAaAADAqABAAABgQCyQiMi2HhPtLRS+HFCVwPY41EI5cwAbshyUt3J48MKvWSOW0exgJp6jbSm3xgfZMJ4BfLr8KXo5mx7CS3PcrSlBaWg7ebUsWXKdbgVmehE77+0ZIjvo9McT/xZIJnlb6FYRUcPvww5ay03AWg8D0QBskCeYnfEd4fPadxzvtKWJ5CoG+wabvcv50+QbkOWcBUWUQ3XEp97thb9bQxPeMRRmnJu2g5LwZ9ZKgg5Vu4r4TKaHEnofFxJDLzLBdTu4ms3WjBMiMAdwfykgMQxTBPA2BCSqraMH5q/osGPRKqDnZsqwYgCkF/KBHnZpTmJzIA9Lt2ujQmix4CdOyd0O1ECwqfcx8FLGdZr4lGP0jepHgZ9tsD08HQq629R/ljf8DR7iiVF0LEJLPH2EGf/2ulDFlxyCcC6zMQztQNaCPrLcqAGZPTqNz9erfZ9GllyGJh91T8ucy+yCYYHEkLURuhL4w3GdkPlpuDstY33T7wszOr/lawCNTsTcYZ1764+aC0= koratsuki@happyharry"
}
# Aca va la plantilla que usaremos, puede ser Debian/Ubuntu u otra.
variable "template_name" {
    default = "external:vztmpl/debian-11-standard_11.0-1_amd64.tar.gz"
}

Y ahora el archivo main.tf, el cual nos definirá como se crea el CT:

nano main.tf

Contenido:

resource "proxmox_lxc" "test" {
  count = 1
  onboot = true
  start = true
  vmid = "201"
  hostname = var.hostname
  ostype = "debian"
  cores = 2
  cpulimit = 0
  memory = 1024
  swap = 512
  ostemplate = var.template_name
  password = var.ct_pass
  pool = ""
  ssh_public_keys = var.ssh_key

  rootfs {
    storage= "external"
    size="8G"
  }

  nameserver = var.dns_server
  searchdomain = var.dns_domain

  network {
    name = "eth0"
    bridge = "vmbr0"
    ip = "192.168.0.201/24"
    gw = "192.168.0.254"
    firewall = false
  }

  features {
    nesting = true
  }

  unprivileged = false
  target_node = "pve1"

  connection {
    type     = "ssh"
    user     = "root"
    private_key = file(pathexpand("~/.ssh/id_rsa"))
    host     = "192.168.0.201"
  }

  provisioner "file" {
    source = "config/script.sh"
    destination = "/tmp/script.sh"
  }

  provisioner "remote-exec" {
    inline = [
    "chmod +x /tmp/script.sh",
    "/tmp/script.sh args",
    ]
    on_failure = continue
  }
}

Acá hemos definido lo mismo que hacemos vía web, a la hora de crear un contenedor, pero mediante código, y al final, dentro de la carpeta config hemos creado un script que se copiará al contenedor recién creado y se ejecutará.

nano config/script.sh

Contenido:

#!/bin/bash

# deshabilitamos resolved
systemctl stop systemd-resolved
systemctl disable systemd-resolved
systemctl mask systemd-resolved

# definimos la zona horaria
timedatectl set-timezone America/Havana

# Repos locales en caso de tenerlos
echo "deb http://repo.inutil.cu/debian/bullseye bullseye main contrib non-free" > /etc/apt/sources.list
echo "deb http://repo.inutil.cu/debian/bullseye-security bullseye-security main contrib non-free" >> /etc/apt/sources.list

# Removing unused things
apt purge -y postfix* rpcbind

# Upgrade system
apt update ;; apt dist-upgrade -y

# Installing stuff
apt install -y mc net-tools dnsutils wget git rsync \
 p7zip-full htop iftop nethogs telnet screen multitail \
 ccze lzma xz-utils rar unrar ;; apt clean

Entonces, listo todo, sólo queda ejecutar todo:

$ terraform init

Entonces, empezamos bien, se inicializó terraform y el plugin para proxmox, Ahora:

$ terraform plan

Acá Terraform te muestra todo el plan que vas a ejecutar, en detalle. Ahora sólo queda ejecutar el provisionado:

$ terraform apply

Terraform nos recordará todo lo anterior y nos avisará que estamos listos, que acepte para empezar:


Y listo, empezará el provisionamiento:

Y con esto, ya tenemos nuestro CT creado y provisionado, actualizado mediante script externo. Nos vemos en la parte 4 de este tutorial, donde haremos lo mismo, pero para VMs. Un saludo y happy hacking!

 

Referencias:
https://www.terraform.io/language/values/variables

¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en una estrella para puntuar!

Promedio de puntuación 5 / 5. Recuento de votos: 4

Hasta ahora, ¡no hay votos!. Sé el primero en puntuar este contenido.