Fase 2.1
hashicorp/kubernetes ~> 2.30

Kubernetes Provider · Cluster como Código

El provider de Kubernetes para OpenTofu permite gestionar recursos dentro del cluster k3s con el mismo workflow declarativo que la infraestructura cloud. Namespace, ConfigMaps, Secrets — todo definido en .tf y reconciliado automáticamente.

01

Configuración del Provider

La configuración es mínima: el bloque terraform declara el provider requerido y el bloque provider apunta al kubeconfig de k3s. Sin credenciales hardcodeadas, sin configuración de cluster — todo se deriva del kubeconfig.

tofu/main.tf
terraform {
  required_version = ">= 1.7"
  required_providers {
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.30"
    }
  }
}

provider "kubernetes" {
  config_path = var.kubeconfig_path
}
1
El provider usa el kubeconfig default de k3s ( ~/.kube/config ). Si se ejecuta dentro de la VM, ya está configurado. Si se ejecuta desde la Mac, el kubeconfig se copió en el paso 3 del Quick Start.
2
La versión usa el constraint ~> 2.30 (pessimistic constraint). Esto acepta versiones >= 2.30 y < 3.0 — estable pero con fixes de bugs.
3
El provider no necesita credenciales explícitas: lee el kubeconfig y usa el contexto actual. Si kubectl get nodes funciona, tofu plan también.
Prerrequisito: k3s debe estar corriendo y el kubeconfig debe ser accesible. Si se ejecuta OpenTofu dentro de la VM Rocky Linux, k3s ya configuró /etc/rancher/k3s/k3s.yaml. Si se ejecuta desde la máquina local, el kubeconfig se copió a ~/.kube/config en el Quick Start.
02

Recursos Gestionados

Tres recursos en main.tf. Cada uno declara el estado deseado del objeto en Kubernetes. OpenTofu se encarga de crearlo, actualizarlo o recrearlo si se modifica o elimina manualmente.

kubernetes_namespace.aiops

Crea el namespace donde vive todo el stack. Las labels app.kubernetes.io/part-of y managed-by permiten identificar qué recursos pertenecen al proyecto y cuáles son gestionados por OpenTofu vs creados manualmente.

Definición
resource "kubernetes_namespace" "aiops" {
  metadata {
    name = "aiops"
    labels = {
      "app.kubernetes.io/part-of" = "aiops-lab"
      "managed-by"                = "opentofu"
    }
  }
}
kubernetes_config_map.prometheus

ConfigMap con dos claves. prometheus.yml define los scrape configs (3 jobs: prometheus, node-exporter, k3s-metrics) y el alertmanager target. alert_rules.yml define tres alertas: HighCPU, DiskSpaceLow y ServiceDown.

Definición
resource "kubernetes_config_map" "prometheus" {
  metadata {
    name      = "prometheus-config"
    namespace = kubernetes_namespace.aiops.metadata[0].name
  }
  data = {
    "prometheus.yml"  = <<-YAML
      global:
        scrape_interval: 15s
      scrape_configs:
        - job_name: "prometheus"
        - job_name: "node-exporter"
        - job_name: "k3s-metrics"
    YAML
    "alert_rules.yml" = <<-YAML
      groups:
        - name: aiops-alerts
          rules:
            - alert: HighCPU
            - alert: DiskSpaceLow
            - alert: ServiceDown
    YAML
  }
}
kubernetes_config_map.grafana

ConfigMap que Grafana lee al iniciar para provisionar automáticamente sus datasources. Sin este ConfigMap, habría que configurar Prometheus y Loki manualmente desde la UI de Grafana después de cada deploy.

Definición
resource "kubernetes_config_map" "grafana" {
  metadata {
    name      = "grafana-datasources"
    namespace = kubernetes_namespace.aiops.metadata[0].name
  }
  data = {
    "datasources.yml" = <<-YAML
      apiVersion: 1
      datasources:
        - name: Prometheus
          type: prometheus
          url: http://prometheus:9090
        - name: Loki
          type: loki
          url: http://loki:3100
    YAML
  }
}
03

