Saltar a contenido

Primeros pasos con Terraform

En este artículo

Información

Terraform es una herramienta de infraestructura como código desarrollada por HashiCorp. El estado deseado de la infraestructura se describe en archivos de configuración escritos en HCL, y Terraform alinea los recursos reales con esa descripción mediante la llamada a la API del proveedor de servicios a través de un módulo dedicado conocido como provider. Cada operación que realiza se registra en un archivo de estado, por lo que la herramienta sabe qué existe ya y aplica solo los cambios faltantes en la siguiente ejecución. Terraform permite previsualizar los cambios antes de aplicarlos, mantener la configuración en un control de versiones y reproducir entornos idénticos, lo que lo convierte en una forma conveniente de gestionar servidores, redes y servicios, independientemente de quién los aloje.

Cuando solo ejecutas un servidor, pedirlo manualmente es más rápido. Una vez que hay quince, creados en diferentes momentos por diferentes administradores, nadie recuerda por qué uno ejecuta Ubuntu 20.04 mientras que la máquina de al lado ejecuta 22.04. Un archivo de configuración mantiene ese historial por sí mismo, y también te permite levantar el mismo entorno sin tener que reconstruir una secuencia de clics de memoria.

Con nuestro provider el flujo de trabajo es el siguiente. El archivo enumera el preset, la ubicación, el sistema operativo y el plan de tráfico, tras lo cual terraform apply realiza el pedido y espera a que la implementación finalice. Ejecutarlo de nuevo no duplica nada, ya que Terraform recuerda los recursos que creó. El comando terraform plan muestra los próximos cambios sin realizar ninguno de ellos.

El provider funciona con todo el catálogo, incluyendo VPS, VDS, servidores dedicados y GPU, direcciones IP adicionales, claves SSH y zonas DNS. La referencia completa de los recursos y fuentes de datos está disponible en el Terraform Registry y en el repositorio hostkey-cloud/terraform-provider-hostkey-com. Lo que sigue es el escenario básico: pedir un servidor virtual.

Qué necesitas para trabajar con Terraform

  • Una cuenta en el panel de control Invapi con fondos en el saldo, ya que pedir un servidor es una operación de pago;
  • una API key;
  • una clave SSH;
  • Terraform 1.0 o superior.

Atención

La cuenta debe tener al menos un servidor. Invapi no emite una sesión para una cuenta sin servicios, y la autenticación fallará con No appropriate servers found. Si la cuenta es nueva, pide el primer servidor a través del panel de control y crea el resto con Terraform.

Paso 1. Instalar Terraform

Terraform se ejecuta en Linux, macOS y Windows, y puedes instalarlo de dos maneras: mediante un gestor de paquetes o manualmente, descargando y descomprimiendo el binario precompilado.

Windows

Descarga el archivo, descomprime terraform.exe en una carpeta dedicada como C:\terraform y añade esa carpeta a la variable de entorno Path.

Cierra y vuelve a abrir la terminal después, ya que el nuevo valor de Path no se aplica hasta que lo hagas. Para verificar la instalación:

terraform -v

Linux

wget https://releases.hashicorp.com/terraform/1.15.8/terraform_1.15.8_linux_amd64.zip
unzip ./terraform_1.15.8_linux_amd64.zip
sudo mv ./terraform /usr/local/bin
terraform -v

macOS

brew install terraform
terraform -v

Paso 2. Crear una API key

La clave se crea en el panel de control Invapi. Haz clic en tu nombre de usuario en la esquina superior derecha y selecciona API keys:

Haz clic en Add new y rellena el formulario.

Campo Valor
Name Solo letras latinas, dígitos, _ y - (5-30 caracteres)
Restrict a new API key only for the server Any
IP ACL Deja vacío para permitir el acceso desde cualquier dirección
Set login notification method None
Active Selected

El campo Restrict a new API key only for the server vincula la clave a un único servicio, y el provider necesita pedir nuevos servidores, por lo que el valor debe ser Any.

