拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Airflow CI 失败本地复现完整实战:用 Breeze 把失败现场拉回你电脑

Airflow CI 失败本地复现完整实战用 Breeze 把失败现场拉回你电脑【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflow如果你的 Apache Airflow PR 在 CI 上挂了不必对着日志盲猜。本文用 BreezeAirflow 的 Docker 命令 Python 封装器完整演示 Airflow CI 本地复现一条命令加载失败 CI 运行产出的镜像进入与 CI 完全一致的环境交互式跑测试定位根因以及在必须本地构建镜像时如何避免依赖漂移。全文覆盖路线选型、分步实操、变量速查表和源码级的实现细节。CI 又红了先停止猜日志想象一下你提交了 PR二十分钟后 CI 结果回来Some checks were not successful——25 项通过2 项失败。接下来最常见的错误动作是盯着失败日志里滚动而过的 traceback改一行推上去再等二十分钟。这个循环既慢又不可靠因为你的本地环境和 CI 环境根本不是同一个东西。Airflow 开发团队给 CI 定了一条原则无论测试和集成基础设施多复杂开发者都应在本地复现并重跑任何失败的检查。落地手段就是 Breeze——它本质上是对 docker 命令的封装能在你机器上重建 CI 的容器环境并让你直接交互。复现之前有个关键前提Airflow 的所有 CI 作业都是按顺序执行的breeze命令序列。要精确复现某个作业你必须同时关注 CI 作业日志里的两样东西传给breeze命令的 flags命令行参数运行breeze时设置的环境变量——同一个作业甚至整个 workflow 里需要给所有命令设置公共 flag 时就用环境变量例如VERBOSE在所有 workflow 里都是true用于打印内部命令的更多细节。这两样东西都能从作业输出日志里直接找到缺一不可。把失败现场搬回电脑的 3 条路线在动手之前先明确你手上有什么、想要什么。复现 CI 失败共有三条路线保真度和便捷性各不相同路线前提能得到什么局限加载 CI 镜像breeze ci-image loadGitHub tokenAMD 机器与失败运行 100% 一致的镜像可直接进容器调试不能直接改源码除非配合检出分支检出 PR 分支 常规breeze命令能访问该 PR 分支可挂载本地源码、用 IDE 正常开发无需重建镜像依赖与 CI 运行时刻可能已有微小差异本地构建镜像breeze ci-image build检出对应分支完全自主控制构建依赖漂移风险最高仅在无法加载镜像时使用日常优先级很清楚能 load 就 load需要改代码就检出分支build 是最后的手段。下面按这个顺序展开。一条命令加载 CI 失败现场加载 CI 镜像的完整流程先按 PR 或 Run ID 把该次 CI 运行产出的镜像工件下载下来再docker image load进本地。两个入口分别是按 PR 号和按 Run IDRun ID 可从 GitHub Actions 的运行列表获取breeze ci-image load --from-pr 12345 --python 3.10 --github-token your_github_tokenbreeze ci-image load --from-run 12538475388 --python 3.10 --github-token your_github_token使用注意只要指定了--from-run或--from-pr--github-token就是强制项源码里会直接校验并报错退出--python要和失败运行使用的 Python 版本一致它参与拼镜像文件名加载完成后默认会删除下载的 tar 文件可用--skip-image-file-deletion保留verbose 模式下会顺带打印docker images -a供你确认加载成功时会调用mark_image_as_rebuilt标记镜像已就绪避免后续 breeze 命令误判需要重建镜像而重新构建。一个硬性限制要提前知道该功能目前只支持 AMD 架构机器不支持 ARM文档注明这一限制即将改变。不挂载本地源码进入与 CI 完全一致的环境镜像在手下一步是进容器。这里有个容易踩错的参数——--mount-sourcesbreeze shell --mount-sources skip [OPTIONS][OPTIONS]对应你要复现的那个作业在 CI 日志里出现的 flags 与环境变量。而skip的含义是不挂载本地源码容器里呈现的是 CI 镜像的原始内容。这正是精确复现的关键——只要你挂上了自己电脑上的代码环境和 CI 就已经不同了。在这个环境里即使你没有检出失败 PR 的源码也能交互式运行任意测试和命令直接复现失败现场。需要说明的是skip并不是唯一取值mount_sources还支持挂载全部源码all、仅测试tests、providers 与测试、移除挂载等模式源码会在 shell_params.py 中按模式拼接不同的 docker compose 文件而且MOUNT_SOURCES的取值还会被写入容器环境供容器内初始化逻辑感知当前的挂载方式。如果你的目标不只是复现失败而是要修复它更顺手的做法是检出 PR 对应分支后使用常规breeze命令本地源码会按惯例挂载进容器你可以像平时开发 Airflow 一样用 IDE 编辑文件且这种情况下即便依赖有变化、CI 用了新发布的包也无需重建镜像即可复现环境。更多测试体系细节见 测试指南。本地构建镜像为什么更不可靠3 个依赖漂移原因当无法加载镜像时比如工件已过期你只能检出失败 PR 的分支后本地构建breeze ci-image build配合--python、--platform等选项指定版本与平台--python-versions可一次并行构建多个 Python 版本--push构建后推送--docker-cache控制缓存策略constraints 相关还有--airflow-constraints-location和--airflow-constraints-mode-ci两个选项控制来源与模式。但必须接受一个事实你本地构建出来的镜像很可能和 CI 里那个不一样。漂移来自三个方向constraints 文件变了。普通构建依赖 constraints 锁定版本而构建发生的时间点不同锁定结果就不同PyPI 发布了新包。Airflow 生态每天发布大量包CI 构建后哪怕只过了几小时可用版本集合就可能变化canary 构建和部分 PR 根本不用 constraints。这类构建设置了UPGRADE_TO_NEWER_DEPENDENCIEStrue对应 flag--upgrade-to-newer-dependencies如果你本地重建时不带这个 flag装出来的依赖完全对不上。所以官方文档的结论很明确breeze ci-image load才是复现 CI 构建更可靠的方式因为它直接复用 CI 产出的镜像工件而不是在你这个时间点重新解析依赖。CI 作业里用到的变量速查表复现作业时你需要把 CI 作业实际使用的变量搬到本地。这些变量既能作为环境变量直接设置也能转化为传给breeze shell的对应命令行 flag。下表按你复现时实际要操心的顺序重新组织本地开发一列的值来自官方文档*表示在 prek hooks 场景下为 true环境与版本类——决定跑在什么解释器、什么后端、哪个提交上变量等价 flagCI 中典型值 / 本地默认说明PYTHON_MAJOR_MINOR_VERSION--python—Python 主/次版本BACKEND--backend—测试使用的后端数据库INTEGRATION--integration—测试使用的集成组件COMMIT_SHA无取自GITHUB_SHA构建所基于的提交 SHAHOST_OS无CI 为linux本地从 os 推导宿主机系统darwin/linux/windowsHOST_USER_ID/HOST_GROUP_ID无本地自动取宿主机 UID/GID宿主机用户与组 id数据库与测试范围类——控制测试集的大小和数据库状态变量等价 flagCI 中典型值 / 本地默认说明DB_RESET--db-reset/--no-db-resetCI 为true本地false容器入口处是否重置数据库ANSWER--answerCI 为yes提问是否自动应答RUN_DB_TESTS_ONLY--run-db-tests-only数据库测试中为true是否只跑数据库测试SKIP_DB_TESTS--skip-db-tests非数据库测试中为true是否跳过数据库测试SKIP_PROVIDERS_TESTS无false是否跳过 provider 集成测试非 main 分支容器初始化与调试类——控制容器启动时的环境准备变量等价 flagCI 中典型值 / 本地默认说明MOUNT_SOURCES--mount-sourcesCI 为skip是否把本地源码挂载进容器SKIP_ENVIRONMENT_INITIALIZATION--skip-environment-initialization双方均false*跳过测试环境初始化SKIP_IMAGE_UPGRADE_CHECK--skip-image-upgrade-check双方均false*跳过镜像是否需要升级检查SKIP_SSH_SETUP无本地falseCIfalse*CodeSpaces 中为true跳过为测试配置 SSH 服务器VERBOSE_COMMANDS无false是否打印 docker 中执行的每条命令其中HOST_*和COMMIT_SHA这一组在本地运行时由 Breeze 自动设置一般不用你管只在跨环境复现时才需要显式覆盖。CI 日志背后两个值得知道的实现细节理解下面两个细节会帮你判断日志里那些信息能不能直接信。日志里的本地复现指令是自动生成的不是人贴的。仓库里有专门的 reproduce_ci.py它的 docstring 写明自己是Helpers for printing local reproduction instructions in CI logs。它从 click 的Context重建 CLI 调用build_reproduction_command_from_context遍历命令的每个参数用ctx.get_parameter_source()识别哪些值来自 COMMANDLINE / ENVIRONMENT / PROMPT——也就是只输出用户或 CI 显式提供的参数取默认值的直接省略对--flag/--no-flag成对选项只输出被显式设置的那一侧。所以你在 CI 日志里看到的那条可复制命令信息是完整且自洽的放心直接拷到本地执行。ci-image load为什么比本地 build 可信看它的流程就明白了。在 ci_image_commands.py 的load实现里先做环境校验再基于--python和--github-repository构造构建参数平台字符串里的/会被替换成_用于拼出ci-image-save-v3-{platform}-{python}.tar这样的工件文件名接着做强制 token 校验然后按--from-run或--from-pr分别调用download_artifact_from_run_id/download_artifact_from_pr从 github.py 拉取工件最后执行docker image load -i加载若指定--tag-as还会docker tag重命名。它从头到尾没有重新解析依赖这个动作——这正是它保真度高的根本原因。从CI 红了到修复提交一次完整走查把上面的零件串起来一次完整的排查是这样走的。你打开失败作业的日志先抄下breeze命令的完整 flags 和作业设置的环境变量顺手确认VERBOSEtrue这类公共变量也在。然后优先走加载路线breeze ci-image load --from-run run_id --python version --github-token token把那次运行的镜像原封不动搬下来。接着breeze shell --mount-sources skip加上日志里抄来的 options 进容器在精确的 CI 环境里重跑失败的测试——此时你看到的每一个报错都是 CI 当时看到的。要动手改代码时检出 PR 分支改用常规breeze命令让本地源码挂载进容器IDE 照常打开镜像不用重建。只有在镜像工件拿不到、被迫本地breeze ci-image build时才需要额外核对该 PR 是否属于 canary / 特殊构建要不要追加--upgrade-to-newer-dependencies并接受构建结果与 CI 存在依赖差异的可能。这个闭环——从CI 红了到本地复现、修复、提交——完全可以在本地完成不需要在 CI 上反复试错。这正是 Airflow 把 CI 可复现性当作一等公民来设计的初衷细节还可以结合 Breeze 文档 与 CI 运行说明 继续深入。【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门