python - 如何在 Windows 主机上使用 Apache 气流中的 DockerOperator
问题描述
我已经成功地在本地开发了一个超级简单的 ETL 过程(下面称为 load_staging),它从某个远程位置提取数据,然后将未处理的数据写入我本地 Windows 机器上的 MongoDB 容器中。现在,我想为每个任务使用 DockerOperator 使用 Apache-Airflow 来安排这个过程,即我想为我的源代码创建一个 docker 映像,然后使用 DockerOperator 执行该映像中的源代码。由于我在 Windows 机器上工作,我只能从 docker 容器内使用 Airflow。
我已经启动了气流容器(下面称为 webserver)和 MongoDB 容器(下面称为 mongo),docker-compose up
并且我在 Airflow 的 GUI 中手动触发了 DAG。根据 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
所以,我的两个问题是:
- 我是否得出了正确的结论,或者还有什么可能是这个问题的根源?
- 如何确保图像中的代码总是被执行?
您可以在下面找到有关如何设置 DockerOperator、如何定义应该由 DockerOperator 执行的映像、docker-compose.yml
启动 webserver 和 mongo 容器的文件以及用于创建 webserver 容器的 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
)
上面引用的图像的 Dockerfileload_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 中引用的 webserver 容器的 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"]
感谢您的帮助,我非常感谢!
解决方案
我衷心感谢所有花时间帮助我解决问题的人。我需要实施以下更改以使其工作:
码头工人:
- 调整在运行时传递给容器的命令,即在构建容器时
- 使用运行 webserver 容器的网络添加参数
network_mode
。这对我来说很难,因为我是 Docker 新手,在网上找不到太多关于此的教程。为了找到运行 webserver 容器的网络名称,我使用类似docker network ls
. 在显示的网络列表中,我看到一个名为 的网络,它是project_root_dirname_mynet
我项目的根目录和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"
)
load_staging_op 任务的 Dockerfile:
- 将最后一行从 更改
ENTRYPOINT [ "sh", "-c"]
为ENTRYPOINT [ "python", "/src/etl/load_staging_op/main.py"]
。我认为“python”参数将在容器中打开一个 Python 控制台,第二个参数只是您要在 docker 容器中执行的脚本的路径。然后,在运行时(或构建时,或者无论如何调用它),cmd
上面的命令行参数将被传递。在图像的源代码中,您可以使用类似的库argparse
来检索这些命令。
推荐阅读
- java - 是否可以序列化 WebSocket 连接对象并在另一台服务器上重用它?
- wordpress - Wordpress / Elementor / Ninjaforms - 挑战:If else / 销售计算
- python-3.x - 获取有关子进程的信息
- r - 如何一次运行多个外循环?
- python - Python - 如何按索引替换列表中的字符 - 遗传算法
- r - 我写的 R 函数没有改变列值
- development-environment - 如何设置环境以在 Django 项目中编写/测试 Clarity 智能合约
- tensorflow - 尺寸必须相等,但为 25 和 50。输入形状:[5,25]、[5,50]
- discord.py - Bot 命令查看参数是否为 int
- typescript - 如何在 typescript eslint 配置中启用标准命名约定的警告?