El campo IP ACL limita el acceso a las direcciones listadas. Mejora la seguridad; sin embargo, con una dirección IP dinámica, la clave dejará de funcionar en cuanto la dirección cambie, así que deja el campo vacío cuando estés empezando, y para integración continua enumera las direcciones de tus servidores de compilación.

Haz clic en Create. La clave se muestra solo una vez.

Atención

Guarda la clave inmediatamente, ya que solo conservamos su hash y el valor no se puede recuperar. Si la pierdes, tendrás que crear una nueva.

Paso 3. Preparar la configuración

Ejemplo de configuración

Hay ejemplos de configuración listos para usar disponibles en el repositorio del provider. Para una configuración básica, consulta el ejemplo examples/basic.

Crea un directorio de proyecto, por ejemplo hostkey-terraform. Los archivos de configuración utilizan la extensión .tf y sus nombres son arbitrarios, ya que Terraform combina cada archivo .tf en el directorio en una única configuración. Nuestro ejemplo utiliza tres archivos.

main.tf

El primer bloque fija el provider y la versión requerida de Terraform.

terraform {
  required_providers {
    hostkey = {
      source  = "hostkey-cloud/hostkey-com"
      version = "~> 0.2"
    }
  }
  required_version = ">= 1.0"
}

provider "hostkey" {}

Nota

A partir de la versión 0.2, el provider se publica por separado para cada sistema de facturación. El paquete hostkey-com funciona con invapi.hostkey.com, por lo que no hay un endpoint de API que elegir y el bloque provider se mantiene vacío.

A continuación viene la comprobación del catálogo. Estos bloques no crean recursos y no se facturan, solo solicitan a la API las listas de presets y planes de tráfico disponibles para pedir:

data "hostkey_presets" "selected" {
  location = var.location
  name     = var.preset_name
}

data "hostkey_traffic_plans" "for_preset" {
  location    = var.location
  instance_id = data.hostkey_presets.selected.presets[0].id
}

output "catalog_preset" {
  value = data.hostkey_presets.selected.presets
}

output "catalog_traffic_plans" {
  value = data.hostkey_traffic_plans.for_preset.traffic_plans
}

Vale la pena hacer la comprobación por dos razones. El provider requiere una coincidencia exacta del nombre, y el catálogo contiene nombres de planes de tráfico similares, por ejemplo 3 TB / 1 Gbps VM y 3Tb traffic (1Gbps) VM. Además, el contenido del catálogo depende de la ubicación y cambia con el tiempo, por lo que un preset disponible hoy puede no estarlo mañana.

A continuación se describe el servidor:

resource "hostkey_server" "web" {
  preset_name       = var.preset_name
  location_name     = var.location
  traffic_plan_name = var.traffic_plan_name
  deploy_period     = "monthly"

  os_name   = "Ubuntu 22.04"
  root_pass = var.root_pass
  ssh_key   = file(pathexpand(var.ssh_public_key_path))

  power_state = "on"

  cancellation_type   = 1
  cancellation_reason = "terraform"

  tags = {
    env = "demo"
  }

  timeouts {
    create = "90m"
    update = "90m"
    delete = "30m"
  }
}

El bloque timeouts establece cuánto tiempo espera Terraform a que una operación finalice. La implementación suele tardar un par de minutos, pero si la espera se interrumpe por un timeout, el pedido seguirá pagado mientras Terraform pierde el rastro de él.

El argumento cancellation_type establecido en 1 cancela el servicio inmediatamente, mientras que 0 lo deja funcionando hasta el final del periodo pagado.

Nota

El argumento hostname se ha omitido deliberadamente del ejemplo. Cuando se omite, el provider genera un nombre único como tf-44067425, y el servicio aparece con ese nombre en el panel de control. El nombre dentro del sistema operativo puede ser diferente, ya que Invapi no se lo pasa al invitado, por lo que la única forma de comprobarlo es ejecutando hostname en el propio servidor.

La clave SSH en el almacenamiento de la cuenta se crea por separado:

resource "hostkey_ssh_key" "deploy" {
  name = "tf-deploy"
  key  = file(pathexpand(var.ssh_public_key_path))
}

