二、基础使用与语法
2.1 简单示例
# 阶段 1:构建阶段
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 阶段 2:生产阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
2.2 AS 别名命名
# 使用别名
FROM golang:1.22 AS build-stage
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY *.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -o /app
# 使用 alias
FROM gcr.io/distroless/static-debian12
COPY --from=build-stage /app /app
CMD ["/app"]
三、多阶段构建深入
3.1 阶段间文件复制
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production # 仅安装生产依赖
RUN npm install -g typescript
COPY tsconfig.json ./
COPY src ./src
RUN tsc
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
USER node
CMD ["node", "dist/index.js"]
3.2 复制特定文件
# 从特定阶段复制特定文件
FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install -y gcc make
COPY . .
RUN make
FROM alpine:3.19
COPY --from=builder /app/bin/main /usr/local/bin/
COPY --from=builder /app/config/*.yaml /etc/app/
CMD ["main"]
四、缓存优化
4.1 分层利用缓存
FROM node:18 AS deps
WORKDIR /app
# 先复制 package 文件,利用缓存
COPY package*.json ./
RUN npm ci
FROM node:18 AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:18-alpine AS prod
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=deps /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
4.2 RUN 缓存挂载
# Docker 18.09+ 支持缓存挂载
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/app/.npm npm ci --cache /app/.npm
COPY . .
RUN npm run build
五、语言特定优化
5.1 Go 语言
# 多阶段 Go 构建
FROM golang:1.22 AS builder
WORKDIR /app
ENV CGO_ENABLED=0
ENV GOOS=linux
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -ldflags="-s -w" -o myapp
# distroless 镜像
FROM gcr.io/distroless/static-debian12
WORKDIR /
COPY --from=builder /app/myapp /myapp
CMD ["/myapp"]
5.2 Java
# Maven 多阶段构建
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml ./
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
# 运行阶段
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
5.3 Python
# Python 多阶段构建
FROM python:3.12 AS builder
WORKDIR /app
RUN python -m venv venv
ENV PATH="/app/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /app/venv ./venv
ENV PATH="/app/venv/bin:$PATH"
COPY app.py .
CMD ["python", "app.py"]
六、高级技巧
6.1 多平台构建
# 使用 buildx
FROM --platform=$BUILDPLATFORM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM --platform=$TARGETPLATFORM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
6.2 命名多个阶段
FROM node:18 AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM base AS dev
COPY . .
CMD ["npm", "run", "dev"]
FROM base AS build
COPY . .
RUN npm run build
FROM nginx:alpine AS prod
COPY --from=build /app/dist /usr/share/nginx/html
6.3 使用外部镜像作为源
FROM alpine:3.19
# 从官方 nginx 复制文件
COPY --from=nginx:alpine /etc/nginx/nginx.conf /etc/nginx/
COPY --from=nginx:alpine /docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
七、最佳实践
7.1 优化要点
- 使用 Alpine 或 Distroless 作为基础
- 分离依赖安装与代码构建
- 利用多阶段缓存
- 移除调试信息
- 合并 RUN 命令
7.2 安全性考量
FROM node:18 AS builder
# ...
FROM node:18-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
WORKDIR /app
COPY --chown=appuser:appgroup --from=builder /app/dist ./dist