docker-build

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Docker Build for Python/FastAPI Applications

Python/FastAPI应用的Docker构建

Overview

概述

Containerize Python and FastAPI applications using Docker with production-grade multi-stage builds, layer caching, security hardening, and Docker Compose orchestration. All patterns target Python 3.12+, use
uv
for dependency management, and follow the principle of minimal, reproducible images.
Refer to the asset templates bundled with this skill for ready-to-use starting points:
  • assets/Dockerfile.fastapi
    -- production multi-stage Dockerfile
  • assets/Dockerfile.dev
    -- development Dockerfile with hot reload
  • assets/docker-compose.yml
    -- Compose stack with PostgreSQL and Redis
  • assets/.dockerignore
    -- ignore rules for lean build contexts

使用Docker对Python和FastAPI应用进行容器化,采用生产级别的多阶段构建、层缓存、安全加固以及Docker Compose编排。所有模式均针对Python 3.12+版本,使用
uv
进行依赖管理,并遵循最小化、可复现镜像的原则。
参考此技能附带的资产模板,获取可直接使用的起点:
  • assets/Dockerfile.fastapi
    -- 生产环境多阶段Dockerfile
  • assets/Dockerfile.dev
    -- 带热重载的开发环境Dockerfile
  • assets/docker-compose.yml
    -- 包含PostgreSQL和Redis的Compose栈
  • assets/.dockerignore
    -- 精简构建上下文的忽略规则

Base Image Selection

基础镜像选择

Choose the base image according to the deployment target and dependency requirements.
根据部署目标和依赖要求选择基础镜像。

python:3.12-slim (recommended)

python:3.12-slim(推荐)

The default choice for most FastAPI projects. Based on Debian Bookworm with a minimal package set. Binary wheels from PyPI install without issues, and system libraries such as
libpq
can be added via
apt-get
.
dockerfile
FROM python:3.12-slim AS base
大多数FastAPI项目的默认选择。基于Debian Bookworm,包含最小化的软件包集合。PyPI的二进制wheel可顺利安装,可通过
apt-get
添加
libpq
等系统库。
dockerfile
FROM python:3.12-slim AS base

python:3.12-alpine

python:3.12-alpine

Smaller download size, but Alpine uses musl libc. Packages with C extensions (e.g.,
psycopg2
,
numpy
,
pandas
) often fail to install or require building from source, negating the size advantage. Avoid unless the dependency tree is pure Python.
下载体积更小,但Alpine使用musl libc。带有C扩展的软件包(如
psycopg2
numpy
pandas
)通常安装失败或需要从源码构建,抵消了体积优势。除非依赖树全部为纯Python,否则避免使用。

ghcr.io/astral-sh/uv:python3.12-bookworm-slim

ghcr.io/astral-sh/uv:python3.12-bookworm-slim

Ships with
uv
pre-installed. Useful when the build should not fetch
uv
at build time. The image is Debian-based and behaves like
python:3.12-slim
otherwise.
dockerfile
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder

预安装了
uv
。适用于构建时无需拉取
uv
的场景。该镜像基于Debian,其他行为与
python:3.12-slim
一致。
dockerfile
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder

Multi-Stage Build Pattern

多阶段构建模式

Separate dependency installation from the final runtime image to keep the production image small and free of build tools.
将依赖安装与最终运行时镜像分离,以保持生产镜像体积小巧且不含构建工具。

Stage 1 -- Builder

阶段1 -- 构建器

Install
uv
, copy only the dependency manifests, and resolve/install dependencies into a virtual environment. This stage may contain compilers and header packages that must not ship in production.
dockerfile
FROM python:3.12-slim AS builder

COPY --from=ghcr.io/astral-sh/uv /uv /usr/local/bin/uv

ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy

WORKDIR /app

COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-install-project

COPY . .
RUN uv sync --frozen --no-dev
安装
uv
,仅复制依赖清单,并将依赖解析/安装到虚拟环境中。此阶段可包含编译器和头文件包,但这些不得随生产镜像发布。
dockerfile
FROM python:3.12-slim AS builder

COPY --from=ghcr.io/astral-sh/uv /uv /usr/local/bin/uv

ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy

WORKDIR /app

COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-install-project

COPY . .
RUN uv sync --frozen --no-dev

Stage 2 -- Runtime