Grafo de Dependencias

OpenTofu resuelve automáticamente el orden de creación basándose en las referencias entre recursos. Los ConfigMaps referencian kubernetes_namespace.aiops.metadata[0].name, lo que crea una dependencia implícita: el namespace se crea antes que los ConfigMaps.

namespace
kubernetes_namespace.aiops
namespace = ns.metadata[0].name
namespace = ns.metadata[0].name
configmap
prometheus
configmap
grafana

OpenTofu construye un grafo dirigido acíclico (DAG) a partir de estas referencias. Orden de creación: namespace → ambos ConfigMaps en paralelo. Orden de destrucción: inverso (ConfigMaps → namespace). Esto evita intentar crear un ConfigMap en un namespace que todavía no existe.

04

Variables

Cuatro variables parametrizan el comportamiento del stack local. Todas tienen defaults razonables para el lab — solo hace falta modificarlas para cambiar el namespace o la ruta del kubeconfig.

kubeconfig_path
Ruta al kubeconfig de k3s. Apunta al archivo generado por k3s install en /etc/rancher/k3s/k3s.yaml o copiado a ~/.kube/config.
default ~/.kube/config
namespace
Nombre del namespace donde vive el stack. Cambiable si se necesita otro nombre sin tocar el código de recursos.
default aiops
prometheus_retention
Tiempo de retención de métricas. 15 días es suficiente para el lab. En producción se ajustaría según el storage disponible.
default 15d
grafana_admin_password sensitive
Password de admin de Grafana. Marcada como sensitive — no se muestra en logs. En Fase 3 se reemplaza por un secret de Vault.
default admin
sobreescribir variables
# Crear un archivo terraform.tfvars
$cat > tofu/terraform.tfvars << 'EOF'
namespace = "aiops-dev"
kubeconfig_path = "/home/rocky/.kube/config"
EOF
# O pasarlas por línea de comandos
$tofu apply -var="namespace=aiops-dev"
05

Outputs

Los outputs del stack local exponen el nombre del namespace y de los ConfigMaps creados. Útiles para scripts que necesitan saber dónde se desplegó el stack.

tofu/outputs.tf
output "namespace_name" {
  description = "Nombre del namespace creado"
  value       = kubernetes_namespace.aiops.metadata[0].name
}

output "prometheus_configmap_name" {
  description = "Nombre del ConfigMap de Prometheus"
  value       = kubernetes_config_map.prometheus.metadata[0].name
}

output "grafana_configmap_name" {
  description = "Nombre del ConfigMap de Grafana"
  value       = kubernetes_config_map.grafana.metadata[0].name
}
tofu output
$tofu output
namespace_name = "aiops"
prometheus_configmap_name = "prometheus-config"
grafana_configmap_name = "grafana-datasources"
06

Labels y Trazabilidad

Todos los recursos gestionados por OpenTofu llevan labels que identifican su origen y pertenencia. Esto es práctica de producción: cuando hay decenas de recursos en un cluster, saber cuál herramienta los creó evita conflictos.

app.kubernetes.io/part-of = aiops-lab Identifica que el recurso pertenece a este proyecto.
managed-by = opentofu Diferencia recursos IaC de recursos creados con kubectl apply manual.
filtrar por label
# Ver todos los recursos gestionados por OpenTofu
$kubectl get all -n aiops -l managed-by=opentofu
# Ver todos los ConfigMaps del proyecto
$kubectl get configmap -n aiops -l app.kubernetes.io/part-of=aiops-lab

Siguiente: init → plan → apply

Con el provider configurado y los recursos definidos, la siguiente página detalla el workflow completo: inicializar el provider, planificar los cambios y aplicar el estado deseado al cluster k3s.

Workflow