Por qué alojar Apache Airflow en tu propio VPS
Los orquestadores en la nube como Cloud Composer (Google) o MWAA (Amazon) incluyen Airflow como servicio gestionado, pero cobran el entorno por hora, independientemente de tu carga real. El alojamiento autónomo en un VPS significa que solo pagas el servidor, y tus DAGs se ejecutan cerca de tus fuentes de datos internas sin tránsito de red externo. La libertad va más allá: eliges la versión de Airflow, los providers de Python, las conexiones a bases de datos y el ejecutor. Para pipelines con datos sensibles o entornos regulados, mantenerse on-premise con un VPS dedicado no es una opción sino un requisito.
Qué orquesta Airflow en la práctica
- Pipelines de datos y ETL — extraer desde APIs o bases de datos, transformar y cargar en un data warehouse.
- Flujos de trabajo de ML — entrenamiento de modelos, evaluación, despliegue automatizado con dependencias entre pasos.
- Tareas programadas complejas — backfills, catchups, reintentos configurables por tarea.
- Integraciones con terceros — más de 80 providers oficiales: PostgreSQL, MySQL, S3, BigQuery, dbt, Spark, Kubernetes, HTTP.
- Pipelines de informes — generación automática de informes periódicos y entrega por correo o Slack.
- Orquestación de microservicios — lanzar trabajos remotos vía API y esperar su resultado antes de continuar.
Requisitos del VPS y stack técnico
Airflow es el stack más exigente en recursos de esta categoría en modo CeleryExecutor, ya que ejecuta varios servicios en paralelo. Para producción: mínimo 4 vCPU y 8 GB de RAM. Para desarrollo o pruebas: 2 vCPU y 4 GB de RAM son suficientes en LocalExecutor. Prevé 40 GB de disco SSD para logs y metadatos. Requisitos de software: Docker 24+ y Docker Compose v2, Ubuntu 22.04 LTS o Debian 12, y un nombre de dominio apuntando a tu VPS para el reverse proxy HTTPS.
Arquitectura Docker Compose de Airflow
El archivo docker-compose.yaml oficial de Airflow despliega seis servicios que forman una arquitectura completa. El webserver sirve la interfaz gráfica en el puerto 8080. El scheduler es el núcleo del sistema: analiza los DAGs y programa las tareas. El worker ejecuta las tareas asignadas. El triggerer gestiona las tareas diferibles. PostgreSQL es la base de datos de metadatos. Redis sirve como broker de mensajes entre el scheduler y los workers de Celery.
Desplegar Airflow 3.x con Docker Compose
Obtener el docker-compose oficial y crear directorios
Crea el directorio de trabajo, descarga el archivo de referencia y prepara las carpetas:
mkdir -p /opt/airflow && cd /opt/airflow curl -LfO 'https://airflow.apache.org/docs/apache-airflow/stable/docker-compose.yaml' mkdir -p ./dags ./logs ./plugins ./configConfigurar el archivo .env (UID, PostgreSQL, clave secreta)
Crea
/opt/airflow/.envcon las variables esenciales:echo "AIRFLOW_UID=$(id -u)" > .env echo "AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=postgresql+psycopg2://airflow:airflow@postgres/airflow" >> .env echo "AIRFLOW__CORE__FERNET_KEY=$(python3 -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())')" >> .envFERNET_KEYcifra las conexiones y variables — genérala una sola vez y guarda una copia de seguridad.Inicializar la base de datos
Aplica las migraciones y crea la primera cuenta de administrador:
docker compose up airflow-initEspera el código de salida
0— cualquier otro código indica un problema de conexión a PostgreSQL.Iniciar todos los servicios
Lanza el stack completo en segundo plano:
docker compose up -d docker compose psTodos los contenedores deben alcanzar el estado
healthyen uno a tres minutos.Crear una cuenta de administrador personalizada
Crea tu cuenta permanente:
docker compose exec airflow-webserver airflow users create \ --username admin --firstname Nombre --lastname Apellido \ --role Admin --email [email protected] \ --password TuContraseñaSeguraExponer Airflow detrás de un reverse proxy con SSL
Nunca expongas el puerto 8080 directamente. Con Caddy:
apt install -y caddy cat > /etc/caddy/Caddyfile << 'EOF' airflow.tudominio.com { reverse_proxy localhost:8080 } EOF systemctl reload caddy && ufw deny 8080
Configurar PostgreSQL como backend de metadatos
Nunca uses SQLite en producción con Airflow en Docker. SQLite no está diseñado para accesos concurrentes múltiples: el scheduler, el webserver y los workers acceden a la base de datos simultáneamente, y SQLite en volúmenes Docker tiene limitaciones de bloqueo que causan corrupción y pérdida de datos. Verifica que tu .env fuerza explícitamente la conexión a PostgreSQL:
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=postgresql+psycopg2://airflow:airflow@postgres/airflowHaz copias de seguridad regularmente: docker compose exec postgres pg_dump -U airflow airflow > backup_$(date +%Y%m%d).sql.
Pasar al CeleryExecutor para múltiples workers
El LocalExecutor ejecuta tareas como subprocesos del scheduler — simple pero limitado a un solo nodo. El CeleryExecutor desacopla la ejecución: el scheduler empuja tareas a una cola Redis, y uno o más workers las consumen de forma independiente. Para escalar horizontalmente:
docker compose up -d --scale airflow-worker=3Esto inicia tres workers consumiendo la misma cola Redis en paralelo.
Gestionar conexiones y variables secretas
Airflow cifra las conexiones y variables sensibles en la base de datos usando FERNET_KEY. Vía UI: Admin → Connections → Add Connection. Vía variables de entorno: una variable prefijada con AIRFLOW_CONN_ anula cualquier conexión almacenada en la base de datos:
AIRFLOW_CONN_MY_POSTGRES=postgresql://user:password@host:5432/dbnameSecret Backend: para entornos Kubernetes o cloud, configura el proveedor de secretos apropiado (AWS Secrets Manager, HashiCorp Vault).
Crear y probar tu primer DAG Python
Crear el archivo DAG en la carpeta /dags
Crea
/opt/airflow/dags/mi_primer_dag.py:from airflow.sdk import DAG, task from datetime import datetime with DAG( dag_id='mi_primer_dag', schedule='@daily', start_date=datetime(2025, 1, 1), catchup=False, ) as dag: @task def extraer(): return {'filas': 42} @task def transformar(datos): return datos['filas'] * 2 @task def cargar(resultado): print(f'Resultado: {resultado}') cargar(transformar(extraer()))Verificar que el scheduler analiza el DAG sin errores
Verifica manualmente:
docker compose exec airflow-scheduler airflow dags list | grep mi_primer_dagSi el DAG no aparece tras 30 segundos, busca errores de análisis:
docker compose logs airflow-scheduler | grep -i 'error\|exception' | tail -20Lanzar una ejecución manual e inspeccionar logs
En la UI de Airflow, navega a DAGs, encuentra
mi_primer_dag, actívalo y haz clic en ▶ Trigger DAG. Desde el terminal:docker compose exec airflow-scheduler airflow dags trigger mi_primer_dag
Securizar tu instalación Airflow
Una instalación Airflow expone potencialmente conexiones de bases de datos, variables y logs de ejecución. Deshabilitar DAGs de ejemplo:
AIRFLOW__CORE__LOAD_EXAMPLES=FalseFirewall en puerto 8080: ufw deny 8080. Autenticación: configura LDAP u OAuth2 para organizaciones. Rotación de secretos: usa airflow db rotate-fernet-key si necesitas cambiar FERNET_KEY.
LocalExecutor vs CeleryExecutor vs KubernetesExecutor
Desplace la tabla
| Criterio | LocalExecutor | CeleryExecutor | KubernetesExecutor |
|---|---|---|---|
| Recursos necesarios | 2 vCPU / 4 GB RAM | 4 vCPU / 8 GB RAM + Redis | Clúster Kubernetes requerido |
| Paralelismo | Limitado a CPUs del scheduler | Horizontal — workers según necesidad | Un pod por tarea — casi ilimitado |
| Aislamiento de tareas | Subprocesos compartidos | Workers separados, misma imagen | Pod aislado por tarea |
| Complejidad operacional | Simple — sin Redis | Moderada — Redis que mantener | Alta — Kubernetes requerido |
| Caso de uso ideal | Dev, pruebas, pipelines ligeros | Producción VPS, carga variable | Cloud-native, aislamiento fuerte |
Actualizar Airflow sin interrupción
Para una actualización rolling sin interrumpir los DAGs en curso:
docker compose stop airflow-webserver airflow-scheduler
docker compose pull
docker compose up -d airflow-webserver airflow-scheduler
docker compose exec airflow-scheduler airflow db upgrade
docker compose up -dSiempre conserva una copia de seguridad reciente de PostgreSQL antes de cualquier actualización de versión.
Depurar y leer los logs de Airflow
Logs de tareas: cada tarea escribe en ./logs/dag_id/run_id/task_id/. Logs del scheduler: los más importantes para diagnosticar DAGs que no se lanzan:
docker compose logs airflow-scheduler --follow --tail=100Errores silenciosos: si un DAG desaparece de la UI sin mensaje:
docker compose exec airflow-webserver airflow dags list-import-errorsPurga de logs: configura AIRFLOW__LOG_RETENTION_DAYS=30 para evitar la saturación del disco.