mcpField
P
python-containers

python-containers

github.com/laurigates云与 DevOps5969 次安装1 天前更新
代码仓库

关于 python-containers

面向编写和优化 Python 容器镜像的开发者技能,涵盖 Python Dockerfile 与依赖管理。重点包括 slim 基础镜像、多阶段构建、虚拟环境、包管理器,以及规避 Alpine 和解释器版本不匹配带来的问题。

主要功能

  1. 01Python slim 基础镜像指引
  2. 02使用包管理器进行多阶段构建
  3. 03优化虚拟环境
  4. 04处理编译扩展与 libc 问题
  5. 05检查镜像运行和依赖

适用场景

  1. 01缩小 Python Docker 镜像
  2. 02使用 uv、poetry 或 pip 构建镜像
  3. 03排查 Alpine 或 musl 相关问题
  4. 04验证解释器与虚拟环境兼容性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/laurigates/claude-plugins --skill python-containers

安装后在 Claude Code 中输入/python-containers确认已加载。

附带文件REFERENCE.md

详细介绍

Python 容器优化

构建优化的 Python 容器镜像所需的专业知识,包括使用精简基础镜像、虚拟环境、现代包管理器(uv、poetry)和多阶段构建模式。

何时使用此技能

在以下情况下使用此技能……在以下情况下改用 container-development……
构建 Python 专用 Dockerfile通用多阶段构建模式
优化 Python 镜像大小与语言无关的容器安全
在容器中处理 pip/poetry/uvDocker Compose 配置
处理 musl/glibc 问题非 Python 容器优化

核心专长

Python 容器面临的挑战:

  • 基础镜像体积大,包含不必要的包(约 1GB)
  • 关键:Alpine 会导致 Python 问题(musl 与 glibc)
  • 依赖管理复杂(pip、poetry、pipenv、uv)
  • 编译型 C 扩展需要构建工具
  • 在容器中处理虚拟环境

核心能力:

  • 基于 slim 的镜像(Python 容器不要使用 Alpine)
  • 使用现代工具进行多阶段构建(推荐 uv)
  • 虚拟环境优化
  • 编译型扩展处理
  • 非 root 用户配置

为什么 Python 容器不应使用 Alpine

Python 容器应使用 slim,而不是 Alpine。Alpine 使用 musl libc,会导致以下问题:

  • 许多 wheel 无法使用(numpy、pandas、scipy)
  • 被迫从源代码编译(构建速度慢)
  • 由于构建工具,最终镜像更大
  • 原生扩展出现运行时错误

优化的 Dockerfile 模式(uv)

推荐的模式可生成约 80-120MB 的镜像:

# Both stages MUST share this interpreter version — see below.
ARG PYTHON_VERSION=3.11

# Build stage
FROM python:${PYTHON_VERSION}-slim AS builder
WORKDIR /app

RUN pip install --no-cache-dir uv

# Copy dependency files
COPY pyproject.toml uv.lock ./

# Install dependencies with uv (much faster than pip)
RUN uv sync --frozen --no-dev

COPY . .

# Runtime stage
FROM python:${PYTHON_VERSION}-slim
WORKDIR /app

