Как использовать DockerOperator с apache airflow на windows host - PullRequest
1 голос
/ 20 января 2020

Я успешно разработал локально очень простой процесс ETL (называемый load_staging ниже), который извлекает данные из некоторого удаленного местоположения, а затем записывает эти необработанные данные в контейнер MongoDB на моей локальной машине Windows. Теперь я хочу запланировать этот процесс с Apache -Airflow, используя DockerOperator для каждой задачи, т.е. я хочу создать docker образ моего исходного кода и затем выполнить исходный код в этом образе с помощью DockerOperator. Поскольку я работаю на машине windows, я могу использовать Airflow только из контейнера docker.

Я запустил контейнер воздушного потока (называемый ниже веб-сервером) и контейнер MongoDB (называемый mon * 1038). * ниже) с docker-compose up, и я вручную вызвал DAG в GUI Airflow. Согласно Airflow, задача успешно выполняется, но кажется, что код внутри образа docker не выполняется, потому что задача завершается слишком рано и сразу после запуска контейнера docker из моего образа, задача выполняется с кодом ошибки 0, то есть я не вижу никаких результатов регистрации самой задачи. Смотрите журналы ниже:

[2020-01-20 17:09:44,444] {{docker_operator.py:194}} INFO - Starting docker container from image myaccount/myrepo:load_staging_op
[2020-01-20 17:09:50,473] {{logging_mixin.py:95}} INFO - [[34m2020-01-20 17:09:50,472[0m] {{[34mlocal_task_job.py:[0m105}} INFO[0m - Task exited with return code 0[0m

Итак, два моих вопроса:

  1. Я пришел к правильному выводу или что еще может быть root этой проблемы?
  2. Как убедиться, что код внутри изображения всегда выполняется?

Ниже вы можете найти дополнительную информацию о том, как я настраиваю DockerOperator, как я определяю изображение, которое должно выполняться DockerOperator, файл docker-compose.yml, запускающий веб-сервер, и mon go Containers и Dockerfile, используемый для создания контейнера веб-сервера.

В моем файле определения DAG я указал DockerOperator следующим образом:

CONFIG_FILEPATH = "/configs/docker_execution.ini"
data_object_name = "some_name"
task_id_ = "{}_task".format(data_object_name)
cmd = "python /src/etl/load_staging_op/main.py --config_filepath={} --data_object_name={}".format(CONFIG_FILEPATH, data_object_name)
staging_op = DockerOperator(
            command=cmd,
            task_id=task_id_,
            image="myaccount/myrepo:load_staging_op",
            api_version="auto",
            auto_remove=True
)

Dockerfile для изображения load_staging_op, на которое есть ссылки выше выглядит следующим образом:

# Inherit from Python image
FROM python:3.7

# Install environment
USER root
COPY ./src/etl/load_staging_op/requirements.txt ./
RUN pip install -r requirements.txt

# Copy source code files into container
COPY ./configs /configs
COPY ./wsdl /wsdl
COPY ./src/all_constants.py /src/all_constants.py
COPY ./src/etl/load_staging_op/utils.py /src/etl/load_staging_op/utils.py
COPY ./src/etl/load_staging_op/main.py /src/etl/load_staging_op/main.py

# Extend python path so that custom modules are found
ENV PYTHONPATH "${PYTHONPATH}:/src"

ENTRYPOINT [ "sh", "-c"]

Соответствующие аспекты файла docker-compose.yml выглядят следующим образом:

version: '2.1'
services:
    webserver:
        build: ./docker-airflow
        restart: always
        privileged: true
        depends_on:
            - mongo
            - mongo-express
        volumes:
            - ./docker-airflow/dags:/usr/local/airflow/dags
            # source code volume
            - ./src:/src
            - ./docker-airflow/workdir:/home/workdir
            # Mount the docker socket from the host (currently my laptop) into the webserver container
            # so that we can build docker images from inside the webserver container.
            - //var/run/docker.sock:/var/run/docker.sock  # the two "//" are needed for windows OS
            - ./configs:/configs
            - ./wsdl:/wsdl
        ports:
            # Change port to 8081 to avoid Jupyter conflicts
            - 8081:8080
        command: webserver
        healthcheck:
            test: ["CMD-SHELL", "[ -f /usr/local/airflow/airflow-webserver.pid ]"]
            interval: 30s
            timeout: 30s
            retries: 3
        networks:
            - mynet

    mongo:
        container_name: mymongo
        image: mongo
        restart: always
        ports:
            - 27017:27017
        networks:
            - mynet

Dockerfile для контейнера веб-сервера, на который есть ссылка в приведенном выше Dockerfile, выглядит следующим образом :

FROM puckel/docker-airflow:1.10.4

# Adds DAG folder to the PATH
ENV PYTHONPATH "${PYTHONPATH}:/src:/usr/local/airflow/dags"

# Install the optional packages
COPY requirements.txt requirements.txt  # make sure something like docker==4.1.0 is in this requirements.txt file!
USER root
RUN pip install -r requirements.txt

# Install docker inside the webserver container
RUN curl -sSL https://get.docker.com/ | sh
ENV SHARE_DIR /usr/local/share

# Install simple text editor for debugging
RUN ["apt-get", "update"]
RUN ["apt-get", "-y", "install", "vim"]

Спасибо за помощь, я очень ценю это!

1 Ответ

0 голосов
/ 21 января 2020

Я искренне благодарю всех, кто нашел время, чтобы помочь мне с моей проблемой. Мне нужно было внести следующие изменения, чтобы заставить его работать:

DockerOperator:

  • Настройте команду, передаваемую контейнеру во время выполнения, т.е. когда контейнер собран
  • Добавьте параметр network_mode в сеть, в которой работает контейнер веб-сервера. Это было трудно для меня, так как я новичок в Docker и не смог найти много учебников по этому вопросу в Интернете. Чтобы найти имя сети, в которой работает контейнер веб-сервера, я перечислил все текущие активные сети на моем хосте (= windows ноутбук), используя что-то вроде docker network ls. В списке отображаемых сетей я увидел сеть, которая называлась чем-то вроде project_root_dirname_mynet, поэтому комбинация каталога root моего проекта и имени сети, указанного в файле docker-compose.yml. Интересно (и, очевидно, тогда), перечислив все сети, вы можете проверить сеть project_root_dirname_mynet, используя что-то вроде docker network inspect project_root_dirname_mynet. Это вернет файл json с подразделом «контейнеры», в котором вы можете увидеть все контейнеры, указанные в вашем файле docker-compose.yml.

Код для DockerOperator становится следующим:

cmd = "--config_filepath {} --data_object_name {}".format(CONFIG_FILEPATH.strip(), data_object_name.strip())
print("Command: {}".format(cmd))
staging_op = DockerOperator(
    command=cmd,
    task_id=task_id_,
    image="myaccount/myrepo:load_staging_op",
    api_version="auto",
    auto_remove=True,
    network_mode="project_root_dirname_mynet"
)

Dockerfile задачи load_staging_op:

  • Изменить последнюю строку с ENTRYPOINT [ "sh", "-c"] на ENTRYPOINT [ "python", "/src/etl/load_staging_op/main.py"]. Я думаю, что аргумент "python" откроет консоль Python в контейнере, а второй аргумент - это просто путь к сценарию, который вы хотите выполнить внутри контейнера docker. Затем во время выполнения (или во время сборки, или как это называется) аргументы командной строки из cmd выше будут переданы. В исходном коде изображения вы можете использовать библиотеку, например argparse, для получения этих команд.
...