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.json
  • poetry.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 本章知识体系总览

下面这张图把本章的核心逻辑串起来了。你想想看,从本地开发到团队协作,整个链路是通的:

开发环境搭建知识体系 Python虚拟环境 venv / conda / virtualenv 依赖管理 Poetry / Pipenv / pyproject.toml Docker容器化 Dockerfile / docker-compose 可复现的开发环境 poetry.lock + Docker镜像 + docker-compose.yml 任何机器上都能一键拉起,依赖完全一致 Git工作流 分支策略 + 提交规范 + .gitignore 团队高效协作 代码一致、环境一致、流程一致 核心原则:环境即代码(Environment as Code),所有配置都版本化、可追溯

3.6 本章小结

到这,开发环境就彻底搭好了。咱们捋一下:

  • Python虚拟环境:用venv隔离项目依赖,避免全局污染
  • Poetry管理依赖:pyproject.toml声明依赖,poetry.lock锁定版本
  • Docker容器化:Dockerfile定义运行环境,docker-compose编排多服务
  • Git工作流:分支策略规范协作,提交信息清晰可追溯

这套组合拳打下来,后面写代码的时候,你基本不用再操心环境问题。把精力都放在业务逻辑上,这才是正经事。