Esto no es lo mismo que el atributo ssh_key de hostkey_server. El atributo del servidor escribe la clave en la máquina durante la instalación del sistema operativo, mientras que el recurso hostkey_ssh_key almacena la clave en la cuenta para su uso posterior.

El archivo termina con bloques output. Después del pedido, Terraform imprime la dirección del servidor, su identificador y el número de factura, y terraform output main_ipv4 devuelve la dirección en cualquier momento posterior, lo cual es útil cuando algo más se ejecuta después:

output "server_id" {
  value = hostkey_server.web.id
}

output "main_ipv4" {
  value = hostkey_server.web.main_ipv4
}

output "invoice" {
  value = hostkey_server.web.invoice
}

variables.tf

variable "location" {
  type    = string
  default = "FI"
}

variable "preset_name" {
  type    = string
  default = "vm.v2-pico"
}

variable "traffic_plan_name" {
  type    = string
  default = "3 TB / 1 Gbps VM"
}

variable "root_pass" {
  type      = string
  sensitive = true
}

variable "ssh_public_key_path" {
  type    = string
  default = "~/.ssh/id_ed25519.pub"
}

terraform.tfvars

Este archivo contiene la contraseña, por lo que no se incluye en el control de versiones:

root_pass = "StrongPass1%"

# Los valores por defecto pueden sobrescribirse aquí
# location          = "NL"
# preset_name       = "vm.v3-pico"
# traffic_plan_name = "5 TB / 1 Gbps VM"

Atención

La contraseña de root debe tener entre 8 y 30 caracteres y contener una letra mayúscula, una letra minúscula, un dígito y uno de los caracteres %, -, _, +. Los caracteres @ y # no están permitidos. La contraseña se almacena en el archivo de estado de Terraform y se envía en texto plano en el correo electrónico de preparación del servidor, así que cámbiala una vez que el servidor esté desplegado.

Paso 4. Inicializar el provider

La clave se pasa a través de una variable de entorno para que permanezca fuera de los archivos del proyecto:

$env:HOSTKEY_API_KEY = "your-key"

En el símbolo del sistema de Windows usa set HOSTKEY_API_KEY=your-key, y en Linux y macOS export HOSTKEY_API_KEY="your-key". La variable solo se aplica a la sesión actual de la terminal.

Nota

La clave ya es necesaria en la etapa de planificación, ya que el provider compara los nombres de la configuración con el catálogo y falla sin acceso a la API.

A continuación, hay que descargar el provider:

terraform init

Terraform descarga el provider y crea un archivo .terraform.lock.hcl con la versión exacta. Este archivo se incluye en el repositorio, ya que garantiza que todos en el proyecto terminen con la misma versión instalada.

Paso 5. Validar la configuración

La sintaxis se comprueba sin llamar a la API:

terraform validate

Una comprobación exitosa imprime Success! The configuration is valid.

Luego viene el plan, que muestra los próximos cambios sin realizar ninguno de ellos:

terraform plan

La línea de resumen. Se espera Plan: 2 to add, 0 to change, 0 to destroy, es decir, el servidor y la clave SSH.

Los identificadores resueltos. El provider rellena preset_id, os_id y traffic_plan_id junto a los nombres, y si no se encuentra un nombre en el catálogo, el plan falla antes de que se facture nada.

El catálogo. La sección Changes to Outputs enumera los presets y planes de tráfico, y los valores en la configuración deben escribirse exactamente de la misma manera.

Paso 6. Pedir el servidor

terraform apply

Terraform muestra el plan una vez más y pide confirmación; escribe yes y pulsa Enter.

Atención

El pedido se paga a partir de este momento. No cierres la ventana de la terminal ni interrumpas el comando; de lo contrario, el pedido se quedará en el panel de control mientras Terraform pierde el rastro de él.

La clave SSH se crea primero, luego comienza el pedido del servidor, y Terraform determinó ese orden por sí mismo a partir de las dependencias.

Después de eso aparecen las líneas Still creating..., que se actualizan cada diez segundos, mientras el provider consulta la API y espera a que la instalación finalice. Mientras tanto, el servidor es visible en el panel de control:

