Airflow Docker Compose 快速启动测试实战:Breeze 驱动、手动运行与源码级原理解析
2026/9/11 16:26:03 网站建设 项目流程

Airflow Docker Compose 快速启动测试实战:Breeze 驱动、手动运行与源码级原理解析

【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflow

Apache Airflow 官方文档向用户提供了基于 Docker Compose 的快速启动(Quick Start)部署方案,它允许开发者在几分钟内用docker compose up拉起一套包含 webserver、scheduler、worker、triggerer 等组件的完整 Airflow 环境。为了让这套部署方案始终可用、可复现,Airflow 在 CI 中专门运行 "Test docker-compose quick start" 测试,本文基于仓库中的 docker_compose_tests.rst 贡献者文档,系统讲解如何用 Breeze 或 pytest 本地运行这套测试、如何保留并调试部署现场,并结合 docker-tests 下的真实测试源码,剖析这套测试的完整执行链路。读完本文,你将掌握 Airflow Docker Compose 部署测试的完整运行方法、关键参数与底层实现细节。

一、测试背景与设计动机

Airflow 在官方文档中通过 Running Airflow in Docker 向用户推荐 Docker Compose 快速启动方式。为了让文档中展示的这份docker-compose.yaml真正可用,而不是停留在纸面上,Airflow 项目在 CI 中持续对它进行验证——这就是docker-compose-tests测试组存在的意义。

需要特别说明的是,该测试不是在 Breeze CI 镜像内部运行的,而是在本地 Docker 环境中直接执行的。测试会使用COMPOSE_PROJECT_NAME设置为quick-start,以避免与你本机其他正在运行的 docker compose 部署发生命名冲突。

从 dev/breeze/src/airflow_breeze/commands/testing_commands_config.py 的测试分组定义可以看到,docker-compose-tests被归入 "Other Tests" 组,与system-testshelm-testspython-api-client-testsairflow-e2e-tests并列,属于集成验证性质的测试套件。

二、测试的工作方式:三步走

根据原文档描述,这套测试的整体流程非常直观,共分三步:

  1. 构建 Airflow 生产镜像(prod image):测试必须以本地已存在的 Airflow 生产镜像为蓝本;
  2. 启动 Docker Compose 部署:取出项目自带的docker-compose.yaml,用上一步构建的镜像把整套 Airflow 环境拉起来;
  3. 触发示例 DAG 并校验结果:通过简单的 DAG 触发测试,确认 Airflow 已经正常启动,并且能够真正调度、执行一个示例 DAG。

从 test_docker_compose_quick_start.py 的源码注释可以看到测试的定位:"Simple test which reproduce setup docker-compose environment and trigger example dag",即复现 docker-compose 环境的搭建并触发示例 DAG——这正是对文档描述的代码级印证。

三、运行前置条件

在运行 Docker Compose 测试之前,需要确认以下环境就绪:

  • Docker 引擎已安装并正常运行;
  • Docker Compose 可用docker-compose(v1 独立命令)或docker compose插件(v2)二者之一存在于PATH中。测试代码在 test_docker_compose_quick_start.py 中会先调用docker.compose.version()探测,若抛DockerException则直接pytest.fail("docker composenot available. Make sure compose plugin is installed"),即缺少 compose 时测试会立即失败并给出明确提示;
  • 内存充足:Airflow 的 Docker Compose 部署包含多个服务,请确保 Docker Engine 分配了足够内存(官方快速启动文档建议至少 4GB,理想 8GB)。

四、用 Breeze 运行完整测试

Breeze 是 Airflow 贡献者使用的开发环境管理工具,它将镜像构建与测试执行封装成一条龙命令。运行完整测试只需两条命令:

breeze prod-image build --python 3.10 breeze testing docker-compose-tests

第一条命令构建 Airflow 生产镜像(以 Python 3.10 为例),第二条命令执行 docker-compose 测试。测试对应的底层实现位于 dev/breeze/src/airflow_breeze/utils/run_tests.py 的run_docker_compose_tests()函数,其关键逻辑包括:

  • 先用docker inspect <image_name>检查镜像是否存在于本地,若不存在会提示 "The image ... does not exist locally. It should be build before running docker-compose tests.",并交互式询问是否立即构建;
  • 组装 pytest 命令在docker-tests目录下执行,默认追加-s参数,以便实时看到测试的 print 输出(测试源码也通过rich.console.Console输出大量运行日志);
  • 通过环境变量把参数传递给测试进程:DOCKER_IMAGE指定被测镜像、SKIP_DOCKER_COMPOSE_DELETION控制是否保留部署、AIRFLOW_UID使用当前用户 uid。