阶段2 -- 运行时

Start from a clean slim image, copy only the virtual environment and application source from the builder, create a non-root user, and declare the entrypoint.
dockerfile
FROM python:3.12-slim AS runtime

WORKDIR /app

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

ENV PATH="/app/.venv/bin:$PATH"

RUN useradd --create-home --shell /bin/bash appuser
USER appuser

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

从干净的slim镜像开始,仅从构建器复制虚拟环境和应用源码,创建非root用户,并声明入口点。
dockerfile
FROM python:3.12-slim AS runtime

WORKDIR /app

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

ENV PATH="/app/.venv/bin:$PATH"

RUN useradd --create-home --shell /bin/bash appuser
USER appuser

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

uv Integration in Docker

Docker中的uv集成

Installing uv

安装uv

The fastest method is a static binary copy from the official image:
dockerfile
COPY --from=ghcr.io/astral-sh/uv /uv /usr/local/bin/uv
Alternatively, install via pip (slower, but works on any base):
dockerfile
RUN pip install --no-cache-dir uv
最快的方法是从官方镜像复制静态二进制文件:
dockerfile
COPY --from=ghcr.io/astral-sh/uv /uv /usr/local/bin/uv
或者通过pip安装(速度较慢,但可在任何基础镜像上运行):
dockerfile
RUN pip install --no-cache-dir uv

Dependency Resolution

依赖解析

Always pass
--frozen
to
uv sync
inside Docker so that the lockfile is used as-is without resolution. This guarantees reproducible builds.
dockerfile
RUN uv sync --frozen --no-dev
For uv dependency management outside of Docker, consult the
uv
skill.

在Docker内部执行
uv sync
时,始终传递
--frozen
参数,以便直接使用锁定文件而不进行重新解析。这可确保构建的可复现性。
dockerfile
RUN uv sync --frozen --no-dev
关于Docker之外的uv依赖管理,请参考
uv
技能文档。

Layer Ordering for Cache Efficiency

缓存效率的层顺序

Docker caches each layer. When a layer changes, every subsequent layer is rebuilt. Order instructions from least to most frequently changing:
  1. Base image and system packages
  2. Copy dependency manifests (
    pyproject.toml
    ,
    uv.lock
    )
  3. Install dependencies (
    uv sync
    )
  4. Copy application source code
  5. Any final build steps
dockerfile
undefined
Docker会缓存每个层。当某一层发生变化时,后续所有层都将重新构建。按变更频率从低到高排列指令:
  1. 基础镜像和系统软件包
  2. 复制依赖清单(
    pyproject.toml
    uv.lock
  3. 安装依赖(
    uv sync
  4. 复制应用源码
  5. 任何最终构建步骤
dockerfile
undefined

Step 2 -- manifests change infrequently

步骤2 -- 清单变更频率低

COPY pyproject.toml uv.lock ./
COPY pyproject.toml uv.lock ./

Step 3 -- re-runs only when manifests change

步骤3 -- 仅在清单变更时重新运行

RUN uv sync --frozen --no-dev --no-install-project
RUN uv sync --frozen --no-dev --no-install-project

Step 4 -- changes on every code edit

步骤4 -- 每次代码编辑都会变更

COPY src/ src/

This ordering ensures that dependency installation is cached across most code
changes, drastically reducing rebuild times.

---
COPY src/ src/

此顺序确保依赖安装在大多数代码变更时都能被缓存,大幅缩短重建时间。

---

Security Hardening

安全加固

Non-Root User

非Root用户

Never run the application as root inside the container. Create a dedicated user and switch to it before
CMD
.
dockerfile
RUN useradd --create-home --shell /bin/bash appuser
USER appuser
For stricter security, use a numeric UID and no login shell:
dockerfile
RUN adduser --system --uid 1001 --no-create-home appuser
USER 1001
永远不要在容器内以root身份运行应用。创建专用用户,并在
CMD
之前切换到该用户。
dockerfile
RUN useradd --create-home --shell /bin/bash appuser
USER appuser
如需更严格的安全设置,可使用数字UID且不设置登录shell:
dockerfile
RUN adduser --system --uid 1001 --no-create-home appuser
USER 1001

Minimal Packages

最小化软件包

Do not install editors, debug tools, or documentation packages in the production image. If build-time packages are necessary (e.g.,
gcc
,
libpq-dev
), install them only in the builder stage.
不要在生产镜像中安装编辑器、调试工具或文档软件包。如果构建时需要某些软件包(如
gcc
libpq-dev
),仅在构建器阶段安装它们。

.dockerignore

.dockerignore

Exclude files that must not enter the build context: version control metadata, local environment files, test suites, caches, and documentation. See
assets/.dockerignore
for a comprehensive template.
排除不得进入构建上下文的文件:版本控制元数据、本地环境文件、测试套件、缓存和文档。参考
assets/.dockerignore
获取全面的模板。

Pin Image Digests in CI

在CI中固定镜像摘要

For reproducible CI builds, pin the base image to a digest:
dockerfile
FROM python:3.12-slim@sha256:<digest> AS builder

为实现可复现的CI构建,将基础镜像固定到具体的摘要值:
dockerfile
FROM python:3.12-slim@sha256:<digest> AS builder

HEALTHCHECK Instruction

HEALTHCHECK指令

Define a health check so orchestrators (Docker Swarm, Compose, ECS) can detect unresponsive containers and restart them automatically.
dockerfile
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] || exit 1
If
curl
is available in the runtime image, prefer the simpler form:
dockerfile
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:8000/health || exit 1
Ensure the FastAPI application exposes a lightweight
/health
endpoint that returns HTTP 200.

定义健康检查,以便编排器(Docker Swarm、Compose、ECS)能够检测无响应的容器并自动重启。
dockerfile
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] || exit 1
如果运行时镜像中包含
curl
,可使用更简洁的形式:
dockerfile
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:8000/health || exit 1
确保FastAPI应用暴露一个轻量级的
/health
端点,返回HTTP 200状态码。

