Airflow es un orquestador de procesos relativamente nuevo pero que está ganando popularidad velozmente debido a su amplísima funcionalidad, su interfaz de uso intuitiva y el hecho de estar programado enteramente en Python. Incluso Google lo ha definido como servicio de orquestación nativo en sus servicios de cloud. Si quieres saber más sobre qué es y lo que se puede hacer con Airflow, te recomiendo la lectura de este artículo donde lo explicamos con más detalle.

Requisitos y consideraciones

Para seguir esta guía se presuponen conocimientos de Docker y PostgreSQL. En el ejemplo propuesto vamos a ejecutar Airflow sobre un contenedor linux en Windows 10, por tanto se deberá de tener instalada la versión de docker para este S.O. Docker Desktop. Todas las demás aplicaciones que usaremos corren sobre Docker, por tanto no hay necesidad de instalar nada más. Si estás usando alguna distribución de Linux, este tutorial también te servirá, pero algunos de los pasos que daremos aquí no son necesarios.

Docker

Docker no necesita introducción, ya que ha cambiado de forma radical la forma de desarrollar y desplegar aplicaciones en los últimos años. No obstante, hemos de tener cuidado de no caer en el “hype” innecesariamente, ya que hay casos en los que disponibilizar nuestra aplicación en forma de contenedor puede introducir una capa de complejidad adicional que podríamos evitar. Esta situación se puede dar por ejemplo cuando necesitamos que nuestra aplicación se nutra de algún tipo de almacenamiento persistente como es, precisamente, el caso de Airflow. Entonces, ¿por qué usar Docker para este fin? Las razones que nos han llevado a plantearlo así son la dificultad para instalar Airflow en distintos sistemas y la portabilidad entre entornos.

Persistencia de datos

Para poder ejecutar, Airflow necesita un backend en forma de base de datos que almacena, por ejemplo, el resultado de las ejecuciones de los DAGs en un histórico y otra serie de datos como pueden ser variables y configuraciones de conexiones a sistemas remotos. Por defecto, Airflow instancia una base de datos sqlite dentro del propio directorio de Airflow donde se almacena esta información. Es la configuración por defecto y la más sencilla ya que no requiere de una base de datos externa. Sin embargo, esta estrategia tiene dos problemas. El primero afecta al rendimiento, ya que esta base de datos no permite ejecuciones de tareas en paralelo. Segundo, y esto viene introducido por el uso de Docker, cada vez que reiniciemos el contenedor, toda esta información se perderá y Airflow no tendrá manera trazar las ejecuciones pasadas.

Para solventar ambos problemas, una de las opciones posibles es recurrir a una base de datos externa. Airflow soporta un montón de opciones pero en este caso nos hemos decidido por Postgres ya que mejora el rendimiento de Airflow, es sencillo de implementar y la documentación necesaria se puede encontrar con facilidad en internet.

Se podría instalar un servidor de PostgreSQL en la máquina local y acceder a él desde Airflow, pero en este caso hemos decidido que la BBDD se encuentre también en un contenedor para mantener nuestro sistema base más limpio y además para poder replicar la configuración en cualquier sistema distinto del nuestro en segundos gracias a docker-compose.

Contenedor de Airflow

Por supuesto para poder ejecutar esta aplicación de la forma arriba descrita necesitamos correr dos contenedores a la vez, uno con el propio Airflow y otro con un Postgres. Existe una imagen oficial de Apache Airflow en Docker Hub, pero en este caso, para tener control absoluto sobre el proceso, vamos a generarla nosotros mismos, usando el siguiente Dockerfile:

#Dockerfile
FROM python:3.7
RUN pip3 install 'apache-airflow' 'psycopg2'

Fácil, ¿no? Hemos comentado que Airflow está escrito enteramente en Python, por lo que partimos de la imagen oficial de Python 3.7 y lo instalamos, junto con una librería para conectar con Postgres.

Finalmente construimos la imagen con:

docker build -t airflow .

Con esto hemos finalizado la parte de Airflow.

Contenedor de PostgreSQL

En este caso usaremos simplemente la versión actualizada de Postgres disponible en Docker Hub, por lo tanto no necesitamos disponer un Dockerfile para generarlo.

