Dockerfile 最佳实践及案例

Dockerfile 最佳实践及案例

核心最佳实践

1. 基础镜像选择

# 推荐:使用具体版本标签
FROM node:20-alpine AS builder

# 避免:使用latest
FROM node:latest

2. 分层缓存优化

# 推荐:先复制依赖文件,后复制源码
COPY package*.json ./
RUN npm install

COPY . .

# 避免:一次性复制所有文件
COPY . .
RUN npm install

3. 多阶段构建

# 构建阶段
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o myapp

# 运行阶段
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
CMD ["./myapp"]

4. 减小镜像体积

# 清理缓存和临时文件
RUN apt-get update && apt-get install -y \
    package1 \
    package2 \
    && rm -rf /var/lib/apt/lists/*

# 合并RUN命令减少层数
RUN apt-get update \
    && apt-get install -y curl \
    && curl -sL https://example.com/script.sh | bash \
    && apt-get remove -y curl \
    && apt-get autoremove -y \
    && rm -rf /var/lib/apt/lists/*

实际案例

案例1:Node.js 应用

# 多阶段构建Node.js应用
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app

# 创建非root用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

COPY --from=deps --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --chown=nodejs:nodejs package*.json ./

USER nodejs

EXPOSE 3000
ENV NODE_ENV=production

CMD ["node", "dist/main.js"]

案例2:Python 应用

FROM python:3.11-slim AS builder

WORKDIR /app

# 安装构建依赖
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

FROM python:3.11-slim

WORKDIR /app

# 只复制运行时依赖
COPY --from=builder /root/.local /root/.local

COPY . .

# 确保PATH包含用户安装的包
ENV PATH=/root/.local/bin:$PATH

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD python -c "import requests; requests.get('http://localhost:8000/health')"

EXPOSE 8000

# 使用非root用户
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser

CMD ["python", "app.py"]

案例3:Java/Spring Boot 应用

# 多阶段构建Spring Boot应用
FROM eclipse-temurin:21-jdk-alpine AS builder

WORKDIR /app

# 利用Docker层缓存
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
RUN ./mvnw dependency:go-offline -B

COPY src src
RUN ./mvnw package -DskipTests

FROM eclipse-temurin:21-jre-alpine

WORKDIR /app

# 使用jlink创建自定义JRE(可选)
RUN $JAVA_HOME/bin/jlink \
    --module-path $JAVA_HOME/jmods \
    --add-modules java.base,java.logging,java.sql \
    --output /custom-jre

# 复制jar文件
COPY --from=builder /app/target/*.jar app.jar

# JVM优化参数
ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC"

EXPOSE 8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=30s \
    CMD wget --quiet --tries=1 --spider http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

案例4:Nginx 静态网站

FROM node:20-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine

# 复制自定义nginx配置
COPY nginx.conf /etc/nginx/nginx.conf

# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html

# 设置正确的权限
RUN chown -R nginx:nginx /usr/share/nginx/html && \
    chmod -R 755 /usr/share/nginx/html

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
    CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

.dockerignore 示例

# Git
.git/
.gitignore

# Node
node_modules/
npm-debug.log
.env
.env.local

# Build
dist/
build/
*.log

# IDE
.vscode/
.idea/
*.swp

# OS
.DS_Store
Thumbs.db

# Docker
Dockerfile
.dockerignore
docker-compose*.yml

# CI/CD
.github/
.gitlab-ci.yml
.travis.yml

安全最佳实践

# 1. 使用具体版本标签
FROM alpine:3.19

# 2. 避免以root运行
RUN addgroup -g 1001 -S appgroup && \
    adduser -S appuser -u 1001 -G appgroup

# 3. 使用COPY而非ADD(除非需要解压)
COPY --chown=appuser:appuser . .

# 4. 设置不可变文件系统
RUN chmod -R 755 /app && \
    chown -R appuser:appgroup /app

USER appuser

# 5. 使用secrets,避免在镜像中存储敏感信息
# docker build --secret id=mysecret,src=secret.txt .
RUN --mount=type=secret,id=mysecret \
    cat /run/secrets/mysecret > /app/config.json

通用推荐设置

# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 限制日志大小(部分应用)
ENV NODE_OPTIONS="--max-old-space-size=512"

模版参考

# 多阶段构建:生产环境镜像
# ============================================

# ---------- 阶段 1:依赖安装 ----------
FROM node:20-alpine AS deps

# 如果有私有 npm 源或需要系统依赖
RUN apk add --no-cache python3 make g++

WORKDIR /app

# 只复制依赖文件(利用 Docker 缓存)
COPY package.json package-lock.json ./
# 如果需要 yarn,使用 yarn.lock
# COPY yarn.lock ./

# 安装仅生产依赖(+ 可选:lock 文件校验)
RUN npm ci --only=production --no-audit --no-fund && \
    npm cache clean --force


# ---------- 阶段 2:构建/编译(如果需要)----------
FROM node:20-alpine AS builder

WORKDIR /app

# 复制依赖文件并安装所有依赖(含 dev)
COPY package.json package-lock.json ./
RUN npm ci --no-audit --no-fund

# 复制源码并构建(如 TypeScript、React 等)
COPY . .
RUN npm run build  # 假设有构建脚本


# ---------- 阶段 3:生产运行 ----------
FROM node:20-alpine

# 创建非 root 用户(安全最佳实践)
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

# 安装必要的系统工具(例如 curl 用于健康检查,可选)
RUN apk add --no-cache curl

WORKDIR /app

# 从 deps 阶段复制生产 node_modules
COPY --from=deps --chown=nodejs:nodejs /app/node_modules ./node_modules

# 如果需要构建产物(如 dist, build 目录)
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
# 或者直接复制整个应用(但建议 .dockerignore 忽略不必要文件)
COPY --chown=nodejs:nodejs package.json ./

# 切换用户
USER nodejs

# 暴露应用端口
EXPOSE 3000

# 健康检查(根据应用调整间隔和命令)
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

# 启动命令
CMD ["node", "dist/main.js"]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容