Запускалась ли каждая задача (task) в Airflow в отдельном pod?

Ответ

Да, в одном из проектов мы использовали KubernetesPodOperator для запуска каждой задачи в изолированном pod Kubernetes. Это обеспечивало:

  • Изоляцию зависимостей: Каждая задача могла иметь свой Docker-образ с уникальным набором библиотек и версий Python.
  • Гибкость ресурсов: Возможность задания запросов и лимитов CPU/RAM (resources) индивидуально для тяжеловесных задач.
  • Чистое окружение: Задача выполнялась в свежем pod, что исключало побочные эффекты от предыдущих выполнений.

Пример оператора:

from airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator

data_processing_task = KubernetesPodOperator(
    task_id="process_data",
    namespace="airflow",
    image="my-registry/data-pipeline:latest",
    cmds=["python", "/scripts/process.py"],
    arguments=["{{ ds }}"],
    name="process-data-pod",
    get_logs=True,
    is_delete_operator_pod=True,  # Pod удаляется после выполнения
    resources={
        'request_memory': '512Mi',
        'request_cpu': '250m'
    }
)

Для менее требовательных задач мы использовали стандартный PythonOperator, где задачи выполнялись в общих воркерах.

Ответ 18+ 🔞

А, ну это классика, ёпта! В одном из проектов мы так замутили, что каждая задача в Airflow летала в своём собственном KubernetesPodOperator, как будто в отдельной капсуле. Представляешь? Каждой таске — свой личный космический корабль-под. И знаешь, зачем этот ёперный театр?

  • Зависимости, блядь, изолированы: Одна задача может орать, что ей нужен Python 3.11 с кучей свежих либ, а другая — сидеть на древнем 3.7. И они друг другу не мешают, потому что каждая в своём Docker-образе, как в отдельной квартире. Никаких "ой, а у меня версия конфликтует" — красота!
  • Ресурсы гибкие: Одна задача — лёгкая мартышлюшка, ей памяти чуть-чуть. А другая — монстр, который жрёт оперативки овердохуища. Так вот для каждой можно прописать свои аппетиты (resources), и никто никого не задавит.
  • Чистота, сука: После выполнения под накрывается медным тазом (удаляется). Следующая задача стартует в абсолютно чистом окружении. Никаких следов от предыдущего запуска, никакого мусора. Идеальный порядок, ядрёна вошь!

Вот, смотри, как это выглядело в коде:

from airflow.providers.cncf.kubernetes.operators.pod import KubernetesPodOperator

data_processing_task = KubernetesPodOperator(
    task_id="process_data",
    namespace="airflow",
    image="my-registry/data-pipeline:latest",
    cmds=["python", "/scripts/process.py"],
    arguments=["{{ ds }}"],
    name="process-data-pod",
    get_logs=True,
    is_delete_operator_pod=True,  # Под удаляется после выполнения — чистота!
    resources={
        'request_memory': '512Mi',
        'request_cpu': '250m'
    }
)

А для всякой мелкой работы, где не надо городить огород, мы просто юзали обычный PythonOperator. Там задачи бегали в общих воркерах, как тараканы по кухне. Быстро, просто, без изысков. Главное — инструмент под задачу, а не наоборот.