WSL2 + Docker + Python:打造跨平台一致开发环境
🐍 WSL2 + Docker + Python:打造跨平台一致开发环境
一、前言
在软件开发中,“它在我的机器上能跑!” 是一个广为流传的笑话,但它揭示了一个真实而痛苦的现实:开发环境与生产环境之间的不一致,是导致线上故障最常见的根源之一。
即使在团队内部,不同成员的开发环境也可能存在细微差异——操作系统版本不同、系统库版本不同、Python 版本不同、环境变量配置不同——这些差异在日常开发中可能不会暴露问题,但在关键时刻(紧急修复、上线部署)往往引发难以排查的诡异 bug。
解决这一问题的终极方案,是 WSL2 + Docker 的组合:
- WSL2(Windows Subsystem for Linux 2) 让 Windows 用户拥有完整的 Linux 内核,消除了操作系统层面的差异
- Docker 通过容器化技术将应用及其依赖打包为不可变的镜像,确保开发、测试、生产环境的高度一致
本文将详细介绍如何在 Windows 上搭建 WSL2 + Docker 的 Python 开发环境,并探讨如何将这套工作流融入日常开发。
二、WSL2 原理与安装
2.1 WSL1 vs. WSL2:架构差异
WSL 经历了两个版本的演进,它们的架构有本质区别:
| 特性 | WSL1 | WSL2 |
|---|---|---|
| 架构 | 翻译层(将 Linux 系统调用转换为 Windows 系统调用) | 完整的 Linux 虚拟机(运行在 Hyper-V 轻量级 VM 中) |
| Linux 内核 | ❌ 无实际 Linux 内核 | ✅ 包含完整 Linux 内核 |
| 系统调用兼容性 | ⚠️ 部分不兼容(约 70% 系统调用) | ✅ 完全兼容(100%) |
| I/O 性能 | 🚀 快(跨文件系统操作) | ⚡ Windows → Linux 文件系统:较快;反之较慢 |
| 内存使用 | 💾 低(共享 Windows 内存) | 💾 较高(有独立 VM 内存分配) |
| Docker 支持 | ❌ 不支持 Docker 原生运行 | ✅ 支持 Docker 原生运行 |
为何选择 WSL2? 对 Python 开发者而言,WSL2 带来的完整 Linux 内核意味着:
- Docker 可以在 WSL2 中原生运行(无需 Docker Desktop 的 Hyper-V VM)
- Linux 特有的系统调用(如
inotify、epoll、fork等)全部可用 - 科学计算库(numpy、scipy 等)的底层优化全面生效
2.2 WSL2 安装步骤
前提条件
- Windows 10 版本 2004+(Build 19041+)或 Windows 11
- 启用了 BIOS 中的虚拟化技术(VT-x/AMD-V)
安装命令
# 1. 以管理员身份打开 PowerShell,启用 WSL 功能
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
# 2. 启用虚拟机平台
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
# 3. 设置 WSL2 为默认版本
wsl --set-default-version 2
# 4. 安装 Linux 发行版(推荐 Ubuntu 22.04 LTS 或 24.04 LTS)
# 方法一:从 Microsoft Store 搜索 "Ubuntu" 安装
# 方法二:使用命令行
wsl --install -d Ubuntu-24.04
# 5. 查看已安装的 WSL 发行版及其版本
wsl --list --verbose
验证安装
# 进入 WSL2 环境
wsl
# 在 WSL2 中验证
uname -a
# 输出示例:Linux DESKTOP-XXXX 5.15.146.1-microsoft-standard-WSL2 #1 SMP ...
cat /etc/os-release
# 输出示例:Ubuntu 24.04 LTS
2.3 WSL2 优化配置
WSL2 的默认配置在内存和资源使用上可能不是最优的。在 Windows 用户目录下创建 .wslconfig 文件进行调优:
# %USERPROFILE%\.wslconfig
[wsl2]
# 限制最大内存使用(防止 WSL2 占用过多内存)
memory=8GB
# 限制最大 CPU 核心数
processors=4
# 交换空间大小
swap=2GB
# 开启 localhost 转发(WSL2 中的服务可从 Windows 访问)
localhostForwarding=true
# 启用 WSL2 的 systemd 支持(Ubuntu 22.04+ 需要)
systemd=true
⚠️ 注意: 修改
.wslconfig后需要重启 WSL2 才能生效:wsl --shutdown wsl
三、在 WSL2 中配置 Python 开发环境
3.1 基础环境安装
进入 WSL2 后,配置与在原生 Linux 上完全一致:
# 更新包管理器
sudo apt update && sudo apt upgrade -y
# 安装基础开发工具
sudo apt install -y \
build-essential \
curl \
wget \
git \
vim \
htop \
software-properties-common \
libssl-dev \
libffi-dev \
zlib1g-dev
# 安装 Python(Ubuntu 24.04 默认包含 Python 3.12)
sudo apt install -y python3 python3-pip python3-venv python3-dev
# 验证
python3 --version
pip3 --version
# 安装常用 Python 工具
pip3 install --user --upgrade pip
pip3 install --user poetry ruff mypy pre-commit
3.2 安装 pyenv 管理多版本 Python
# 安装 pyenv 依赖
sudo apt install -y \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
libncursesw5-dev \
xz-utils \
tk-dev \
libxml2-dev \
libxmlsec1-dev
# 安装 pyenv
curl https://pyenv.run | bash
# 将 pyenv 添加到 shell 配置文件(~/.bashrc 或 ~/.zshrc)
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
# 重新加载配置
source ~/.bashrc
# 安装多版本 Python
pyenv install 3.10.15
pyenv install 3.11.9
pyenv install 3.12.5
# 设置全局版本
pyenv global 3.12.5
3.3 配置 Poetry
# 安装 Poetry
curl -sSL https://install.python-poetry.org | python3 -
# 配置 Poetry 在项目目录内创建虚拟环境(而非统一管理)
poetry config virtualenvs.in-project true
# 配置 Poetry 使用的 Python 版本
poetry config virtualenvs.prefer-active-python true
# 验证
poetry --version
3.4 WSL2 中的项目结构建议
WSL2 的文件系统性能访问 Windows 文件(/mnt/c/...)时存在显著的性能损失。建议将项目代码放在 WSL2 内部文件系统,然后在 Windows 中使用 \\wsl$ 网络路径访问:
# ❌ 不推荐:在 Windows 文件系统中开发(跨文件系统操作很慢)
/mnt/c/Users/Administrator/Desktop/my-project/
# ✅ 推荐:在 WSL2 文件系统中开发
/home/username/projects/my-project/
# ✅ 推荐:将项目链接到 Windows 资源管理器(方便访问)
# 在 WSL2 中创建符号链接
ln -s /home/username/projects /mnt/c/Users/Administrator/projects
性能测试对比:
# Windows 文件系统中的项目 time python -c "import numpy; numpy.zeros((1000, 1000))" # real 0m0.350s ← I/O 路径经过 9p 协议,有额外开销 # WSL2 文件系统中的项目 time python -c "import numpy; numpy.zeros((1000, 1000))" # real 0m0.125s ← 原生 Linux 文件系统性能
四、Docker 基础与安装
4.1 Docker 的核心概念
在进入安装步骤之前,有必要建立对 Docker 核心概念的清晰理解:
┌──────────────────────────────────────────────────┐
│ Docker 架构 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Client │ │ Client │ │ Client │ │
│ │ (CLI) │ │ (IDE) │ │ (API) │ │
│ └─────┬────┘ └─────┬────┘ └─────┬────┘ │
│ │ │ │ │
│ └──────────────┼──────────────┘ │
│ │ │
│ ┌─────▼──────┐ │
│ │ Docker │ │
│ │ Daemon │ │
│ │ (dockerd) │ │
│ └─────┬──────┘ │
│ │ │
│ ┌────────────┼────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Image │ │ Image │ │ Image │ │
│ │(只读模板) │ │(只读模板) │ │(只读模板) │ │
│ └─────┬────┘ └─────┬────┘ └─────┬────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Container │ │Container │ │Container │ │
│ │(运行实例) │ │(运行实例) │ │(运行实例) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└──────────────────────────────────────────────────┘
核心概念:
| 概念 | 类比 | 描述 |
|---|---|---|
| Image(镜像) | 类的定义 | 只读的模板,包含运行应用所需的代码、运行时、库、环境变量和配置文件 |
| Container(容器) | 类的实例 | 镜像的运行实例,可被创建、启动、停止、删除 |
| Dockerfile | 类的源码 | 用于构建镜像的自动化脚本 |
| Registry(仓库) | PyPI / npm | 存储和分发镜像的中央仓库(如 Docker Hub) |
| Volume(卷) | 外接硬盘 | 持久化容器数据的存储机制 |
4.2 在 WSL2 中安装 Docker
由于 WSL2 包含完整的 Linux 内核,可以在其中直接安装 Docker Engine(而非 Docker Desktop),这是资源占用最小的方式:
# 更新包索引
sudo apt update
# 安装依赖
sudo apt install -y \
ca-certificates \
curl \
gnupg \
lsb-release
# 添加 Docker 官方 GPG 密钥
sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 添加 Docker 软件源
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 将当前用户添加到 docker 组(避免每次使用 sudo)
sudo usermod -aG docker $USER
# 使组变更生效
newgrp docker
# 验证安装
docker --version
docker compose version
4.3 启动 Docker 守护进程
WSL2 默认不自动启动 Docker 守护进程(dockerd),需要手动启动:
# 手动启动 Docker(每次进入 WSL2 需要执行一次)
sudo service docker start
# 验证 Docker 是否正常运行
docker info
# 运行 hello-world 验证
docker run hello-world
自动化启动配置:
如果 WSL2 启用了 systemd(在 .wslconfig 中设置 systemd=true),Docker 会自动随系统启动:
# 启用 Docker 开机自启
sudo systemctl enable docker
# 手动启动
sudo systemctl start docker
五、Python 项目的 Docker 化实践
5.1 编写 Dockerfile
以一个典型的 FastAPI 项目为例:
# ===== 第一阶段:依赖安装 =====
FROM python:3.12-slim AS builder
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
# 安装系统依赖(仅在需要编译 C 扩展时)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY pyproject.toml poetry.lock ./
# 安装 Poetry 并安装依赖
RUN pip install poetry && \
poetry config virtualenvs.create false && \
poetry install --no-dev --no-interaction --no-ansi
# ===== 第二阶段:运行镜像 =====
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# 从 builder 阶段复制已安装的包
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
# 复制应用代码
COPY . .
# 创建非 root 用户运行
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Dockerfile 最佳实践说明:
- 多阶段构建:将依赖安装与运行分离,大幅减小最终镜像体积
- 依赖层利用 Docker 缓存:
COPY pyproject.toml poetry.lock ./放在代码之前,利用 Docker 的层缓存机制——只有当依赖文件变化时才重新安装 - 最小化基础镜像:
python:3.12-slim比python:3.12小约 800MB,只包含运行 Python 所需的最小系统库 - 非 root 运行:
USER appuser提升容器安全性
5.2 使用 docker-compose 编排多服务
在实际项目中,一个应用往往需要多个服务配合运行(应用 + 数据库 + 缓存 + 消息队列)。docker-compose 可以一键启动所有服务:
# docker-compose.yml
version: "3.9"
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
container_name: myproject-app
ports:
- "8000:8000"
volumes:
- .:/app # 挂载代码目录,实现热重载
env_file:
- .env
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
db:
image: postgres:16-alpine
container_name: myproject-db
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: myproject
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: myproject-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
volumes:
postgres_data:
redis_data:
5.3 开发工作流
# 1. 克隆项目并进入目录
git clone git@github.com:user/myproject.git
cd myproject
# 2. 启动所有服务
docker compose up -d
# 3. 查看服务状态
docker compose ps
# 4. 查看日志
docker compose logs -f app
# 5. 进入运行中的容器执行命令
docker compose exec app bash
# 6. 运行测试
docker compose exec app pytest
# 7. 停止所有服务
docker compose down
# 8. 停止并删除数据卷
docker compose down -v
5.4 开发 vs 生产:使用不同 Dockerfile
为开发和生产环境分别配置 Dockerfile,可以兼顾开发体验和生产效率:
# Dockerfile.dev(开发环境)
FROM python:3.12-slim
WORKDIR /app
# 安装开发依赖
RUN pip install poetry
COPY pyproject.toml poetry.lock ./
RUN poetry install --no-interaction # 包含 dev 依赖
# 代码通过 volume 挂载,无需 COPY
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
# docker-compose.override.yml(开发环境覆盖配置)
# 使用方式:docker compose -f docker-compose.yml -f docker-compose.override.yml up
services:
app:
build:
dockerfile: Dockerfile.dev
volumes:
- .:/app # 挂载代码实现热重载
- /app/__pycache__ # 排除缓存目录
environment:
- DEBUG=1
- LOG_LEVEL=debug
六、进阶:Dev Containers(开发容器)
VSCode 的 Dev Containers 扩展将 Docker 容器的应用推向了新的高度——整个开发环境(包括编辑器配置、扩展、终端、调试器)都可以运行在容器中。
6.1 配置 Dev Container
在项目根目录创建 .devcontainer/devcontainer.json:
{
"name": "Python 开发环境",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"charliermarsh.ruff",
"ms-python.debugpy",
"tamasfe.even-better-toml",
"GitHub.copilot"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.analysis.typeCheckingMode": "basic",
"[python]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "charliermarsh.ruff"
}
}
}
},
"postCreateCommand": "pip install poetry && poetry install",
"forwardPorts": [8000],
"remoteUser": "vscode",
"mounts": [
"source=${env:HOME}${env:USERPROFILE}/.gitconfig,target=/home/vscode/.gitconfig,type=bind"
]
}
6.2 使用 Dev Container 的优势
| 优势 | 说明 |
|---|---|
| 环境即代码 | 开发环境配置纳入版本控制,新成员一键复现 |
| 隔离性 | 每个项目有独立的开发环境,互不干扰 |
| 一致性 | 开发环境和 CI/CD / 生产环境使用相同的 Docker 镜像 |
| 零配置上手指南 | 新开发者只需安装 Docker + VSCode + Dev Containers 扩展即可开始编码 |
# 在 VSCode 中打开项目
code /home/username/projects/myproject
# 按 F1 → "Dev Containers: Reopen in Container"
# 等待镜像构建完成,即可在容器化的开发环境中编码
七、生产环境:从开发到部署
7.1 CI/CD 流水线中的 Docker
# .github/workflows/deploy.yml
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: |
docker build \
--target runtime \
-t registry.example.com/myapp:${{ github.sha }} \
-t registry.example.com/myapp:latest \
.
- name: Push to registry
run: |
docker push registry.example.com/myapp:${{ github.sha }}
docker push registry.example.com/myapp:latest
7.2 生产部署建议
# docker-compose.prod.yml(生产配置)
version: "3.9"
services:
app:
build:
context: .
dockerfile: Dockerfile
image: registry.example.com/myapp:latest
restart: unless-stopped
ports:
- "8000:8000"
environment:
- PYTHONOPTIMIZE=1 # 启用 Python 优化模式
- PYTHONHASHSEED=random
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
cpus: "2.0"
memory: "2GB"
reservations:
cpus: "0.5"
memory: "512MB"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
八、常见问题与排查
8.1 WSL2 相关
# 问题:WSL2 占用内存过高
# 解决:配置 .wslconfig 限制内存(见 2.3 节),或手动清理
wsl --shutdown
# 问题:跨文件系统访问(/mnt/c/)性能差
# 解决:将项目移至 WSL2 内部文件系统 /home/username/projects/
# 问题:WSL2 网络代理配置
# 在 ~/.bashrc 中添加:
export host_ip=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')
export http_proxy="http://$host_ip:7890"
export https_proxy="http://$host_ip:7890"
8.2 Docker 相关
# 问题:docker: permission denied
# 解决:将用户添加到 docker 组
sudo usermod -aG docker $USER && newgrp docker
# 问题:端口已被占用
# 解决:修改映射端口
docker run -p 8001:8000 myapp
# 问题:磁盘空间被 Docker 镜像占满
# 解决:清理未使用的 Docker 资源
docker system prune -a --volumes
# 查看各资源占用
docker system df
# 问题:查看容器日志
docker logs -f container_name
# 问题:进入容器调试
docker exec -it container_name bash
九、总结
WSL2 + Docker 的组合为 Python 开发者提供了一种"环境即代码"的现代工作流:
| 层级 | 技术 | 解决的问题 |
|---|---|---|
| 操作系统 | WSL2 | Windows 上获得完整 Linux 内核,消除 OS 差异 |
| 语言级 | pyenv / Poetry | 多版本 Python 管理、依赖隔离 |
| 应用级 | Docker | 应用及其依赖打包为不可变镜像,确保环境一致性 |
| 开发级 | Dev Containers | 开发环境容器化,团队一键复现 |
这套工作流的核心思想是:从开发到部署,软件运行的环境始终是同一个 Docker 镜像。不再有"开发环境能跑、线上跑不了"的问题,不再有"明明按文档配置了,就是启动不起来"的挫败感。
当你配置好了 WSL2 上的 Docker 开发环境,编写好 Dockerfile 和 docker-compose 配置,你就拥有了一个可以随身携带、在任何机器上完全一致的 Python 开发环境——这才是现代软件工程的正确打开方式。
📌 系列文章目录:
- ✅ 从零搭建Python开发环境:Python安装 + VSCode + PyCharm配置
- ✅ Conda vs. venv vs. Poetry:Python虚拟环境方案对比与最佳实践
- ✅ 告别编码乱码:Python开发中编码问题的终极解决方案
- ✅ WSL2 + Docker + Python:打造跨平台一致开发环境(本文)
- 🔜 终端美化与效率工具:Oh My Zsh + iTerm2 + IPython 配置指南
如果本文对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)