Sin embargo, hay un detalle que sí hemos de tener en cuenta, relacionado con el asunto del almacenamiento persistente. Como comentábamos al principio, Airflow necesita que su BBDD backend mantenga la información para poder trazar su histórico, pero siendo que hemos decidido crear nuestra BBDD en un contenedor, los datos almacenados en ella son efímeros. Para solucionar esto, una forma sencilla sería mapear el directorio donde Postgres guarda sus datos (/var/lib/postgresql/data) a un directorio en nuestra máquina local, sin embargo, esto en Windows no funciona por un problema de permisos con el usuario postgres de nuestra BBDD (el usuario por defecto de la BBDD del contenedor de Postgres).

Una forma elegante de sortear este problema es crear un volumen de Docker en Windows, que no es nada más que un espacio en disco gestionado por Docker que nos permite precisamente mantener nuestros datos entre ejecuciones de contenedores, cumpliendo así nuestro requisito de persistencia. Podemos crear el volumen de esta forma:

docker volume create --name=db_data

Y con esto ya estaríamos listos para completar nuestro setup.

Levantar nuestra instancia de Airflow con Docker-compose

Recapitulando, hasta ahora hemos:

Por tanto estamos ya listos para encarar el paso final, que no es otro que levantar los dos contenedores y comprobar que se comunican entre ellos correctamente. Para ello, haremos uso de la herramienta compose que viene instalada por defecto con Docker Desktop.

Compose nos permite instanciar varios contenedores con un solo comando y además genera automáticamente una red, de forma que todos los contenedores se ven entre ellos y se pueden identificar usando sus nombres como hostnames. Además, nos permite rematar las configuraciones necesarias y mapear los datos de disco, los volúmenes y puertos que necesitamos. Para lograr todo ello, lo hacemos así:

# docker-compose.yml
services:
  postgres:
    image: postgres
    container_name: pg_airflow
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=MYPASSWORD

  webserver:
    image: airflow1-10:patched
    container_name: airflow
    restart: always
    depends_on:
      - postgres
    environment:
      - LOAD_EX=n
      - AIRFLOW__CORE__EXECUTOR=LocalExecutor
      - AIRFLOW__CORE__SQL_ALCHEMY_CONN=\
                    postgresql+psycopg2://postgres:MYPASSWORD@pg_airflow/postgres
    volumes:
      - C:\airflow_home:/root/airflow/dags
      # Uncomment to include custom plugins
      # - ./plugins:/usr/local/airflow/plugins
    ports:
      - "8080:8080"
    command: bash -c "airflow initdb && (airflow scheduler &) && airflow webserver"
volumes:
    db_data:
      external: true

Hay dos services, el primero de los cuales es el Postgres. Debemos especificar que el directorio donde guarda los datos Postgres (/var/lib/postgresql/data) se mapee al volumen que hemos creado anteriormente. De esta forma lograremos un almacenamiento persistente de dichos datos. Además, tendremos que especificar la contraseña del usuario que se conectará a la BBDD, que por defecto se llama postgres.

A continuación configuramos el servicio webserver con la imagen de Airflow que hemos creado anteriormente. Necesitamos incluir dos variables de entorno importantes para que Airflow se conecte a nuestra BBDD Postgres en vez de al sqlite que viene por defecto, y estas son:

postgresql+psycopg2://[user]:[pwd]@[hostname]/[nombre de BBDD]

Por tanto lo único que hemos de verificar es que el hostname corresponde con el contenedor de Postgres y las contraseñas coinciden.

Además de todo esto, vamos a mapear un directorio local de nuestra elección al directorio donde Airflow busca los DAGs (las definiciones de las tareas que tiene que realizar) y que será donde podamos empezar a programar nuestros scripts. Hemos elegido para este fin C:\airflow_home.

¡Ya está todo! Lo único que resta es lanzar el proceso con compose y comprobar que todo se ha ejecutado como debería. Esto lo hacemos con:

docker compose up -d

Una vez están los dos contenedores levantados y listos, nos podemos conectar a Airflow simplemente escribiendo:

localhost:8080

en nuestro navegador. Para pararlos, procedemos simplemente a ejecutar el comando:

docker-compose down

¡A disfrutar con Airflow!

Conclusión

Hemos visto cómo, en determinadas circunstancias, puede ser interesante levantar aplicaciones que requieren datos persistentes en contenedores efímeros y cómo podemos hacer para asegurarnos de que mantenemos esa persistencia. Además, hemos logrado configurar una aplicación fácilmente exportable que se levanta en segundos en cualquier entorno que soporte Docker.

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.