4.1 测试失败时的日志转储

测试过程中如果失败,Breeze 会把正在运行的各容器日志转储到控制台,随后关闭整个 Docker Compose 部署。在测试源码中,这一行为由print_diagnostics()函数实现(test_docker_compose_quick_start.py):它会依次输出健康检查结果、DAG Run 与 TaskInstance 状态、Docker 与 Docker Compose 版本、compose config渲染结果,以及每个服务的名称、状态、配置与完整日志,方便定位问题根因。

4.2 保留部署以便调试

默认情况下测试结束(无论成功或失败)都会执行compose.down(remove_orphans=True, volumes=True, quiet=True)删除部署。如果你需要保留部署现场进行调试,有两种方式:

  • 在 Breeze 命令中传递--skip-docker-compose-deletion标志;
  • 或者导出环境变量SKIP_DOCKER_COMPOSE_DELETION"true"

当该开关生效时,测试结束会打印 "Skipping docker-compose deletion",并输出一条可直接复制的docker compose ...命令前缀,方便你继续手动操作这套部署。

4.3 容器等待超时控制

可以用--wait-for-containers-timeout标志指定容器的最大等待超时时间;同时也可以给命令追加-s选项,将其透传给底层 pytest,以便实时观察测试输出(原文档特别注明该行为也可通过WAIT_FOR_CONTAINERS_TIMEOUT环境变量设置)。从测试源码看,DAG 状态的轮询等待上限为 400 秒(for _ in range(400)循环中每秒查询一次),--wait-for-containers-timeout正是用来调节这类容器就绪与执行等待窗口的参数。

五、手动运行 pytest 测试

除了 Breeze,你也可以在本地 Python 环境中直接运行 pytest:

pytest docker_tests/test_docker_compose_quick_start.py

手动运行的前提是:

  • 本地存在一个 Airflow venv,且安装了devextra(确保python_on_whalesrequestsrich等测试依赖可用,见 docker-tests/pyproject.toml);
  • 设置DOCKER_IMAGE环境变量,指向你要测试的镜像:
    export DOCKER_IMAGE=ghcr.io/apache/airflow/main/prod/python3.10:latest

    该变量在 constants.py 中定义默认值:ghcr.io/apache/airflow/main/prod/python3.10:latest——正是breeze prod-image build --python 3.10默认构建出的镜像;pytest fixturedefault_docker_image(见 conftest.py)会优先读取DOCKER_IMAGE,未设置时回落为默认镜像。

注意:手动运行 pytest 时,--skip-docker-compose-deletion--wait-for-containers-timeout这两个开关只能通过环境变量传递(即SKIP_DOCKER_COMPOSE_DELETIONWAIT_FOR_CONTAINERS_TIMEOUT),Breeze 的命令行标志在纯 pytest 场景下不生效。

六、调试保留下来的部署

如果你使用了SKIP_DOCKER_COMPOSE_DELETION保留了部署,想要用docker compose命令手动查看容器,需要先设置项目名,与测试保持一致:

export COMPOSE_PROJECT_NAME=quick-start

也可以在 docker compose 命令中显式添加--project-name quick-start。由于测试代码在创建 compose 客户端时指定了compose_project_name="breeze-quick-start"(见 test_docker_compose_quick_start.py),调试时请以实际输出的命令前缀为准。此外,测试每次重新运行时,会先自动compose.down关闭上一次的部署,再启动新部署,因此重复执行测试是安全的。

七、手动运行 Docker Compose 部署(独立于 pytest)

你还可以完全不经过 pytest,手动用刚构建的镜像拉起这套 Docker Compose 环境:

export AIRFLOW_IMAGE_NAME=ghcr.io/apache/airflow/main/prod/python3.10:latest

然后按照 Running Airflow in Docker 的指引操作,但务必使用仓库源码自带的 compose 文件:它位于仓库的airflow-core/docs/howto/docker-compose/docker-compose.yaml(测试代码也正是从AIRFLOW_ROOT_PATH / "airflow-core" / "docs" / "howto" / "docker-compose" / "docker-compose.yaml"复制该文件到临时目录后启动的)。随后即可用常规的docker compose/docker命令调试运行中的实例,也可以连接 Airflow 的 Web UI(默认localhost:8080)手动触发 DAG 做验证。

八、源码级剖析:测试到底做了什么

