Terraform Kubernetes Provider es la solución definitiva para gestionar recursos de Kubernetes mediante infraestructura como código. En esta guía completa, aprenderás a desplegar aplicaciones en clusters K8s de manera declarativa, automatizar la gestión de deployments y services, y mantener un control versionado de tu infraestructura cloud-native. Combinar Terraform con Kubernetes te permite unificar tu workflow de IaC y aprovechar el ciclo de vida completo de recursos.
¿Qué es Terraform Kubernetes Provider?
El Terraform Kubernetes Provider es un plugin oficial de HashiCorp que permite gestionar recursos de Kubernetes directamente desde código Terraform. En lugar de escribir manifiestos YAML y aplicarlos con kubectl, puedes definir deployments, services, configmaps, secrets y cualquier otro recurso K8s usando la sintaxis HCL de Terraform.
Este provider se conecta a tu cluster de Kubernetes (ya sea EKS, AKS, GKE o cualquier distribución on-premise) y ejecuta operaciones CRUD sobre los recursos que defines en tus archivos .tf. HashiCorp mantiene activamente este provider, con más de 100 recursos soportados y actualizaciones regulares que siguen la evolución de la API de Kubernetes.
Características principales del provider
- Gestión declarativa completa: Define el estado deseado de tus recursos K8s en código Terraform
- Ciclo de vida automatizado: Terraform maneja creación, actualización y eliminación de recursos automáticamente
- Comprensión de dependencias: El grafo de dependencias de Terraform previene errores al crear recursos en el orden correcto
- Soporte multi-cluster: Gestiona múltiples clusters desde una misma configuración usando alias de providers
- Integración con ecosistema Terraform: Combina recursos K8s con infraestructura cloud (VPCs, load balancers, bases de datos)
- Custom Resource Definitions: Soporte completo para CRDs mediante el recurso kubernetes_manifest
Casos de uso principales
El provider es ideal para equipos DevOps que necesitan:
- Desplegar aplicaciones microservicios con múltiples deployments y services coordinados
- Gestionar configuración de aplicaciones mediante ConfigMaps y Secrets versionados
- Automatizar infraestructura K8s completa desde la creación del cluster hasta la aplicación final
- Mantener consistencia multi-entorno (dev, staging, production) con código reutilizable
- Integrar Kubernetes con servicios cloud como RDS, S3, Azure Storage en un único workflow
Terraform Kubernetes Provider vs Alternativas
Al gestionar aplicaciones en Kubernetes, existen varias herramientas disponibles. Comparemos el Terraform Kubernetes Provider con las alternativas más populares:
Terraform Kubernetes Provider vs kubectl + YAML
Usar kubectl con manifiestos YAML es el enfoque tradicional. Sin embargo, Terraform ofrece ventajas significativas:
- State management: Terraform mantiene un state file que rastrea qué recursos existen, evitando configuración drift
- Plan antes de apply: Puedes previsualizar cambios antes de aplicarlos con terraform plan
- Infraestructura unificada: Gestiona tanto el cluster K8s como las aplicaciones que corren en él
- Módulos reutilizables: Encapsula configuraciones complejas en módulos Terraform compartibles
Terraform Kubernetes Provider vs Helm
Helm es el package manager de Kubernetes, enfocado en desplegar aplicaciones empaquetadas. La diferencia clave:
- Nivel de abstracción: Helm trabaja con charts (paquetes de aplicaciones), mientras que el provider gestiona recursos individuales
- Propósito: Helm es para deployment de aplicaciones, Terraform es para provisioning de infraestructura
- Rollbacks: Helm tiene rollback nativo (helm rollback), Terraform requiere gestión de state
- Complementarios: Puedes usar Terraform Helm Provider para desplegar charts desde Terraform
Muchos equipos usan ambos: Terraform para infraestructura base y Helm para aplicaciones complejas. Para gestionar configuraciones de Docker Compose en entornos locales, consulta nuestros tutoriales de Docker Compose.
Requisitos Previos
Antes de comenzar con el Terraform Kubernetes Provider, necesitas tener configurado lo siguiente:
Software necesario
- Terraform: Versión 1.0 o superior (recomendado 1.5+)
- kubectl: Cliente de línea de comandos de Kubernetes
- Cluster Kubernetes: Puede ser minikube, kind, k3s, EKS, AKS, GKE o cualquier distribución
- Kubeconfig válido: Archivo ~/.kube/config con credenciales del cluster
Verificar acceso al cluster
# Verificar que kubectl puede conectarse
kubectl cluster-info
# Listar nodos del cluster
kubectl get nodes
# Verificar contexto actual
kubectl config current-context
Si no tienes un cluster disponible, puedes crear uno localmente con minikube o kind para practicar. Para entornos de producción, te recomendamos usar servicios gestionados como EKS, AKS o GKE.
Configuración del Terraform Kubernetes Provider
Vamos a configurar el Terraform Kubernetes Provider paso a paso. Primero, crea un directorio para tu proyecto:
mkdir terraform-k8s-demo
cd terraform-k8s-demo
1. Definir el provider
Crea un archivo providers.tf con la configuración del provider:
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.25"
}
}
required_version = ">= 1.0"
}
provider "kubernetes" {
config_path = "~/.kube/config"
config_context = "minikube" # Cambia según tu contexto
}
Este código especifica que vamos a usar el provider oficial de HashiCorp. El provider se autentica usando tu archivo kubeconfig local.
Métodos de autenticación
El provider soporta múltiples métodos de autenticación, con el siguiente orden de prioridad:
- Plugins cloud-específicos (eks, az, gcloud) – Recomendado para producción
- Tokens OAuth2 – Para integración con sistemas de identidad
- Certificados TLS – Autenticación basada en certificados
- Archivos kubeconfig – Ideal para desarrollo local
- Autenticación HTTP básica – No recomendado para producción
Para clusters en AWS EKS, usa esta configuración:
provider "kubernetes" {
host = data.aws_eks_cluster.cluster.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority[0].data)
token = data.aws_eks_cluster_auth.cluster.token
}
2. Inicializar Terraform
terraform init
Este comando descarga el plugin del Terraform Kubernetes Provider desde el Terraform Registry y lo instala localmente en tu directorio .terraform/.
Desplegar una Aplicación con Terraform Kubernetes Provider
Ahora vamos a desplegar una aplicación NGINX completa usando el Terraform Kubernetes Provider. Esta aplicación incluirá un Deployment, un Service y un ConfigMap.
1. Crear un Namespace
Primero, crea un namespace dedicado para organizar tus recursos. Añade este código a namespace.tf:
resource "kubernetes_namespace" "app" {
metadata {
name = "terraform-demo"
labels = {
environment = "development"
managed-by = "terraform"
}
}
}
2. Configurar un Deployment
Crea un archivo deployment.tf con la definición del Deployment de NGINX:
resource "kubernetes_deployment" "nginx" {
metadata {
name = "nginx-deployment"
namespace = kubernetes_namespace.app.metadata[0].name
labels = {
app = "nginx"
}
}
spec {
replicas = 3
selector {
match_labels = {
app = "nginx"
}
}
template {
metadata {
labels = {
app = "nginx"
}
}
spec {
container {
image = "nginx:1.25-alpine"
name = "nginx"
port {
container_port = 80
}
resources {
limits = {
cpu = "500m"
memory = "512Mi"
}
requests = {
cpu = "250m"
memory = "256Mi"
}
}
liveness_probe {
http_get {
path = "/"
port = 80
}
initial_delay_seconds = 30
period_seconds = 10
}
readiness_probe {
http_get {
path = "/"
port = 80
}
initial_delay_seconds = 5
period_seconds = 5
}
}
}
}
}
}
Este Deployment crea 3 réplicas de NGINX con health checks configurados. Observa cómo referenciamos el namespace usando kubernetes_namespace.app.metadata[0].name – esto crea una dependencia implícita que asegura que el namespace se cree primero.
3. Exponer con un Service
Crea service.tf para exponer el Deployment:
resource "kubernetes_service" "nginx" {
metadata {
name = "nginx-service"
namespace = kubernetes_namespace.app.metadata[0].name
}
spec {
selector = {
app = kubernetes_deployment.nginx.spec[0].template[0].metadata[0].labels.app
}
port {
port = 80
target_port = 80
node_port = 30080
}
type = "NodePort"
}
}
El selector del Service referencia dinámicamente las labels del Deployment, garantizando que siempre estén sincronizados. Para producción en cloud, cambia el type a «LoadBalancer» para obtener un balanceador de carga externo.
4. Añadir un ConfigMap
Crea configmap.tf para gestionar configuración de la aplicación:
resource "kubernetes_config_map" "nginx_config" {
metadata {
name = "nginx-config"
namespace = kubernetes_namespace.app.metadata[0].name
}
data = {
"nginx.conf" = <<-EOF
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /health {
access_log off;
return 200 "healthy\n";
}
}
EOF
}
}
5. Aplicar la configuración
# Previsualizar cambios
terraform plan
# Aplicar cambios
terraform apply
# Confirmar con 'yes'
Terraform creará todos los recursos en el orden correcto gracias a su grafo de dependencias. Puedes verificar el despliegue con kubectl:
kubectl get all -n terraform-demo
Gestión de Variables en Terraform Kubernetes Provider
Para hacer tu configuración reutilizable, utiliza variables de Terraform. Crea un archivo variables.tf:
variable "namespace" {
description = "Kubernetes namespace para los recursos"
type = string
default = "terraform-demo"
}
variable "app_name" {
description = "Nombre de la aplicación"
type = string
default = "nginx"
}
variable "replicas" {
description = "Número de réplicas del deployment"
type = number
default = 3
}
variable "image_tag" {
description = "Tag de la imagen de contenedor"
type = string
default = "1.25-alpine"
}
Ahora modifica tus recursos para usar estas variables:
resource "kubernetes_deployment" "nginx" {
metadata {
name = "${var.app_name}-deployment"
namespace = var.namespace
}
spec {
replicas = var.replicas
template {
spec {
container {
image = "nginx:${var.image_tag}"
name = var.app_name
# ... resto de la configuración
}
}
}
}
}
Puedes sobrescribir valores desde línea de comandos:
terraform apply -var="replicas=5" -var="image_tag=1.26-alpine"
O crear un archivo terraform.tfvars para cada entorno:
# production.tfvars
namespace = "production"
app_name = "nginx"
replicas = 10
image_tag = "1.25-alpine"
Escalado y Actualización con Terraform Kubernetes Provider
Una de las ventajas del Terraform Kubernetes Provider es la facilidad para escalar y actualizar aplicaciones.
Escalar réplicas
Simplemente modifica el valor de replicas en tu configuración:
resource "kubernetes_deployment" "nginx" {
# ...
spec {
replicas = 5 # Cambiar de 3 a 5
}
}
Ejecuta terraform apply y Terraform actualizará el Deployment sin interrumpir el servicio.
Actualizar versión de imagen
container {
image = "nginx:1.26-alpine" # Nueva versión
}
Terraform actualizará el Deployment siguiendo la estrategia de rolling update configurada en Kubernetes, garantizando cero downtime.
Previsualizar cambios antes de aplicar
# Ver qué cambiará exactamente
terraform plan
# Ver el diff detallado
terraform plan -out=plan.out
terraform show plan.out
Gestión de Secrets con Terraform Kubernetes Provider
El Terraform Kubernetes Provider permite gestionar Secrets de Kubernetes, aunque con consideraciones de seguridad importantes.
Crear un Secret
resource "kubernetes_secret" "app_credentials" {
metadata {
name = "app-credentials"
namespace = kubernetes_namespace.app.metadata[0].name
}
data = {
username = "admin"
password = "changeme123" # NO hacer esto en producción
}
type = "Opaque"
}
Mejores prácticas para Secrets
- NO almacenar secrets en código: Usa variables de entorno o sistemas externos
- Integrar con Vault: Usa el Terraform Vault Provider para obtener secrets dinámicos
- Encriptar el state file: Almacena tu terraform.tfstate en S3 con encriptación o usa Terraform Cloud
- Variables sensibles: Marca variables como sensitive para evitar que aparezcan en logs
variable "db_password" {
description = "Database password"
type = string
sensitive = true
}
resource "kubernetes_secret" "db" {
metadata {
name = "database-credentials"
}
data = {
password = var.db_password
}
}
Para gestión avanzada de secrets, considera usar Vaultwarden o integrar con HashiCorp Vault.
Custom Resources y Terraform Kubernetes Provider
El Terraform Kubernetes Provider soporta Custom Resource Definitions (CRDs) mediante el recurso kubernetes_manifest.
Ejemplo: Desplegar un Ingress
resource "kubernetes_manifest" "nginx_ingress" {
manifest = {
apiVersion = "networking.k8s.io/v1"
kind = "Ingress"
metadata = {
name = "nginx-ingress"
namespace = kubernetes_namespace.app.metadata[0].name
annotations = {
"kubernetes.io/ingress.class" = "nginx"
"cert-manager.io/cluster-issuer" = "letsencrypt-prod"
}
}
spec = {
rules = [
{
host = "app.example.com"
http = {
paths = [
{
path = "/"
pathType = "Prefix"
backend = {
service = {
name = kubernetes_service.nginx.metadata[0].name
port = {
number = 80
}
}
}
}
]
}
}
]
}
}
}
Este enfoque funciona con cualquier CRD instalado en tu cluster, como Prometheus Operators, Istio VirtualServices, o Argo CD Applications.
Módulos Reutilizables con Terraform Kubernetes Provider
Para equipos que gestionan múltiples aplicaciones, crear módulos reutilizables es esencial. Aquí un ejemplo de estructura de módulo:
modules/
└── k8s-app/
├── main.tf
├── variables.tf
└── outputs.tf
Contenido de modules/k8s-app/main.tf:
resource "kubernetes_deployment" "app" {
metadata {
name = var.app_name
namespace = var.namespace
}
spec {
replicas = var.replicas
selector {
match_labels = {
app = var.app_name
}
}
template {
metadata {
labels = {
app = var.app_name
}
}
spec {
container {
image = var.image
name = var.app_name
dynamic "port" {
for_each = var.ports
content {
container_port = port.value
}
}
dynamic "env" {
for_each = var.environment_vars
content {
name = env.key
value = env.value
}
}
}
}
}
}
}
resource "kubernetes_service" "app" {
metadata {
name = var.app_name
namespace = var.namespace
}
spec {
selector = {
app = var.app_name
}
dynamic "port" {
for_each = var.service_ports
content {
port = port.value.port
target_port = port.value.target_port
}
}
type = var.service_type
}
}
Uso del módulo:
module "frontend_app" {
source = "./modules/k8s-app"
app_name = "frontend"
namespace = "production"
replicas = 5
image = "myapp/frontend:v1.2.0"
ports = [3000]
service_ports = [
{
port = 80
target_port = 3000
}
]
environment_vars = {
NODE_ENV = "production"
API_URL = "https://api.example.com"
}
}
Optimización y Best Practices del Terraform Kubernetes Provider
Estas son las mejores prácticas para usar el Terraform Kubernetes Provider en entornos de producción:
Organización del código
- Separar infraestructura de aplicaciones: Mantén la creación del cluster en un directorio separado del deployment de aplicaciones
- Usar workspaces: Gestiona múltiples entornos (dev, staging, prod) con Terraform workspaces
- Módulos por responsabilidad: Crea módulos para patrones repetitivos (apps stateless, bases de datos, ingress)
State management
- Backend remoto: Almacena el state en S3, Azure Blob, o Terraform Cloud
- State locking: Usa DynamoDB (AWS) o equivalente para prevenir modificaciones concurrentes
- Versionado del state: Habilita versionado en tu backend para recuperación ante errores
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "kubernetes/production/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-lock"
}
}
Seguridad
- RBAC estricto: Limita permisos del service account que usa Terraform
- Network Policies: Define políticas de red para restringir tráfico entre pods
- Pod Security Standards: Aplica PSS (restricted, baseline) en namespaces
- Secrets externos: Integra con HashiCorp Vault o AWS Secrets Manager
CI/CD
Integra Terraform en tu pipeline de CI/CD:
# Ejemplo GitHub Actions
name: Terraform Kubernetes
on:
push:
branches: [main]
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Init
run: terraform init
- name: Terraform Plan
run: terraform plan -out=plan.out
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: terraform apply plan.out
Para monitorear tu infraestructura K8s, considera implementar Uptime Kuma para monitoreo.
Troubleshooting Terraform Kubernetes Provider
Aquí están los errores más comunes y sus soluciones al trabajar con el Terraform Kubernetes Provider:
Error: Unable to connect to the server
Error: Get "https://kubernetes.default.svc": dial tcp: lookup kubernetes.default.svc
Causa: Terraform no puede conectarse al cluster de Kubernetes.
Solución:
# Verificar que kubectl funciona
kubectl cluster-info
# Verificar contexto actual
kubectl config current-context
# Actualizar provider con contexto correcto
provider "kubernetes" {
config_path = "~/.kube/config"
config_context = "nombre-contexto-correcto"
}
Error: Resource already exists
Error: namespaces "terraform-demo" already exists
Causa: El recurso ya existe en Kubernetes pero no está en el state de Terraform.
Solución: Importa el recurso existente:
terraform import kubernetes_namespace.app terraform-demo
Error: Field is immutable
Error: Service spec.selector is immutable
Causa: Intentas modificar un campo inmutable de Kubernetes.
Solución: Elimina y recrea el recurso:
# Forzar recreación
terraform taint kubernetes_service.nginx
terraform apply
# O usar replace (Terraform 1.0+)
terraform apply -replace="kubernetes_service.nginx"
Debugging avanzado
# Habilitar logs detallados
export TF_LOG=DEBUG
terraform apply
# Ver estado actual de un recurso
terraform state show kubernetes_deployment.nginx
# Listar todos los recursos en el state
terraform state list
Conclusión
El Terraform Kubernetes Provider es una herramienta esencial para equipos que practican infraestructura como código en entornos cloud-native. Al combinar Terraform con Kubernetes, obtienes gestión declarativa completa, control de versiones de tu infraestructura, y la capacidad de coordinar recursos K8s con servicios cloud externos en un único workflow.
Hemos cubierto desde la configuración básica hasta patrones avanzados como módulos reutilizables, gestión de secrets, y custom resources. Las ventajas clave incluyen previsualización de cambios con terraform plan, comprensión automática de dependencias, y state management que previene configuration drift.
Para producción, recuerda implementar backend remoto con locking, integración con sistemas de secrets externos como Vault, y pipelines de CI/CD que ejecuten plan/apply automáticamente. Combina este provider con otros recursos de Terraform para construir infraestructura completa desde la red hasta las aplicaciones.
Explora más tutoriales de infraestructura como código en nuestra sección de Docker Compose y continúa aprendiendo sobre automatización DevOps.
FAQ sobre Terraform Kubernetes Provider
¿Cuándo usar Terraform Kubernetes Provider vs kubectl?
Usa el Terraform Kubernetes Provider cuando necesites gestionar infraestructura completa como código, versionar cambios, o coordinar recursos K8s con servicios cloud (RDS, S3, etc.). Usa kubectl para debugging rápido, troubleshooting en vivo, o aplicar manifiestos YAML de terceros sin modificar.
¿El Terraform Kubernetes Provider puede crear clusters?
No directamente. El provider gestiona recursos dentro de un cluster existente. Para crear clusters, usa providers específicos como terraform-provider-aws (EKS), azurerm (AKS), o google (GKE). Una vez creado el cluster, el provider de Kubernetes gestiona las aplicaciones desplegadas en él.
¿Es seguro almacenar Secrets en Terraform?
No es recomendable. Los secrets en código Terraform aparecen en el state file en texto plano. En su lugar, integra con HashiCorp Vault, AWS Secrets Manager, o Azure Key Vault usando data sources. Otra opción es usar External Secrets Operator en Kubernetes y gestionarlo con el provider.
¿Puedo usar Terraform Kubernetes Provider con Helm?
Sí, son complementarios. Usa el Terraform Helm Provider para desplegar charts de Helm desde Terraform. Esto te permite combinar infraestructura base (managed by Terraform Kubernetes Provider) con aplicaciones empaquetadas (managed by Helm), todo desde el mismo workflow de Terraform.
¿Cómo gestiono múltiples clusters con el provider?
Usa alias de providers para gestionar múltiples clusters simultáneamente:
provider "kubernetes" {
alias = "prod"
config_path = "~/.kube/config-prod"
}
provider "kubernetes" {
alias = "staging"
config_path = "~/.kube/config-staging"
}
resource "kubernetes_namespace" "app_prod" {
provider = kubernetes.prod
# ...
}
Esto permite desplegar la misma configuración en múltiples clusters desde un único código Terraform.