# Install only runtime dependencies (if needed)
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    libpq5 \
    && rm -rf /var/lib/apt/lists/*

# Create non-root user
RUN addgroup --gid 1001 appgroup && \
    adduser --uid 1001 --gid 1001 --disabled-password appuser

# Copy only what's needed
COPY --from=builder --chown=appuser:appgroup /app/.venv /app/.venv
COPY --chown=appuser:appgroup app/ /app/app/
COPY --chown=appuser:appgroup pyproject.toml /app/

ENV PATH="/app/.venv/bin:$PATH" \
    PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1

USER appuser
EXPOSE 8000

HEALTHCHECK --interval=30s CMD python -c "import requests; requests.get('http://localhost:8000/health')" || exit 1

CMD ["python", "-m", "app"]

解释器耦合——两个阶段使用同一版本

上述模式会将虚拟环境复制到另一个构建阶段:

COPY --from=builder /app/.venv /app/.venv

该虚拟环境无法跨 Python 次版本移植。它的包位于 /app/.venv/lib/python<X.Y>/site-packages,其中的任何编译型扩展 都带有该版本的 ABI 标签。如果在不同的次版本上运行,解释器会查找一个 不存在的目录,因此该虚拟环境会从 sys.path 中彻底移除——不是缺少一个包,而是所有包都找不到:

runtime python : 3.14.7
venv libdirs   : python3.12
sys.path       : ['', '/usr/local/lib/python314.zip',
                  '/usr/local/lib/python3.14',
                  '/usr/local/lib/python3.14/lib-dynload']

症状是在入口点遇到的第一个非标准库导入处出现 ModuleNotFoundError,这会让人一味寻找缺失的依赖,而不是发现解释器版本不匹配。

像示例中那样,让两个 FROM 行共用一个 ARG。Renovate 会扩展 FROM 中使用的 ARG 默认值,因此版本仍可更新,同时两个阶段也不会发生偏差。

为什么机器人可能会拆分构建阶段

Renovate 按镜像名称匹配镜像。如果两个阶段使用相同的镜像名称,它会一并更新;如果它们使用不同的镜像——例如 ghcr.io/astral-sh/uv:python3.12-alpine 作为构建器,而 python:3.12-alpine 作为运行时镜像——它的 Python 规则只会匹配后者,并单独更新它。差异中不会显示耦合关系已被破坏。

如果构建器需要 uv,应复制 uv 二进制文件,而不是切换基础镜像,这样两个阶段就能继续使用相同的 python: 基础镜像:

ARG PYTHON_VERSION=3.12
FROM ghcr.io/astral-sh/uv:0.12.7 AS uv

FROM python:${PYTHON_VERSION}-slim AS build
COPY --from=uv /uv /uvx /bin/

FROM python:${PYTHON_VERSION}-slim AS runtime
COPY --from=build /app/.venv /app/.venv
验证并确保检查确实有效

docker build 成功只能证明各层已组装完成,并不能证明容器能够启动。发布前先运行镜像,并断言虚拟环境位于路径中,而不只是导入某个内容:

docker run --rm -i "$IMAGE" /app/.venv/bin/python - <<'EOF'
import sys
assert [p for p in sys.path if "/app/.venv/" in p], sys.path
print("ok", sys.version.split()[0])
EOF

-i 至关重要。没有它,docker 不会转发标准输入,python - 会读取一个空脚本,检查会在未执行任何断言的情况下以 0 退出——之后它会对任何镜像都通过,包括有问题的镜像。应通过对故意不匹配的构建运行检查并要求其失败,来验证此类门禁确实有效。

包管理器摘要

管理器速度命令备注
uv快 10-100 倍uv sync --frozen --no-dev推荐
poetry标准poetry install --only=main设置 POETRY_VIRTUALENVS_IN_PROJECT=1
pip标准pip install --no-cache-dir --prefix=/install -r requirements.txt多阶段构建时使用 --prefix

性能影响

指标完整版(1GB)精简版(400MB)多阶段构建(150MB)优化版(100MB)
镜像大小1GB400MB150MB100MB
拉取时间4m1m 30s35s20s
构建时间(pip)5m4m3m3m
构建时间(uv)--45s30s
内存用量600MB350MB200MB150MB

安全影响

镜像类型漏洞数量大小风险
python:3.11(完整)50-70 个 CVE1GB高
python:3.11-slim12-18 个 CVE400MB中
多阶段精简版8-12 个 CVE150MB低
Distroless Python4-6 个 CVE140MB极低

Agent 优化

场景命令用途
快速构建DOCKER_BUILDKIT=1 docker build -t app .使用缓存快速构建
检查大小docker images app --format "table {{.Repository}}\t{{.Size}}"检查镜像大小
分析层docker history app:latest --human | head -20查找较大的层
测试导入docker run --rm app python -c "import app"验证导入是否正常
依赖列表docker run --rm app pip list --format=freeze查看已安装的软件包
安全扫描docker run --rm app pip-audit检查漏洞

最佳实践

  • Python 项目使用 slim,而不是 alpine
  • 使用 uv 实现最快构建(比 pip 快 10-100 倍)
  • 使用多阶段构建
  • 设置 PYTHONUNBUFFERED=1 和 PYTHONDONTWRITEBYTECODE=1
  • 使用非 root 用户运行
  • 使用虚拟环境,并通过锁文件固定依赖版本
  • 使用 pip 时添加 --no-cache-dir

如需详细示例、高级模式和最佳实践,请参阅 REFERENCE.md。

相关技能

  • container-development - 通用容器模式、多阶段构建和安全
  • go-containers - Go 专属容器优化
  • nodejs-containers - Node.js 专属容器优化

评论

支持 Markdown