Una vez terminado, se imprimen los valores. Vale la pena comprobar el acceso SSH utilizando la dirección que recibiste:

La clave especificada en el atributo ssh_key ya está presente en el servidor, por lo que no se solicita contraseña. El nuevo servidor aparece en el panel de control junto a los pedidos realizados manualmente:

Paso 7. Cambiar la configuración

Los cambios se dividen en tres categorías:

  • Cambios seguros. Las etiquetas (tags) y el estado de encendido se aplican a un servidor en funcionamiento, y el plan los muestra como update in-place.

  • Reinstalación del sistema operativo. Cambiar os_name, soft_name, root_pass o ssh_key reinstala el sistema operativo en el mismo servidor, lo que significa que se perderán todos los datos del disco.

  • Un nuevo pedido. Cambiar preset_name, location_name, traffic_plan_name o deploy_period significa que el servidor anterior se cancela y se pide uno nuevo, por lo que se te volverá a facturar. El plan marca tales cambios como forces replacement.

Atención

Los cambios que conllevan una reinstalación aparecen en el plan como update in-place, exactamente de la misma manera que un cambio de etiqueta inofensivo. El provider imprime una advertencia aparte sobre la pérdida de datos, por lo que, antes de confirmar, vale la pena leer no solo el plan, sino también las advertencias.

Paso 8. Destruir los recursos

terraform destroy

terraform destroy elimina todos los recursos que están en el estado actual de Terraform para esta configuración. Terraform mostrará la lista de recursos a eliminar y pedirá confirmación. Escribe yes y pulsa Enter.

Si necesitas eliminar solo un recurso, puedes especificarlo con -target. Por ejemplo:

terraform destroy -target=hostkey_server.web

Aquí, web es el nombre del recurso del bloque resource "hostkey_server" "web", no el ID del servidor del panel de control.

Otra opción es eliminar el recurso de los archivos .tf y ejecutar:

terraform apply

Terraform verá que el recurso ya no está presente en la configuración y lo eliminará de la infraestructura.

La cancelación del servicio se realiza a través de Invapi, y el método de cancelación se determina mediante el parámetro cancellation_type: 1 cancela el servicio inmediatamente, mientras que 0 lo cancela al final del periodo pagado.

Información

Con la cancelación inmediata (cancellation_type = 1), la parte no utilizada del periodo pagado se acredita de nuevo al saldo de la cuenta proporcionalmente al tiempo real que el servicio estuvo funcionando.

Importar servidores existentes

Los servidores pedidos a través del panel de control pueden pasar a estar bajo la gestión de Terraform. El identificador se toma de la columna ID en la lista de servidores:

terraform import hostkey_server.web 19463

Después de la importación, el estado contiene los datos reales, es decir, el identificador, la dirección, el estado y el estado de encendido. Los argumentos del momento del pedido no se transfieren desde el panel de control, por lo que se describen en la configuración manualmente. El primer terraform apply después de una importación no conlleva una reinstalación.

Resolución de problemas

Nota

No appropriate servers found al ejecutar el plan. Comprueba que la cuenta tenga al menos un servicio, ya que Invapi no emite una sesión para una cuenta sin servicios.

Nota

Catalog name resolve failed. El preset, sistema operativo o nombre del plan de tráfico especificado no está presente en el catálogo para la ubicación seleccionada. Enumera los valores disponibles a través de las fuentes de datos hostkey_presets y hostkey_traffic_plans y ajusta la configuración a ellos.

Nota

Estado pending:<invoice>. El pedido está pagado pero la implementación no ha terminado, normalmente porque se perdió la conexión. Ejecutar terraform apply de nuevo reanuda la espera y no realiza un nuevo pedido. Si la factura no está pagada, pá gala y ejecuta terraform apply de nuevo. El estado en vivo del servicio se muestra en el panel de control.

Información

Puedes encontrar más información sobre Terraform en la documentación oficial de HashiCorp, y los argumentos específicos de los recursos y fuentes de datos están documentados en el Terraform Registry.

question_mark
Is there anything I can help you with?
question_mark
AI Assistant ×