Python Docker 部署
以单阶段骨架解释 Python 容器的依赖、src 导入路径、非 root 入口与停机边界。
#howto
#growing
#dev
#python
#python
[!info] related notes
Python Docker 部署
目标
明确镜像中的 Python 导入路径、依赖与启动命令。示例展示结构;发布可复现性还需锁定依赖、构建输入和基础镜像 digest。
这个场景为什么出现
“在我机器能跑”不够。容器固化运行时,是部署与扩缩的基础单元。
[!abstract] 一句话理解 镜像 = 基础解释器 + 安装依赖 + 应用代码 + 入口命令;构建可重复,配置经环境注入。
最小示例(Dockerfile 形态)
场景:API 服务镜像骨架
假设已有 requirements.txt 和 src/myapp/main.py,后者负责启动监听 0.0.x.x:8000 的服务。本例直接运行源码,不安装项目 wheel;这是单阶段,不是多阶段构建。
# 示例骨架(教学)
FROM python:3.12-slim AS base
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 PYTHONPATH=/app/src
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src ./src
USER 10001:10001
CMD ["python", "-m", "myapp"]
建议运行(需 Docker 环境):
docker build -t myapp:dev .
docker run --rm -e DATABASE_URL=... -p 8000:8000 myapp:dev
结合场景再看三个关注点
- 先复制依赖清单可复用安装层;requirements.txt 本身不保证锁定了传递依赖和哈希,python:3.12-slim 标签也会更新。
- USER 使用非 root UID/GID;源码和依赖需可读,写入目录或卷需单独安排权限,本骨架没有为应用提供可写 /app。
- exec 形式 CMD 让 Python 直接接收容器停止信号,但不会自动实现优雅关闭;应用/server 仍要处理信号、排空与清理。
核心概念与准确模型
- 基础镜像选择
- 多阶段:构建与运行分离
- 健康检查
- 只读层与卷
边界情况与反直觉行为
- 胖镜像 攻击面大
- 本地路径依赖 进不了镜像
- GIL/worker 数 与 CPU 限额
常见误区
[!warning] 常见误区:在容器里 pip install 最新无钉版本 错误理解:永远最新最好。
正确模型:锁定直接与传递依赖、哈希、解释器/平台和构建输入;只固定顶层版本或基础镜像标签仍不足以保证重现。
工程实践
.dockerignore- CI 构建并扫描
- 配置全走环境变量
本节总结
容器是交付包装。可复现与信号/配置正确,比“能 build 通”更重要。
自测题
- 为何先复制 requirements?
- PYTHONUNBUFFERED 作用?
参考答案
- 利用层缓存,代码变更不重装依赖。
- 使 Python 标准输出/错误输出无缓冲;不会关闭上游代理、日志采集器或外部库自己的缓冲。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Docker docs | 文档 | 容器 |
| Python slim images | 镜像 | 官方基础镜像 |