--- title: "Cómo instalar Apache Airflow con Docker en Ubuntu 24.04" description: "Instala Apache Airflow 3 con Docker Compose en Ubuntu 24.04, crea y prueba tu primer DAG, define conexiones y variables y publica la interfaz con Nginx y HTTPS." category: "Ingeniería de Datos" language: es source: https://cubepath.com/es/docs/ingeniería-de-datos/instalacion-y-configuracion-de-apache-airflow updated: 2026-09-25 --- # Cómo instalar Apache Airflow con Docker en Ubuntu 24.04 Apache Airflow es una plataforma para programar y monitorizar flujos de trabajo definidos en Python. Cada flujo es un DAG (grafo acíclico dirigido): un conjunto de tareas con dependencias que Airflow ejecuta según un calendario, con reintentos, registros por tarea e interfaz web. En este tutorial desplegarás Airflow 3 en Ubuntu 24.04 con el archivo de Docker Compose oficial (CeleryExecutor, PostgreSQL y Redis), escribirás y probarás un DAG, definirás conexiones y variables y publicarás la interfaz con Nginx y HTTPS. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 4 GB de RAM (8 GB recomendados), 2 vCPU y 20 GB libres en disco. Con menos memoria los contenedores de Airflow se reinician o no llegan a arrancar. - Un usuario no root con privilegios `sudo` que pertenezca al grupo `docker`. - Docker Engine y el plugin Docker Compose v2.14 o superior, instalados desde el repositorio oficial de Docker. - Un subdominio (en esta guía, `airflow.tu_dominio`) con un registro DNS A que apunte a la IP pública del servidor. - UFW activo con SSH permitido. > Importante: el archivo de Compose oficial está pensado para aprender y para entornos pequeños. El propio proyecto recomienda el chart de Helm sobre Kubernetes para producción. Esta guía añade lo mínimo para exponerlo de forma segura (puerto local, HTTPS, contraseña propia). ## Paso 1: Descargar el archivo de Docker Compose oficial Crea el directorio del proyecto y descarga el archivo de Compose de la versión estable de Airflow: ```bash mkdir -p ~/airflow cd ~/airflow curl -LfO 'https://airflow.apache.org/docs/apache-airflow/stable/docker-compose.yaml' ``` El archivo define estos servicios: | Servicio | Función | |---|---| | `postgres` | Base de datos de metadatos (DAG, ejecuciones, conexiones) | | `redis` | Cola de mensajes entre el scheduler y los workers | | `airflow-apiserver` | Interfaz web y API REST, en el puerto 8080 | | `airflow-scheduler` | Decide qué tareas ejecutar y cuándo | | `airflow-dag-processor` | Lee y analiza los archivos de DAG | | `airflow-worker` | Ejecuta las tareas (Celery) | | `airflow-triggerer` | Gestiona las tareas diferidas | | `airflow-init` | Migra la base de datos y crea el usuario inicial | En Airflow 2.x el servicio web se llamaba `airflow-webserver` y no existía `airflow-dag-processor`. Si descargas un archivo de una versión 2.x, adapta los nombres de los servicios en los comandos siguientes. ## Paso 2: Preparar directorios, usuario y puerto Crea los directorios que el archivo monta en los contenedores: ```bash mkdir -p ~/airflow/{dags,logs,plugins,config} ``` Crea el archivo `.env`. `AIRFLOW_UID` hace que los contenedores escriban con tu UID, de modo que los archivos de `dags` y `logs` sigan siendo tuyos. Las otras dos variables sustituyen el usuario por defecto `airflow`/`airflow`: ```bash nano ~/airflow/.env ``` ```ini AIRFLOW_UID=1000 _AIRFLOW_WWW_USER_USERNAME=admin _AIRFLOW_WWW_USER_PASSWORD=your_strong_password ``` Sustituye `1000` por el resultado de `id -u` y `your_strong_password` por una contraseña robusta. Protege el archivo: ```bash chmod 600 ~/airflow/.env ``` El archivo oficial publica la interfaz en todas las interfaces (`8080:8080`). Docker se salta las reglas de UFW, así que quedaría accesible desde Internet sin cifrar. Publícala solo en local: ```bash sed -i 's/"8080:8080"/"127.0.0.1:8080:8080"/' ~/airflow/docker-compose.yaml ``` Desactiva también los DAG de ejemplo, que llenan la interfaz con decenas de flujos de demostración: ```bash sed -i "s/AIRFLOW__CORE__LOAD_EXAMPLES: 'true'/AIRFLOW__CORE__LOAD_EXAMPLES: 'false'/" ~/airflow/docker-compose.yaml ``` Comprueba ambos cambios: ```bash grep -E '8080:8080|LOAD_EXAMPLES' ~/airflow/docker-compose.yaml ``` ```output AIRFLOW__CORE__LOAD_EXAMPLES: 'false' - "127.0.0.1:8080:8080" ``` ## Paso 3: Inicializar y arrancar Airflow El servicio `airflow-init` comprueba los recursos, migra la base de datos y crea el usuario administrador. Ejecútalo en primer plano para ver el resultado: ```bash cd ~/airflow docker compose up airflow-init ``` Al terminar debe salir con código 0: ```output airflow-init-1 exited with code 0 ``` Si aparece un aviso de memoria o CPU insuficientes, el servidor no cumple los requisitos y es probable que los servicios fallen más adelante. Arranca el resto de servicios en segundo plano: ```bash docker compose up -d ``` Tras uno o dos minutos, todos deben aparecer como `healthy`: ```bash docker compose ps --format "table {{.Service}}\t{{.Status}}" ``` ```output SERVICE STATUS airflow-apiserver Up 2 minutes (healthy) airflow-dag-processor Up 2 minutes (healthy) airflow-scheduler Up 2 minutes (healthy) airflow-triggerer Up 2 minutes (healthy) airflow-worker Up 2 minutes (healthy) postgres Up 3 minutes (healthy) redis Up 3 minutes (healthy) ``` ## Paso 4: Publicar la interfaz con Nginx y HTTPS Instala Nginx y Certbot: ```bash sudo apt update sudo apt install nginx certbot python3-certbot-nginx ``` Crea el bloque de servidor: ```bash sudo nano /etc/nginx/sites-available/airflow ``` ```nginx server { listen 80; listen [::]:80; server_name airflow.tu_dominio; location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } ``` Activa el sitio, valida la configuración y recarga Nginx: ```bash sudo ln -s /etc/nginx/sites-available/airflow /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` Abre los puertos web y solicita el certificado: ```bash sudo ufw allow 'Nginx Full' sudo certbot --nginx -d airflow.tu_dominio ``` ```output Congratulations! You have successfully enabled HTTPS on https://airflow.tu_dominio ``` Abre `https://airflow.tu_dominio` e inicia sesión con el usuario y la contraseña del archivo `.env`. Como has desactivado los ejemplos, la lista de DAG estará vacía. ## Paso 5: Escribir tu primer DAG Airflow detecta cualquier archivo Python en `~/airflow/dags`, montado en los contenedores como `/opt/airflow/dags`. Crea un DAG sencillo de extracción, transformación y carga: ```bash nano ~/airflow/dags/etl_ejemplo.py ``` ```python from datetime import datetime, timedelta from airflow.providers.standard.operators.bash import BashOperator from airflow.sdk import dag, task @dag( schedule="0 6 * * *", start_date=datetime(2026, 1, 1), catchup=False, default_args={"retries": 2, "retry_delay": timedelta(minutes=5)}, tags=["ejemplo"], ) def etl_ejemplo(): @task def extraer() -> list[int]: return [12, 7, 30] @task def transformar(valores: list[int]) -> int: return sum(valores) @task def cargar(total: int) -> None: print(f"Total procesado: {total}") avisar = BashOperator( task_id="avisar", bash_command='echo "ETL terminado para {{ ds }}"', ) cargar(transformar(extraer())) >> avisar etl_ejemplo() ``` Qué define este archivo: - `schedule="0 6 * * *"` ejecuta el DAG cada día a las 06:00 UTC. También admite valores como `@daily` o `@hourly`. - `catchup=False` evita que Airflow lance ejecuciones atrasadas desde `start_date` hasta hoy al activarlo. - `retries` y `retry_delay` reintentan dos veces una tarea fallida, con cinco minutos de espera. - Las funciones con `@task` (API TaskFlow) se pasan los resultados entre sí; Airflow deduce las dependencias. `>>` añade una dependencia explícita con el `BashOperator`. > Nota: este DAG usa los módulos de Airflow 3 (`airflow.sdk` y el proveedor `standard`). En Airflow 2.x los equivalentes son `from airflow.decorators import dag, task` y `from airflow.operators.bash import BashOperator`. ## Paso 6: Validar y ejecutar el DAG El procesador de DAG revisa la carpeta periódicamente, así que el DAG puede tardar un par de minutos en aparecer. Comprueba primero que no hay errores de importación: ```bash docker compose exec airflow-scheduler airflow dags list-import-errors ``` ```output No data found ``` Si hay un error de sintaxis o un import incorrecto, este comando muestra el archivo y la traza. Confirma que Airflow ya conoce el DAG: ```bash docker compose exec airflow-scheduler airflow dags list | grep etl_ejemplo ``` Ejecuta una prueba completa sin esperar al calendario. `airflow dags test` ejecuta todas las tareas en un solo proceso y muestra sus registros en la terminal: ```bash docker compose exec airflow-scheduler airflow dags test etl_ejemplo ``` Entre la salida deberías ver el resultado de la tarea `cargar`: ```output ... Total procesado: 49 ``` Los DAG nuevos están pausados por defecto. Actívalo y lanza una ejecución real, que pasará por el scheduler y los workers de Celery: ```bash docker compose exec airflow-scheduler airflow dags unpause etl_ejemplo docker compose exec airflow-scheduler airflow dags trigger etl_ejemplo ``` En la interfaz web, abre el DAG `etl_ejemplo`: verás la ejecución en la vista de cuadrícula y, al hacer clic en cada tarea, sus registros. ## Paso 7: Definir conexiones y variables Las conexiones guardan los datos de acceso a sistemas externos para no escribirlos en el código de los DAG. Crea una conexión a PostgreSQL con una URI: ```bash docker compose exec airflow-scheduler airflow connections add postgres_origen \ --conn-uri 'postgres://usuario:your_db_password@db.tu_dominio:5432/ventas' ``` Compruébala: ```bash docker compose exec airflow-scheduler airflow connections get postgres_origen ``` Las tareas la usan por su identificador, por ejemplo con `PostgresHook(postgres_conn_id="postgres_origen")` del proveedor de PostgreSQL, incluido en la imagen oficial. Las variables guardan valores de configuración que cambian entre entornos: ```bash docker compose exec airflow-scheduler airflow variables set entorno produccion docker compose exec airflow-scheduler airflow variables get entorno ``` ```output produccion ``` Léelas dentro de una tarea, no en el nivel superior del archivo. El código de nivel superior se ejecuta cada vez que Airflow analiza el DAG y consultaría la base de datos continuamente: ```python from airflow.sdk import Variable, task @task def mostrar_entorno() -> None: print(Variable.get("entorno")) ``` Las conexiones y variables también se gestionan desde la interfaz, en el menú **Admin**. ## Paso 8: Operación diaria Algunos comandos útiles desde `~/airflow`: - Ver los registros del scheduler: `docker compose logs -f airflow-scheduler`. - Reiniciar todo tras cambiar `docker-compose.yaml` o `.env`: `docker compose up -d`. - Parar Airflow conservando los datos: `docker compose down`. Con `docker compose down -v` se borra también el volumen de PostgreSQL con todo el historial. Los registros de las tareas se acumulan en `~/airflow/logs` y pueden ocupar mucho con el tiempo. Revisa su tamaño periódicamente: ```bash du -sh ~/airflow/logs ``` Para añadir paquetes de Python que necesiten tus DAG, no los instales dentro de los contenedores en ejecución: se pierden al recrearlos. Crea una imagen propia a partir de `apache/airflow` con un `Dockerfile` y cambia la línea `image:` del archivo de Compose, como indica la documentación oficial. ## Solución de problemas **El DAG no aparece en la interfaz.** Espera un par de minutos y ejecuta `airflow dags list-import-errors`. Comprueba también que el archivo está en `~/airflow/dags` y que tiene la llamada final `etl_ejemplo()` que registra el DAG. **Las tareas se quedan en estado `queued`.** No hay workers disponibles. Revisa `docker compose ps` y `docker compose logs airflow-worker`; si el worker se reinicia, suele ser por falta de memoria. **Errores `Permission denied` en `logs` o `dags`.** `AIRFLOW_UID` en `.env` no coincide con tu usuario. Corrígelo, ajusta el propietario con `sudo chown -R $(id -u):0 ~/airflow/{dags,logs,plugins,config}` y recrea los contenedores con `docker compose up -d`. **502 Bad Gateway en Nginx.** `airflow-apiserver` aún está arrancando o no está sano. Revisa su estado y sus registros con `docker compose logs airflow-apiserver`. ## Conclusión Tienes Apache Airflow 3 funcionando con Docker Compose, CeleryExecutor, PostgreSQL y Redis, con la interfaz protegida por HTTPS y un DAG probado de principio a fin. Como siguientes pasos puedes configurar notificaciones por correo o Slack para tareas fallidas, crear una imagen propia con las dependencias de tus DAG y versionar la carpeta `dags` en un repositorio Git para desplegar cambios de forma controlada.