镜像构建实践
Docker 镜像构建的实践技巧和最佳实践
📋 目录
构建上下文
什么是构建上下文
构建上下文是 Docker 构建时的工作目录,Dockerfile 中的 COPY 和 ADD 指令只能访问构建上下文中的文件。
# 当前目录作为构建上下文
docker build -t myapp:latest .
# 指定目录作为构建上下文
docker build -t myapp:latest /path/to/build/context
# 使用远程 URL 作为构建上下文
docker build -t myapp:latest https://github.com/user/repo.git构建上下文大小
构建上下文会被发送到 Docker 守护进程,过大的上下文会影响构建速度。
# 查看构建上下文大小
du -sh .
# 优化构建上下文
# 1. 使用 .dockerignore 排除不必要的文件
# 2. 只复制必要的文件.dockerignore 文件
作用
.dockerignore 文件用于排除构建上下文中不需要的文件,类似于 .gitignore。
语法规则
# 注释
# 排除文件
*.log
*.tmp
# 排除目录
node_modules/
.git/
.vscode/
# 排除特定文件
README.md
Dockerfile
# 使用通配符
*.md
test/*.js
# 排除但包含特定文件
*.md
!README.md示例
# Git 相关
.git
.gitignore
.gitattributes
# 开发工具
.vscode/
.idea/
*.swp
*.swo
# 依赖和构建产物
node_modules/
dist/
build/
*.log
# 测试文件
test/
*.test.js
coverage/
# 文档
*.md
docs/
# 环境配置
.env
.env.local构建缓存机制
缓存原理
Docker 使用层缓存机制,如果 Dockerfile 中的指令没有变化,会复用之前的层。
缓存失效
以下情况会导致缓存失效:
- Dockerfile 指令发生变化
- 构建上下文中的文件发生变化(COPY/ADD)
- 使用
--no-cache参数
# 不使用缓存构建
docker build --no-cache -t myapp:latest .
# 使用特定缓存源
docker build --cache-from myapp:previous -t myapp:latest .优化缓存使用
# 好的做法:先复制依赖文件,利用缓存
COPY package.json package-lock.json ./
RUN npm install
COPY . .
# 不好的做法:先复制所有文件
COPY . .
RUN npm install构建参数传递
ARG 构建参数
# 定义构建参数
ARG VERSION=latest
ARG BUILD_DATE
ARG NODE_ENV=production
# 使用构建参数
LABEL version=$VERSION
ENV NODE_ENV=$NODE_ENV传递构建参数
# 传递单个参数
docker build --build-arg VERSION=1.0.0 -t myapp:latest .
# 传递多个参数
docker build \
--build-arg VERSION=1.0.0 \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
-t myapp:latest .
# 从环境变量传递
export VERSION=1.0.0
docker build --build-arg VERSION=$VERSION -t myapp:latest .ARG 与 ENV 的区别
- ARG:构建时变量,构建后不存在
- ENV:运行时变量,容器运行时存在
ARG BUILD_VERSION
ENV APP_VERSION=$BUILD_VERSION多架构构建
Buildx 多架构构建
# 安装 buildx
docker buildx create --use
# 构建多架构镜像
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t username/myapp:latest \
--push .
# 查看支持的平台
docker buildx inspect --bootstrap平台特定构建
# 为特定平台构建
docker buildx build \
--platform linux/arm64 \
-t myapp:arm64 \
--load .构建优化技巧
1. 减少镜像层数
# 好的做法:合并 RUN 指令
RUN apt-get update && \
apt-get install -y nginx && \
rm -rf /var/lib/apt/lists/*
# 不好的做法:多个 RUN 指令
RUN apt-get update
RUN apt-get install -y nginx
RUN rm -rf /var/lib/apt/lists/*2. 使用多阶段构建
# 构建阶段
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 运行阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html3. 合理使用缓存
# 先复制依赖文件(变化频率低)
COPY package.json package-lock.json ./
RUN npm install
# 再复制源代码(变化频率高)
COPY . .4. 清理不必要的文件
RUN apt-get update && \
apt-get install -y nginx && \
rm -rf /var/lib/apt/lists/* && \
apt-get clean5. 使用 .dockerignore
确保 .dockerignore 文件排除不必要的文件,减小构建上下文。
构建输出控制
输出格式
# 静默构建(只显示错误)
docker build -q -t myapp:latest .
# 详细输出
docker build --progress=plain -t myapp:latest .
# JSON 输出
docker build --progress=json -t myapp:latest .构建日志
# 保存构建日志
docker build -t myapp:latest . 2>&1 | tee build.log常见问题
1. 构建上下文过大
问题:构建上下文包含大量文件,导致构建缓慢。
解决:
- 使用
.dockerignore排除不必要的文件 - 只复制必要的文件到构建上下文
2. 缓存失效
问题:每次构建都重新下载依赖。
解决:
- 合理组织 Dockerfile 指令顺序
- 先复制依赖文件,再复制源代码
3. 构建失败
问题:构建过程中出现错误。
解决:
# 查看详细错误信息
docker build --progress=plain -t myapp:latest .
# 使用中间镜像调试
docker build --target builder -t myapp:builder .
docker run -it myapp:builder /bin/bash4. 权限问题
问题:构建时文件权限不正确。
解决:
# 设置正确的文件权限
COPY --chown=user:user app /app
RUN chmod +x /app/entrypoint.sh实用脚本
构建脚本示例
#!/bin/bash
# build.sh
IMAGE_NAME="myapp"
VERSION=${1:-latest}
REGISTRY="registry.example.com"
echo "Building ${IMAGE_NAME}:${VERSION}"
docker build \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
--build-arg VERSION=${VERSION} \
-t ${IMAGE_NAME}:${VERSION} \
-t ${IMAGE_NAME}:latest \
-t ${REGISTRY}/${IMAGE_NAME}:${VERSION} \
.
echo "Build complete: ${IMAGE_NAME}:${VERSION}"