为了帮助读者深入理解这套测试,下面结合源码逐段拆解核心用例test_trigger_dag_and_wait_for_result(test_docker_compose_quick_start.py):

  1. 准备临时目录:用tmp_path_factory.mktemp("airflow-quick-start")创建独立目录,把仓库内的docker-compose.yaml复制进去,并创建dagslogspluginsconfig四个子目录(对应 compose 文件中的卷挂载点);
  2. 写入.env文件:内容为AIRFLOW_UID=<当前用户 uid>,确保容器内以当前用户身份运行,避免文件权限问题(compose 文件默认user: "${AIRFLOW_UID:-50000}:0");
  3. 清理旧部署:执行compose.down(remove_orphans=True, volumes=True, quiet=True),保证测试从干净状态开始;
  4. 启动部署compose.up(detach=True, wait=True, ...)拉起整套服务;
  5. 确保 DAG 已解析:在airflow-dag-processor服务中执行airflow dags reserialize,强制元数据库中的 DAG 序列化数据就绪;
  6. 健康检查:调用GET /api/v2/monitor/health,断言metadatabase.status == "healthy"
  7. 触发 DAG:先PATCH /api/v2/dags/example_simplest_dagis_paused置为false,再POST /api/v2/dags/example_simplest_dag/dagRuns创建一次 DAG Run(dag_run_id=test_dag_run_idlogical_date固定为2020-06-11T18:00:00+00:00);
  8. 轮询等待终态wait_for_terminal_dag_state()每秒查询一次 DAG Run 状态,最多等待 400 秒,直到进入successfailed
  9. 断言结果:最终断言 DAG Run 状态为success,否则测试失败并转储全部诊断日志。

所有 API 请求都通过api_request()封装(test_docker_compose_quick_start.py),它先借助tests_common.test_utils.api_client_helpers.generate_access_token获取 JWT 访问令牌,再携带Authorization: Bearer <token>请求/api/v2接口——这恰好验证了 Airflow 3.x 中由 FabAuthManager 负责认证、JWT 签发访问令牌的完整链路(compose 文件中也配置了AIRFLOW__CORE__AUTH_MANAGER为 FAB 认证管理器及AIRFLOW__API_AUTH__JWT_SECRET等参数)。

仓库还包含第二个用例test_airflow_uid_default_in_chown(test_docker_compose_quick_start.py):它渲染 compose 配置并断言airflow-init服务初始化命令中的chown参数——当未显式设置AIRFLOW_UID时,默认以50000作为用户 ID(chown -R "50000:0" /opt/airflow/),而不是空用户组写法。该用例守护了 compose 快速启动在默认参数下的文件权限正确性,也是文档中AIRFLOW_UID默认值 50000 的代码级证据。

九、测试运行的环境变量速查

结合原文档与源码,整理本测试涉及的全部环境变量与等效 Breeze 开关如下:

环境变量Breeze 开关默认值作用
DOCKER_IMAGE--image-name(间接)ghcr.io/apache/airflow/main/prod/python3.10:latest被测 Airflow 生产镜像
SKIP_DOCKER_COMPOSE_DELETION--skip-docker-compose-deletion未设置(即删除)测试结束后是否保留部署
WAIT_FOR_CONTAINERS_TIMEOUT--wait-for-containers-timeout由 pytest 调用约定容器就绪等待超时
COMPOSE_PROJECT_NAME--project-name(调试时)测试内部固定为breeze-quick-startDocker Compose 项目名,避免冲突
AIRFLOW_UID50000容器内运行 Airflow 的用户 ID
HOST_PORTlocalhost:8080API 服务访问地址(见测试源码DOCKER_COMPOSE_HOST_PORT
INCLUDE_SUCCESS_OUTPUTS--include-success-outputs未设置成功后是否同样转储诊断输出

十、总结

Airflow 的 Docker Compose 测试是一套"轻量而完整"的端到端验证:它构建生产镜像、拉起官方文档同款 compose 部署、通过 REST API 触发真实 DAG 并断言执行成功,从而保证对外发布的快速启动方案在每次代码变更后依然开箱即用。通过 Breeze 的breeze testing docker-compose-tests或直接运行 test_docker_compose_quick_start.py,任何贡献者都可以在本地复现 CI 中的这一验证环节;配合SKIP_DOCKER_COMPOSE_DELETION保留现场,再结合print_diagnostics转储的服务日志,即可高效定位部署或镜像相关问题。关于 Airflow 更广泛的测试体系(单元测试、集成测试、系统测试等),可进一步阅读 09_testing.rst 测试总览文档。

【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflow

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询