3. 开发环境搭建:Python虚拟环境配置、依赖管理、Docker化与Git工作流
说实话,很多新手项目最后翻车,不是死在业务逻辑上,而是死在环境上。
我见过太多次了——代码在本地跑得好好的,部署到服务器就报错。一查,Python版本不对,依赖包冲突,或者某个底层库没装。这种问题特别磨人。
所以这一章,咱们就把开发环境彻底理清楚。从Python虚拟环境,到依赖管理,再到Docker容器化,最后配上Git工作流。一套组合拳打下来,后面30章你都不会再为环境发愁。
本章核心目标:搭建一个可复现、可隔离、可协作的OLAP调度系统开发环境。
3.1 Python虚拟环境:为什么必须用?
Python的全局环境,说白了就是一个大杂烩。你装一个包,它可能依赖A库1.0版本;另一个项目需要A库2.0版本。两个版本一冲突,你就得来回卸载重装。
虚拟环境就是解决这个问题的。每个项目有自己的Python解释器和包目录,互不干扰。
3.1.1 venv vs conda vs virtualenv
我个人的选择很简单:
- venv:Python 3.3+内置,轻量,够用。我90%的项目都用它。
- conda:适合数据科学场景,能管理非Python依赖(比如C库)。但有点重。
- virtualenv:venv的前身,现在基本被venv取代了。
咱们这个OLAP调度系统,用venv就够了。别整太复杂。
我的习惯:每个项目根目录下建一个.venv文件夹,然后加到.gitignore里。这样团队成员拉代码后,各自执行python -m venv .venv就能快速重建环境。
3.1.2 创建与激活虚拟环境
操作很简单,三步走:
# 1. 创建虚拟环境(在项目根目录执行)
python -m venv .venv
# 2. 激活环境
# Linux/Mac:
source .venv/bin/activate
# Windows:
.venv\Scripts\activate
# 3. 验证
which python # 应该指向 .venv 目录下的解释器
python --version # 确认版本
激活后,终端前面会出现(.venv)前缀。嗯,看到这个就说明环境生效了。
我曾经踩过的坑:在Windows上用PowerShell激活虚拟环境,结果脚本执行策略被禁用了。解决方案是用Set-ExecutionPolicy Unrestricted -Scope Process临时放开,或者直接用cmd。
3.2 依赖管理:Poetry vs Pipenv
有了虚拟环境,还得管依赖。传统的pip freeze > requirements.txt有个大问题——它只记录顶层依赖,不记录子依赖的精确版本。换台机器一装,可能就装到不同版本了。
Poetry和Pipenv就是来解决这个痛点的。它们都引入了锁文件的概念。
3.2.1 我为什么选Poetry
两个工具我都用过。Pipenv早期有性能问题,锁文件生成特别慢。Poetry的依赖解析更快,而且它的pyproject.toml格式更规范,符合PEP 621标准。
咱们这个课程就用Poetry。安装方式:
# 官方推荐安装方式
curl -sSL https://install.python-poetry.org | python3 -
# 验证安装
poetry --version
3.2.2 初始化项目与添加依赖
在虚拟环境激活状态下,执行:
# 初始化pyproject.toml
poetry init
# 添加核心依赖
poetry add apache-airflow==2.8.0
poetry add pandas==2.1.0
poetry add sqlalchemy==2.0.23
# 添加开发依赖
poetry add --group dev pytest black flake8
# 安装所有依赖
poetry install
执行完后,你会看到两个关键文件:
pyproject.toml:声明式依赖清单,类似package.jsonpoetry.lock:锁定所有依赖的精确版本,必须提交到Git
重要原则:poetry.lock一定要提交到版本控制。这样团队所有人、CI/CD服务器、生产环境都能装到一模一样的依赖树。
3.2.3 依赖管理对比表
| 特性 | pip + requirements.txt | Pipenv | Poetry |
|---|---|---|---|
| 锁文件 | 无(需手动维护) | Pipfile.lock | poetry.lock |
| 依赖解析速度 | 快(但不精确) | 慢 | 快 |
| 开发/生产分离 | 手动拆分文件 | 支持 | 支持(--group dev) |
| 构建与发布 | 需额外工具 | 有限 | 内置 |
| 社区活跃度 | 最高 | 一般 | 高 |
3.3 Docker化开发环境
虚拟环境解决了Python包隔离的问题,但解决不了操作系统层面的差异。比如你的调度系统依赖某个C库,或者需要特定版本的PostgreSQL客户端。这时候Docker就派上用场了。
3.3.1 Dockerfile设计思路
咱们的OLAP调度系统,Docker镜像要包含:
- Python 3.11运行环境
- Poetry安装的依赖
- Airflow调度器核心组件
- 必要的系统工具(curl、vim等,方便调试)
这是我的Dockerfile模板:
FROM python:3.11-slim
# 安装系统依赖
RUN apt-get update && apt-get install -y \
curl \
vim \
&& rm -rf /var/lib/apt/lists/*
# 安装Poetry
RUN pip install poetry
# 设置工作目录
WORKDIR /app
# 先复制依赖文件,利用Docker缓存
COPY pyproject.toml poetry.lock ./
RUN poetry config virtualenvs.create false \
&& poetry install --no-interaction --no-ansi
# 复制项目代码
COPY . .
# 暴露端口(Airflow默认端口)
EXPOSE 8080
# 启动命令
CMD ["airflow", "standalone"]
优化技巧:把pyproject.toml和poetry.lock先复制进去安装依赖,再复制源码。这样只要依赖没变,Docker就会复用缓存层,构建速度能快好几倍。
3.3.2 docker-compose编排多服务
实际项目中,调度系统不会只跑一个容器。至少要有:
- scheduler:Airflow调度器
- webserver:Airflow Web界面
- worker:执行任务的工作节点
- postgres:元数据库
- redis:消息队列(可选)
用docker-compose统一管理:
version: '3.8'
services:
postgres:
image: postgres:15
environment:
POSTGRES_USER: airflow
POSTGRES_PASSWORD: airflow
POSTGRES_DB: airflow
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
scheduler:
build: .
command: airflow scheduler
depends_on:
- postgres
- redis
volumes:
- ./dags:/app/dags
webserver:
build: .
command: airflow webserver
ports:
- "8080:8080"
depends_on:
- scheduler
volumes:
postgres_data:
启动方式:docker-compose up -d。一行命令,整个环境就起来了。
我曾经犯过的错:在Docker里用root用户运行Airflow,结果生成的日志文件权限全是root,宿主机上普通用户删不掉。后来改成用USER airflow创建专用用户,配合chown解决。
3.4 Git工作流:团队协作的基石
环境搭好了,代码怎么写?Git工作流得定好规矩。不然多人协作时,合并冲突能让你崩溃。
3.4.1 分支策略
我推荐Git Flow的简化版,适合咱们这个OLAP调度系统项目:
- main:生产分支,只合入经过测试的稳定代码
- develop:开发主分支,日常开发往这里合
- feature/xxx:功能分支,从develop拉出,开发完合并回develop
- hotfix/xxx:紧急修复分支,从main拉出,修复后合并回main和develop
举个例子,你要开发一个Hive数据源接入功能:
git checkout develop
git pull origin develop
git checkout -b feature/hive-connector
# 开发、提交...
git add .
git commit -m "feat: add Hive connector"
# 开发完成,合并回develop
git checkout develop
git merge feature/hive-connector
git push origin develop
3.4.2 提交信息规范
我见过最乱的提交信息就是"fix bug"、"update"、"aaa"。根本不知道改了啥。
咱们用Conventional Commits规范:
| 类型 | 说明 | 示例 |
|---|---|---|
| feat | 新功能 | feat: add Hive connector |
| fix | 修复bug | fix: resolve DAG parsing timeout |
| docs | 文档变更 | docs: update README with setup guide |
| refactor | 重构 | refactor: extract scheduler logic |
| test | 测试相关 | test: add unit tests for executor |
| chore | 构建/工具 | chore: update Poetry dependencies |
3.4.3 .gitignore配置
有些东西不能提交到Git仓库:
# Python
__pycache__/
*.py[cod]
*.egg-info/
.venv/
dist/
# IDE
.vscode/
.idea/
# 环境文件
.env
*.local
# Docker
.docker/
# 日志
*.log
logs/
我的习惯:在项目初始化时就创建.gitignore,然后提交第一个commit。后面再补容易漏掉,而且已经跟踪的文件不会自动忽略。
3.5 本章知识体系总览
下面这张图把本章的核心逻辑串起来了。你想想看,从本地开发到团队协作,整个链路是通的:
3.6 本章小结
到这,开发环境就彻底搭好了。咱们捋一下:
- Python虚拟环境:用venv隔离项目依赖,避免全局污染
- Poetry管理依赖:pyproject.toml声明依赖,poetry.lock锁定版本
- Docker容器化:Dockerfile定义运行环境,docker-compose编排多服务
- Git工作流:分支策略规范协作,提交信息清晰可追溯
这套组合拳打下来,后面写代码的时候,你基本不用再操心环境问题。把精力都放在业务逻辑上,这才是正经事。