Environment Variables

环境变量

Set these early in the Dockerfile to influence Python runtime behavior:
dockerfile
undefined
在Dockerfile中尽早设置这些变量,以影响Python运行时行为:
dockerfile
undefined

Send stdout/stderr straight to the terminal without buffering

将stdout/stderr直接发送到终端,不进行缓冲

ENV PYTHONUNBUFFERED=1
ENV PYTHONUNBUFFERED=1

Prevent .pyc file creation inside the container

防止在容器内创建.pyc文件

ENV PYTHONDONTWRITEBYTECODE=1

Application-specific variables (database URL, secret keys) should be injected
at runtime via `docker run --env-file` or the Compose `env_file` directive,
never baked into the image.

---
ENV PYTHONDONTWRITEBYTECODE=1

应用特定的变量(数据库URL、密钥)应在运行时通过`docker run --env-file`或Compose的`env_file`指令注入,永远不要嵌入到镜像中。

---

CMD with Exec Form

执行格式的CMD

Always use the exec form (JSON array) for
CMD
so that
uvicorn
receives signals directly from Docker and can shut down gracefully.
dockerfile
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Avoid the shell form (
CMD uvicorn ...
) because it wraps the process in
/bin/sh -c
, which swallows
SIGTERM
and delays container stops.
For uvicorn production configuration (workers, timeouts, keep-alive), consult the
uvicorn
skill.

始终使用执行格式(JSON数组)编写
CMD
,以便
uvicorn
直接接收来自Docker的信号并优雅关闭。
dockerfile
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
避免使用shell格式(
CMD uvicorn ...
),因为它会将进程包装在
/bin/sh -c
中,这会吞噬
SIGTERM
信号并延迟容器停止。
关于uvicorn的生产配置(工作进程、超时、保持连接),请参考
uvicorn
技能文档。

Docker Compose

Docker Compose

Use Docker Compose to orchestrate the application alongside backing services such as PostgreSQL and Redis. See
assets/docker-compose.yml
for a complete template.
使用Docker Compose将应用与PostgreSQL、Redis等后端服务一起编排。参考
assets/docker-compose.yml
获取完整模板。

Service Definitions

服务定义

yaml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.fastapi
    ports:
      - "8000:8000"
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
yaml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.fastapi
    ports:
      - "8000:8000"
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy

Health Checks in Compose

Compose中的健康检查

Each service should declare a
healthcheck
so that
depends_on
with
condition: service_healthy
works correctly.
yaml
db:
  image: postgres:16-alpine
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U postgres"]
    interval: 10s
    timeout: 5s
    retries: 5
