Dockerfile 最佳实践
下面是一份 企业级、可直接落地的《Dockerfile 最佳实践》,覆盖性能、构建速度、镜像大小、安全、可维护性等所有关键点。
内容 极简、明确、可用,并且适用于后端 / 前端 / Go / Python / Node / Java 等常见项目。
镜像越小:
- 拉取快
- 构建快
- 推送快
- 攻击面更小
推荐:总是首选 官方的 -slim / alpine / distroless 镜像
示例:
FROM python:3.12-slim
❌ 不推荐:
FROM ubuntu:latest
FROM python:latest
减少最终镜像体积、移除构建工具。
示例(前端):
# Build stage
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM nginx:1.27-alpine
COPY --from=builder /app/dist /usr/share/nginx/html
示例(Go):
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o app .
FROM gcr.io/distroless/base
COPY --from=builder /src/app /app
ENTRYPOINT ["/app"]
每一条指令都会创建一层,因此:
- 合并 RUN
- 避免 COPY 过多小文件
示例:
RUN apt-get update && apt-get install -y \
curl \
git \
&& rm -rf /var/lib/apt/lists/*
好处:
- 构建可重复
- 避免未知升级导致不可控 bug
示例:
FROM python:3.12.2-slim
FROM node:20.11.1-slim
FROM nginx:1.27.2-alpine
总是先 COPY 依赖文件,再安装依赖:
Node:
COPY package*.json .
RUN npm ci
COPY . .
Python:
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
Go:
COPY go.mod go.sum ./
RUN go mod download
COPY . .
使得依赖不变时,可以充分利用缓存。
避免把不需要的文件 COPY 进去:
dockerignore 示例:
.git
node_modules
venv
dist
__pycache__
*.log
.env
好处:
- 减少 context 大小
- 加快构建速度
- 降低泄漏风险
示例(Docker 官方推荐方式):
RUN adduser --disabled-password --gecos '' appuser
USER appuser
对于 distroless:
USER nonroot
原则:
- ENTRYPOINT:定义不变的部分
- CMD:允许被覆盖的部分
示例:
ENTRYPOINT ["python", "-m", "myapp"]
CMD ["--config", "/etc/myapp/config.yaml"]
- ❌ 不要 COPY .env
- ❌ 不要把密钥写入镜像
使用:
- docker secret
- k8s secret
- 环境变量注入
构建调试时:
docker build --no-cache .
CI/CD 中建议使用缓存加速构建。
添加标签:
LABEL org.opencontainers.image.authors="martin"
LABEL org.opencontainers.image.source="https://github.com/... "
LABEL org.opencontainers.image.version="1.0.2"
LABEL org.opencontainers.image.created="2025-12-27"
添加 healthcheck(可选):
HEALTHCHECK --interval=10s --timeout=2s \
CMD curl -f http://localhost/health || exit 1
FROM nginx:1.27-alpine
RUN rm -rf /etc/nginx/conf.d/*
COPY nginx.conf /etc/nginx/nginx.conf
COPY dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# ========== build ==========
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ========== production ==========
FROM nginx:1.27-alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
- ❌ 在容器里写大量日志(应该 stdout)
- ❌ 在容器内运行 systemd
- ❌ 在容器里使用 cron
- ❌ 安装太多无用包
- ❌ 基础镜像使用 latest
- ❌ 构建镜像把整个项目 COPY TOO MUCH
- ❌ Dockerfile 逻辑写成脚本一样复杂