ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Docker 化数据处理管道:Data Engineering Zoomcamp 中 Dockerfile 的构建、运行与 uv 实践

Docker 化数据处理管道:Data Engineering Zoomcamp 中 Dockerfile 的构建、运行与 uv 实践 Docker 化数据处理管道Data Engineering Zoomcamp 中 Dockerfile 的构建、运行与 uv 实践【免费下载链接】data-engineering-zoomcampData Engineering Zoomcamp is a free 9-week course on building production-ready data pipelines. Join the course here 项目地址: https://gitcode.com/GitHub_Trending/da/data-engineering-zoomcamp本篇指南聚焦 Data Engineering Zoomcamp 模块一中的核心实操环节——将 Python 数据管道容器化Dockerizing the Pipeline。围绕 03-dockerizing-pipeline.md 的完整脉络我们从为什么需要容器化讲起先后给出基于 pip 与基于 uv 的两套 Dockerfile 完整写法与逐行拆解并延伸到构建、传参运行、可复现构建、镜像缓存等工程细节最后结合仓库中真实的 pipeline/Dockerfile 与后续的 ingestion 管道、Docker Compose 编排展示这套方法如何演进为生产可用的数据接入方案。读完本文你将能够独立为任意 Python 数据管道编写、构建、调试并运行 Docker 镜像。为什么要把数据管道 Docker 化在进入 Dockerfile 之前先回顾一个关键背景一个典型的数据管道接收数据如 CSV 文件作为输入经转换后输出更多数据如 Parquet 文件、PostgreSQL 表或数据仓库。在 02-virtual-environment.md 中我们已经用uv建立了 Python 虚拟环境来管理 pandas、pyarrow 等依赖但虚拟环境仍依赖本机的 Python 解释器与系统环境。Docker 解决的是环境一致性问题。正如 01-introduction.md 所述Docker 提供三大核心优势可复现性Reproducibility同一份镜像在任何装有 Docker 的机器上行为完全一致隔离性Isolation应用彼此独立运行互不干扰可移植性Portability镜像可以随处运行也可直接推送到 AWS、GCP 等云平台执行。这正是数据工程中生产可用的基石同一个镜像既能在本地调试也能交给 AWS Batch、Kubernetes 等调度系统在云端跑批。容器化的基本思路很简单把系统安装依赖 复制脚本 定义启动命令这几步写进一个声明式文件Dockerfile用docker build构建出镜像快照再用docker run启动容器执行管道。第一个 Dockerfile基于 pip 的简单写法原文档给出的第一版 Dockerfile 非常直观适用于依赖较少的脚本# base Docker image that we will build on FROM python:3.13.11-slim # set up our image by installing prerequisites; pandas in this case RUN pip install pandas pyarrow # set up the working directory inside the container WORKDIR /app # copy the script to the container. 1st name is source file, 2nd is destination COPY pipeline.py pipeline.py # define what to do first when the container runs # in this example, we will just run the script ENTRYPOINT [python, pipeline.py]指令逐行解读指令作用说明FROM指定基础镜像选用python:3.13.11-slimslim 变体体积更小且自带 Python 3.13 运行时RUN在构建阶段执行命令这里安装 pandas 与 pyarrow该层会被 Docker 缓存依赖未变时不重复执行WORKDIR设置容器内工作目录/app不存在时会自动创建后续COPY、ENTRYPOINT都基于该目录COPY把宿主文件拷入镜像第一个参数是源文件宿主侧第二个参数是目标路径容器侧ENTRYPOINT定义容器启动时的默认命令使用 JSON 数组exec 形式等价于启动后直接执行python pipeline.py关于镜像标签FROM python:3.13.11-slim中python是镜像名3.13.11-slim是 tag不写 tag 时会默认拉取latest但生产实践中强烈建议固定版本以保证可复现性。构建镜像假设pipeline.py与Dockerfile位于同一目录在该目录下执行docker build -t test:pandas .-t test:pandas给镜像命名test、打标签pandas若省略标签如-t test将默认使用latest末尾的.构建上下文build contextDocker 会把这个目录内的文件发送给守护进程COPY引用的源文件必须位于其中。运行容器并传递参数容器化后的脚本需要接收命令行参数比如管道要处理哪一天的数据。用docker run在镜像名之后追加参数即可docker run -it test:pandas some_number参数some_number会被追加到ENTRYPOINT命令之后最终等价于在容器内执行python pipeline.py some_number。这里-it表示以交互式interactive配合伪终端tty方式运行便于观察输出。运行后你会看到与本地直接执行python pipeline.py some_number完全一致的输出——这正是容器环境即代码的体现。注意pipeline.py依赖的 pandas、pyarrow 已通过RUN pip install固化在镜像里因此本地机器上无需再安装任何依赖。升级方案基于 uv 的 Dockerfilepip install的写法虽简单但存在两个工程隐患依赖安装顺序不稳定、缺少锁文件导致今天能装、明天装不上。课程推荐使用uv——一个用 Rust 编写的现代 Python 包与项目管理器它比 pip 更快且能自动管理虚拟环境。uv 在本仓库中被贯穿使用从本地开发02-virtual-environment.md 中的uv init、uv add、uv run一路延续到容器构建。uv 版本的 Dockerfile 完整写法如下# Start with slim Python 3.13 image FROM python:3.13.10-slim # Copy uv binary from official uv image (multi-stage build pattern) COPY --fromghcr.io/astral-sh/uv:latest /uv /bin/ # Set working directory WORKDIR /app # Add virtual environment to PATH so we can use installed packages ENV PATH/app/.venv/bin:$PATH # Copy dependency files first (better layer caching) COPY pyproject.toml uv.lock .python-version ./ # Install dependencies from lock file (ensures reproducible builds) RUN uv sync --locked # Copy application code COPY pipeline.py pipeline.py # Set entry point ENTRYPOINT [uv, run, python, pipeline.py]与 pip 版本的差异与理由COPY --fromghcr.io/astral-sh/uv:latest /uv /bin/这是多阶段构建的经典模式——从官方 uv 镜像中把编译好的 uv 可执行文件复制进当前镜像无需在构建时联网安装 uv。注意此指令要求 Docker 支持 BuildKit现代 Docker 默认开启。ENV PATH/app/.venv/bin:$PATHuv 会在项目内创建.venv虚拟环境把它加入PATH后后续命令可直接使用虚拟环境中的可执行文件。先拷贝依赖清单、再安装COPY pyproject.toml uv.lock .python-version ./放在COPY pipeline.py之前利用 Docker 层缓存——只要依赖清单没变RUN uv sync --locked这一层就不会重新执行大幅加速反复构建。RUN uv sync --locked严格依据uv.lock锁文件安装依赖锁定每个依赖的精确版本保证一次锁定、处处一致的可复现构建。ENTRYPOINT [uv, run, python, pipeline.py]容器启动时通过uv run在虚拟环境上下文中执行脚本确保使用的正是锁文件声明的依赖集合。仓库中的真实实现本仓库 pipeline/Dockerfile 正是这一模式的直接落地并针对真实数据接入脚本做了微调FROM python:3.13.11-slim COPY --fromghcr.io/astral-sh/uv:latest /uv /bin/ WORKDIR /code ENV PATH/code/.venv/bin:$PATH COPY pyproject.toml .python-version uv.lock ./ RUN uv sync --locked COPY ingest_data.py . ENTRYPOINT [python, ingest_data.py]与之配套的 pipeline/pyproject.toml 声明了管道所需的全部运行时依赖[project] name pipeline version 0.1.0 requires-python 3.13 dependencies [ click8.3.1, pandas2.3.3, psycopg2-binary2.9.11, pyarrow22.0.0, sqlalchemy2.0.44, tqdm4.67.1, ] [dependency-groups] dev [ jupyter1.1.1, pgcli4.3.0, ]两点值得注意开发依赖与运行时依赖分离jupyter、pgcli属于[dependency-groups].dev构建镜像时uv sync --locked只安装dependencies部分从而把镜像体积控制在最小锁文件即真相uv.lock与.python-version由uv add/uv init自动生成与pyproject.toml一并拷入容器--locked模式下任何版本漂移都会导致构建失败从机制上杜绝环境不一致。构建与运行docker build -t test:pandas . docker run -it test:pandas some_number命令与 pip 版本完全一致——对使用者透明这正是 Dockerfile 的价值所在内部实现无论用 pip 还是 uv对外都收敛为一个镜像、一条 run 命令。容器参数传递与管道输入在上一节的示例中pipeline.py通过sys.argv接收参数如day int(sys.argv[1])因此docker run test:pandas 10即可让容器内管道处理第 10 天的数据。到了真实的数据接入场景参数数量会显著增加。查看 pipeline/ingest_data.py可以看到它用click定义了一组完整、带默认值的命令行选项click.command() click.option(--pg-user, defaultroot, helpPostgreSQL user) click.option(--pg-pass, defaultroot, helpPostgreSQL password) click.option(--pg-host, defaultlocalhost, helpPostgreSQL host) click.option(--pg-port, default5432, typeint, helpPostgreSQL port) click.option(--pg-db, defaultny_taxi, helpPostgreSQL database name) click.option(--year, default2021, typeint, helpYear of the data) click.option(--month, default1, typeint, helpMonth of the data) click.option(--target-table, defaultyellow_taxi_data, helpTarget table name) click.option(--chunksize, default100000, typeint, helpChunk size for reading CSV)此时传参给容器与传参给管道是同一回事运行方式为在镜像名后追加--keyvaluedocker run -it \ taxi_ingest:v001 \ --pg-userroot \ --pg-passroot \ --pg-hostpgdatabase \ --pg-port5432 \ --pg-dbny_taxi \ --target-tableyellow_taxi_trips这种参数外置、镜像通用的设计让同一个镜像可以服务于不同的库、表、时间窗口无需为每种情况重新构建镜像。从单容器到多容器编排Docker Compose容器化管道通常不是孤立运行的。在 Data Engineering Zoomcamp 的完整链路中PostgreSQL 数据库与 pgAdmin 管理界面都以容器方式运行参见 04-postgres-docker.md 的docker run -e ... -v ... -p 5432:5432 postgres:18命令。手动维护多条docker run命令既繁琐又易错因此课程引入 Docker Compose用一个 YAML 文件声明全部服务。仓库中的 pipeline/docker-compose.yaml 定义了 Postgres 与 pgAdmin 两个服务services: pgdatabase: image: postgres:18 environment: POSTGRES_USER: root POSTGRES_PASSWORD: root POSTGRES_DB: ny_taxi volumes: - ny_taxi_postgres_data:/var/lib/postgresql ports: - 5432:5432 pgadmin: image: dpage/pgadmin4 environment: PGADMIN_DEFAULT_EMAIL: adminadmin.com PGADMIN_DEFAULT_PASSWORD: root volumes: - pgadmin_data:/var/lib/pgadmin ports: - 8085:80 volumes: ny_taxi_postgres_data: pgadmin_data:关键点在于Compose 会自动创建虚拟网络服务之间按服务名相互发现因此运行容器化 ingestion 脚本时只需把--pg-host指向服务名pgdatabase并通过--network指定 Compose 生成的网络命名规则为目录名 _default。这与 08-dockerizing-ingestion.md 和 09-docker-compose.md 中描述的流程完全一致docker-compose up -d # 后台启动全部服务 docker network ls # 查看 Compose 自动创建的网络 docker run -it --rm \ --networkpipeline_default \ taxi_ingest:v001 \ --pg-userroot --pg-passroot \ --pg-hostpgdatabase --pg-port5432 \ --pg-dbny_taxi --target-tableyellow_taxi_trips docker-compose down # 停止服务加 -v 可同时删除卷至此一条完整的数据链路——容器化 Postgres 容器化 pgAdmin 容器化 ingestion 管道——全部由声明式文件驱动这正是生产级数据管道的基础形态。工程实践要点小结回顾整个容器化过程可以沉淀出几条可复用的经验固定基础镜像版本python:3.13.x-slim中显式写明版本号避免latest漂移导致环境变化优先使用锁文件 uv sync --locked依赖版本以uv.lock为准构建可复现利用层缓存先 COPY 依赖清单、后 COPY 应用代码代码变更时不必重装依赖显著加速迭代构建分离开发/运行时依赖构建镜像只装dependenciesdev组jupyter、pgcli 等留在本地控制镜像体积参数外置通过ENTRYPOINT 命令行参数让同一镜像适配不同库表与数据日期编排交给 Compose多容器场景用docker-compose.yaml声明服务、网络与卷docker-compose up -d一键拉起。从 02-virtual-environment.md 的本地虚拟环境到本文的 pip / uv 两版 Dockerfile再到 08-dockerizing-ingestion.md 的完整 ingestion 容器化与 09-docker-compose.md 的多服务编排这一路径完整展示了数据工程中环境即代码、管道可移植、部署一键化的核心思想——也是后续模块工作流编排、数仓、批处理所有实践的地基。【免费下载链接】data-engineering-zoomcampData Engineering Zoomcamp is a free 9-week course on building production-ready data pipelines. Join the course here 项目地址: https://gitcode.com/GitHub_Trending/da/data-engineering-zoomcamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表