Data Engineering Zoomcamp:使用 Docker 运行 PostgreSQL 数据库的完整实战指南

Data Engineering Zoomcamp:使用 Docker 运行 PostgreSQL 数据库的完整实战指南 Data Engineering Zoomcamp使用 Docker 运行 PostgreSQL 数据库的完整实战指南【免费下载链接】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 课程第 1 周 Docker SQL 模块讲解如何在无需任何本地安装步骤的前提下用 Docker 容器运行 PostgreSQL 数据库从docker run启动命令、环境变量与数据卷配置、命名卷与绑定挂载的取舍到使用 pgcli 客户端连接数据库并执行基础 SQL。读完本文后你将能够在本地快速拉起一个带持久化存储的 Postgres 实例为后续将纽约出租车数据集写入数据库、搭建完整数据管道打下坚实的基础。为什么用 Docker 运行 PostgreSQL在 Data Engineering Zoomcamp 的实战流程中见 docker-sql/README.md从数据管道的容器化03-dockerizing-pipeline.md一路推进到把真实数据写入数据库05-data-ingestion.md数据库是数据管道落地的那一头。而 PostgreSQL 正是这个阶段选用的核心存储。传统做法是去官网下载 PostgreSQL 安装包并完成系统级安装但这种方式存在几个痛点安装过程依赖操作系统类型和版本环境差异大数据库版本升级、多项目共存容易引发冲突后续要写脚本、跑管道时数据库的启动与配置难以自动化。Docker 提供了一条零安装的路径容器化的 Postgres 镜像已经打包好了完整的数据库引擎你只需要向容器提供几个环境变量用于初始化用户、密码和数据库名以及一个数据卷用于持久化数据就能启动一个可用的数据库实例。这正是本模块在 04-postgres-docker.md 中给出的思路。在容器中运行 PostgreSQL第一步准备数据存储目录由于容器文件系统是临时的容器删除后即丢失Postgres 的数据必须存放在容器之外。先在任意位置为 Postgres 创建数据存储目录本文沿用课程示例名称ny_taxi_postgres_data。说明这个目录名在后续所有环节都会反复出现——无论是docker run命令、辅助脚本还是docker-compose.yaml它就是这条管道数据库数据的家。第二步运行容器docker run -it --rm \ -e POSTGRES_USERroot \ -e POSTGRES_PASSWORDroot \ -e POSTGRES_DBny_taxi \ -v ny_taxi_postgres_data:/var/lib/postgresql \ -p 5432:5432 \ postgres:18参数逐项拆解参数含义说明-it交互式终端模式让容器在前台运行日志直接输出到当前终端便于观察启动过程--rm退出即删除容器容器停止后自动清理容器本身不会删除卷中的数据-e POSTGRES_USERroot设置环境变量指定数据库超级用户名这里为root-e POSTGRES_PASSWORDroot设置环境变量指定超级用户密码这里为root仅限本地开发场景-e POSTGRES_DBny_taxi设置环境变量指定要自动创建的数据库名这里为ny_taxi-v ny_taxi_postgres_data:/var/lib/postgresql挂载数据卷创建一个named volume命名卷把容器内的数据目录映射到 Docker 管理的持久化存储-p 5432:5432端口映射将容器内的 5432 端口映射到宿主机的 5432 端口外部程序才能访问postgres:18镜像名使用 PostgreSQL 18 官方镜像截至 2025 年 12 月的最新版本三个环境变量的作用需要特别说明Postgres 官方镜像在首次启动时会读取POSTGRES_USER、POSTGRES_PASSWORD、POSTGRES_DB完成初始化——创建用户、设置密码并建立数据库。因此首次启动时这三者的组合就决定了你后续连接数据库要用的凭据。在本课程中它们被统一设置为root / root / ny_taxi并在后续所有工具pgcli、SQLAlchemy、docker-compose中保持一致。关于镜像版本命令使用postgres:18标签。从仓库的实际配置来看这一版本选择是贯穿始终的pipeline/docker-compose.yaml中数据库服务同样声明为image: postgres:18保证docker run与docker compose两种启动方式使用完全一致的数据库版本避免版本漂移带来的行为差异。备选方案绑定挂载Bind Mount命名卷由 Docker 完全托管数据存放在 Docker 的内部存储中。如果你希望数据目录直接落在宿主机的普通文件系统上例如便于直接查看、备份或用编辑器检查数据文件可以使用绑定挂载方式mkdir ny_taxi_postgres_data docker run -it \ -e POSTGRES_USERroot \ -e POSTGRES_PASSWORDroot \ -e POSTGRES_DBny_taxi \ -v $(pwd)/ny_taxi_postgres_data:/var/lib/postgresql \ -p 5432:5432 \ postgres:18与命名卷版本相比唯一的区别在于-v参数命名卷写法-v ny_taxi_postgres_data:/var/lib/postgresql左侧只有卷名绑定挂载写法-v $(pwd)/ny_taxi_postgres_data:/var/lib/postgresql左侧是宿主机绝对路径。$(pwd)会在 shell 中展开为当前工作目录的绝对路径从而把当前目录下的ny_taxi_postgres_data目录直接挂进容器。此时你在宿主机上就能看到 Postgres 落盘的数据文件。命名卷 vs 绑定挂载如何选择维度命名卷Named Volume绑定挂载Bind Mount语法name:/container/path/host/path:/container/path管理方式Docker 自动管理使用更简单直接映射到宿主机文件系统控制力更强数据位置Docker 内部存储位置对用户透明宿主机上显式可见的目录适用场景推荐日常开发默认使用需要直接访问、备份或审计数据文件时课程仓库中的辅助脚本 pipeline/docker-helper-scripts/docker-postgres.sh 展示了绑定挂载的完整落地形态——它先用mkdir -p ../ny_taxi_postgres_data创建目录再以-v ../ny_taxi_postgres_data:/var/lib/postgresql挂载并额外附加了--networkpg-network与--name pgdatabase参数为后续与容器化摄取脚本taxi_ingest通过同一自定义网络通信做准备。这说明两种挂载方式在真实管道中都有实际用途交互式学习用命名卷最省心写自动化脚本时绑定挂载更容易管理。连接 PostgreSQL安装并使用 pgcli容器运行起来后数据库就在localhost:5432上提供服务了。接下来需要一个客户端来登录数据库。课程选用pgcli——一个带自动补全和语法高亮的 Postgres 命令行客户端。安装 pgcli开发依赖uv add --dev pgcli这里使用了uv本模块在前序课程 02-virtual-environment.md 中引入的现代 Python 包管理器。关键点是--dev标志它把 pgcli 标记为开发依赖而非生产依赖会被写入pyproject.toml的[dependency-groups]段而不是[project].dependencies段。这一点在仓库的 pipeline/pyproject.toml 中有直接体现——pgcli与jupyter一起被放在[dependency-groups] dev组下而 pandas、sqlalchemy、click 等管道运行时依赖才放在正式dependencies中。这样的划分确保了部署镜像时不会把开发工具带进生产环境。连接数据库uv run pgcli -h localhost -p 5432 -u root -d ny_taxi参数含义本文取值uv run在虚拟环境上下文中执行命令确保使用项目环境里的 pgcli-hhost数据库主机地址localhost数据库就在本机容器中-pport数据库端口5432-uuser用户名root-ddatabase数据库名ny_taxi密码不在命令行中提供——执行命令后 pgcli 会提示你输入密码此时输入root即可进入ny_taxi数据库的交互式 shell。与后续环节的连接方式呼应这条连接信息并不是孤立存在的。在课程第 5 节 05-data-ingestion.md 中摄取脚本使用 SQLAlchemy 建立的是同一组凭据from sqlalchemy import create_engine engine create_engine(postgresqlpsycopg://root:rootlocalhost:5432/ny_taxi)而仓库 pipeline/ingest_data.py 中的连接串则由 click 参数动态拼装engine create_engine(fpostgresqlpsycopg://{pg_user}:{pg_pass}{pg_host}:{pg_port}/{pg_db})可以看到root / root / ny_taxi / localhost / 5432这组值贯穿了 pgcli 手动连接、Python 摄取脚本、容器化摄取脚本三条路径它们全部指向同一个 Docker 容器化的 Postgres 实例。理解这一点就理解了整个本地开发环境的连通性设计。基础 SQL 操作验证数据库进入 pgcli 交互界面后用一组最小但完整的 SQL 操作来验证数据库读写链路是否正常-- 列出当前数据库中的所有表 \dt -- 创建一张测试表 CREATE TABLE test (id INTEGER, name VARCHAR(50)); -- 插入一条数据 INSERT INTO test VALUES (1, Hello Docker); -- 查询数据 SELECT * FROM test; -- 退出 pgcli \q逐条说明\dt是 pgcli / psql 的元命令backslash command用于列出当前 schema 下的所有表。新库中还没有表输出为空属正常现象CREATE TABLE test (id INTEGER, name VARCHAR(50))创建一张包含整型id和 50 字符上限name字段的测试表INSERT INTO test VALUES (1, Hello Docker)验证写入能力SELECT * FROM test验证读取能力应返回(1, Hello Docker)一行\q退出客户端容器因--rm参数会在退出后被自动清理但卷中的数据完好保留。这套验证流程的价值在于它用最小代价确认了容器启动 → 端口映射 → 凭据初始化 → 数据持久化 → 客户端连通整条链路全部正常。之后无论用 pgAdmin 图形化管理见课程 07-pgadmin.md还是用摄取脚本灌入纽约出租车数据都是在验证过的基础设施上继续。源码视角同一套配置的三处落地把目光从单个命令移开你会发现 Postgres 容器配置在整个仓库中被复用了三次分别对应三种不同的运行场景1.docker run交互式启动本课程核心——见 04-postgres-docker.md 的命令示例适合教学演示与临时验证。2. 辅助脚本启动——pipeline/docker-helper-scripts/docker-postgres.sh 把同样的参数固化成了可重复执行的 bash 脚本并补上了--networkpg-network --name pgdatabase两个参数。从脚本结构看--network是为了让 Postgres 容器加入预创建的自定义网络--name则让其他容器可以通过pgdatabase这个主机名找到它——这正是 08-dockerizing-ingestion.md 中容器化摄取脚本以--pg-hostpgdatabase而非localhost连接数据库的原因容器之间无法通过 localhost 互相访问必须经由 Docker 网络和容器名。3. Docker Compose 声明式启动——pipeline/docker-compose.yaml 用 YAML 声明了pgdatabase服务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注意这份配置与docker run命令的严格对应关系image: postgres:18↔ 命令末尾的postgres:18environment:三个键 ↔ 三条-e参数volumes:↔-v ny_taxi_postgres_data:/var/lib/postgresql同样采用命名卷ports: 5432:5432↔-p 5432:5432。Compose 还隐式完成了docker run中需要手动处理的网络工作所有 service 自动加入同一个默认网络并可按服务名互相解析。对 Compose 的完整讨论docker-compose up、down、日志查看、跨容器运行摄取脚本等见课程第 9 节 09-docker-compose.md。从这三次落地可以看到一条清晰的演进路径交互式命令用于学习理解 → 脚本固化用于重复执行 → Compose 声明用于多容器编排。无论哪种方式POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB / 数据卷 / 端口这五要素始终保持一致这正是数据管道各组件之间能够稳定协作的前提。常见问题与排障要点端口被占用如果5432已被宿主机上其他 Postgres 占用docker run会因端口冲突而失败。可换用宿主机侧的其他端口如-p 5433:5432后续所有连接命令的-p参数需同步修改。--rm与数据持久化的关系--rm删除的是容器本身不会触碰卷。只要卷ny_taxi_postgres_data还在重新启动容器后数据依然完整。这是理解容器无状态、数据有状态这一 Docker 核心心智模型的最佳起点。数据目录挂载位置本课程将数据挂到/var/lib/postgresql。需要留意官方镜像在较新版本中对数据目录的组织可能有调整例如PGDATA指向/var/lib/postgresql/18/docker的情况若启动日志提示数据目录相关错误可检查镜像版本对应的PGDATA默认值。客户端连不上先确认容器日志中是否出现database system is ready to accept connections再确认docker ps中端口映射是否为0.0.0.0:5432-5432/tcp两者都正常后用pgcli重试即可。小结通过本指南你已经掌握了在 Docker 中运行 PostgreSQL 的完整链路理解docker run各参数环境变量、命名卷、端口映射的作用掌握命名卷与绑定挂载两种持久化方式的差异与取舍能够用 pgcli 客户端连接数据库并执行基础 SQL 验证读写。更进一步你看到了同一套数据库配置如何在辅助脚本、SQLAlchemy 摄取脚本与 Docker Compose 中复用以及容器间如何通过网络与容器名通信。这套容器化数据库 持久化卷 外部客户端连接的模式正是后续把纽约出租车数据灌入ny_taxi库05-data-ingestion.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),仅供参考