每个服务都应声明
healthcheck
,以便
depends_on
配合
condition: service_healthy
正常工作。
yaml
db:
  image: postgres:16-alpine
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U postgres"]
    interval: 10s
    timeout: 5s
    retries: 5

Volumes

Persist database data across container recreations:
yaml
volumes:
  postgres_data:
  redis_data:
在容器重新创建时持久化数据库数据:
yaml
volumes:
  postgres_data:
  redis_data:

Networks

网络

Isolate inter-service traffic on a dedicated bridge network:
yaml
networks:
  backend:
    driver: bridge

在专用的桥接网络上隔离服务间通信:
yaml
networks:
  backend:
    driver: bridge

Development vs Production Dockerfiles

开发与生产Dockerfile对比

Maintain separate Dockerfiles for each environment.
为每个环境维护单独的Dockerfile。

Production (
Dockerfile.fastapi
)

生产环境(
Dockerfile.fastapi

  • Multi-stage build
  • --no-dev
    dependencies only
  • Source code copied into the image
  • Non-root user, health check, exec-form CMD
  • 多阶段构建
  • 仅包含
    --no-dev
    依赖
  • 源码复制到镜像中
  • 非root用户、健康检查、执行格式的CMD

Development (
Dockerfile.dev
)

开发环境(
Dockerfile.dev

  • Single stage for simplicity
  • All dependencies including dev extras (
    pytest
    ,
    ruff
    , etc.)
  • Source code mounted via a bind volume -- do not
    COPY
    source
  • --reload
    flag on uvicorn for hot reload
dockerfile
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
Override the production Compose file with a development variant:
yaml
undefined
  • 单阶段构建,简化流程
  • 包含所有依赖,包括开发附加组件(
    pytest
    ruff
    等)
  • 源码通过绑定卷挂载 -- 不要
    COPY
    源码
  • uvicorn使用
    --reload
    标志实现热重载
dockerfile
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
使用开发变体覆盖生产Compose文件:
yaml
undefined

docker-compose.override.yml

docker-compose.override.yml

services: app: build: dockerfile: Dockerfile.dev volumes: - .:/app

---
services: app: build: dockerfile: Dockerfile.dev volumes: - .:/app

---

Build Arguments

构建参数

Use
ARG
to parameterize the build without creating multiple Dockerfiles.
dockerfile
ARG PYTHON_VERSION=3.12
FROM python:${PYTHON_VERSION}-slim AS builder

ARG APP_VERSION=0.0.0
LABEL org.opencontainers.image.version=${APP_VERSION}
Pass values at build time:
bash
docker build --build-arg PYTHON_VERSION=3.13 --build-arg APP_VERSION=1.2.0 .

使用
ARG
参数化构建,无需创建多个Dockerfile。
dockerfile
ARG PYTHON_VERSION=3.12
FROM python:${PYTHON_VERSION}-slim AS builder

ARG APP_VERSION=0.0.0
LABEL org.opencontainers.image.version=${APP_VERSION}
在构建时传递参数值:
bash
docker build --build-arg PYTHON_VERSION=3.13 --build-arg APP_VERSION=1.2.0 .

Volume Mounts for Development

开发环境的卷挂载

Bind-mount the project directory into the container so that file changes on the host are immediately visible inside the container, enabling uvicorn's
--reload
watcher.
bash
docker run -v "$(pwd)":/app -p 8000:8000 myapp-dev
In Compose:
yaml
services:
  app:
    volumes:
      - .:/app
Avoid bind-mounting over the
.venv
directory. If the virtual environment lives inside the project tree, use an anonymous volume to shadow it:
yaml
volumes:
  - .:/app
  - /app/.venv

将项目目录绑定挂载到容器中,以便主机上的文件变更能立即在容器内生效,启用uvicorn的
--reload
监视器。
bash
docker run -v "$(pwd)":/app -p 8000:8000 myapp-dev
在Compose中:
yaml
services:
  app:
    volumes:
      - .:/app
避免绑定挂载覆盖
.venv
目录。如果虚拟环境位于项目目录内,使用匿名卷将其隐藏:
yaml
volumes:
  - .:/app
  - /app/.venv

Image Size Reduction Checklist

镜像体积缩减清单

  1. Use
    python:3.12-slim
    instead of the full
    python
    image.
  2. Apply multi-stage builds; keep compilers in the builder stage only.
  3. Combine
    RUN
    commands where logical to reduce layer count.
  4. Pass
    --no-cache-dir
    to pip or use
    uv
    (which never caches by default).
  5. Remove apt lists after installing system packages:
    RUN apt-get update && apt-get install -y --no-install-recommends pkg && rm -rf /var/lib/apt/lists/*
  6. Add a thorough
    .dockerignore
    to minimize the build context.
  7. Compile bytecode at build time (
    UV_COMPILE_BYTECODE=1
    ) and skip
    .pyc
    generation at runtime (
    PYTHONDONTWRITEBYTECODE=1
    ).

  1. 使用
    python:3.12-slim
    而非完整的
    python
    镜像。
  2. 采用多阶段构建;仅在构建器阶段保留编译器。
  3. 在合理的情况下合并
    RUN
    命令,以减少层数。
  4. 向pip传递
    --no-cache-dir
    参数,或使用
    uv
    (默认从不缓存)。
  5. 安装系统软件包后删除apt列表:
    RUN apt-get update && apt-get install -y --no-install-recommends pkg && rm -rf /var/lib/apt/lists/*
  6. 添加完善的
    .dockerignore
    以最小化构建上下文。
  7. 在构建时编译字节码(
    UV_COMPILE_BYTECODE=1
    ),并在运行时跳过
    .pyc
    生成(
    PYTHONDONTWRITEBYTECODE=1
    )。

Multi-Architecture Builds

多架构构建

Build images for multiple platforms using
docker buildx
:
bash
undefined
使用
docker buildx
为多个平台构建镜像:
bash
undefined

Create a buildx builder

创建buildx构建器

docker buildx create --name multiarch --use
docker buildx create --name multiarch --use

Build and push for amd64 and arm64

为amd64和arm64构建并推送

docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest --push .

When using multi-arch builds, ensure all base images support the target platforms. Avoid architecture-specific binaries in `COPY` instructions.

---
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest --push .

使用多架构构建时,确保所有基础镜像支持目标平台。避免在`COPY`指令中使用特定架构的二进制文件。

---

BuildKit Secrets

BuildKit密钥

Mount secrets at build time without baking them into image layers:
dockerfile
undefined
在构建时挂载密钥,而不将其嵌入到镜像层中:
dockerfile
undefined

syntax=docker/dockerfile:1

syntax=docker/dockerfile:1

RUN --mount=type=secret,id=pip_index_url
PIP_INDEX_URL=$(cat /run/secrets/pip_index_url)
uv sync --frozen --no-dev

Pass the secret at build time:

```bash
docker build --secret id=pip_index_url,env=PIP_INDEX_URL .
Secrets are available only during the
RUN
instruction and never persist in the image history.

RUN --mount=type=secret,id=pip_index_url
PIP_INDEX_URL=$(cat /run/secrets/pip_index_url)
uv sync --frozen --no-dev

在构建时传递密钥:

```bash
docker build --secret id=pip_index_url,env=PIP_INDEX_URL .
密钥仅在
RUN
指令期间可用,永远不会保留在镜像历史中。

Common Labels

通用标签

Apply OCI-standard labels for image metadata:
dockerfile
LABEL org.opencontainers.image.title="my-fastapi-app"
LABEL org.opencontainers.image.description="FastAPI application"
LABEL org.opencontainers.image.version="1.0.0"
LABEL org.opencontainers.image.source="https://github.com/org/repo"

应用OCI标准标签以添加镜像元数据:
dockerfile
LABEL org.opencontainers.image.title="my-fastapi-app"
LABEL org.opencontainers.image.description="FastAPI application"
LABEL org.opencontainers.image.version="1.0.0"
LABEL org.opencontainers.image.source="https://github.com/org/repo"

Cross-References

交叉引用

  • For uvicorn production configuration (workers, timeouts, logging), consult the
    uvicorn
    skill.
  • For uv dependency management (lockfiles, workspaces, scripts), consult the
    uv
    skill.
  • 关于uvicorn的生产配置(工作进程、超时、日志),请参考
    uvicorn
    技能文档。
  • 关于uv依赖管理(锁定文件、工作区、脚本),请参考
    uv
    技能文档。