Dockerfile 完全指南 🐳

🚀 掌握Docker镜像构建的艺术,打造高效、安全的容器化应用


📋 目录

  1. 🎯 Dockerfile 简介
  2. 📝 指令详解
  3. 🏗️ 多阶段构建
  4. ✅ 最佳实践
  5. 🔒 安全指南
  6. ⚡ 实战示例
  7. 🚀 构建与优化
  8. 🐛 调试技巧

🎯 Dockerfile 简介

📖 什么是 Dockerfile?

Dockerfile 是一个文本文件,包含了一系列的指令和参数,用于自动化构建 Docker 镜像。它就像是容器的”食谱”,定义了如何构建应用程序的运行环境。

🎨 基本结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 基础镜像 - 构建的起点
FROM ubuntu:20.04

# 元数据 - 镜像信息
LABEL maintainer="your.email@example.com"
LABEL version="1.0"
LABEL description="My awesome application"

# 环境变量 - 配置参数
ENV APP_HOME=/app \
NODE_ENV=production

# 工作目录 - 命令执行的上下文
WORKDIR $APP_HOME

# 复制文件 - 添加应用程序代码
COPY . .

# 安装依赖 - 构建环境
RUN apt-get update && \
apt-get install -y python3 pip && \
pip install -r requirements.txt

# 暴露端口 - 容器网络接口
EXPOSE 8000

# 启动命令 - 容器运行时执行的命令
CMD ["python3", "app.py"]

📝 指令详解

🏗️ FROM - 基础镜像

1
2
3
4
5
6
7
8
9
# 使用官方镜像
FROM python:3.9-slim

# 指定具体版本
FROM node:16.15.1-alpine3.16

# 使用多阶段构建的不同基础镜像
FROM golang:1.19 as builder
FROM alpine:3.16 as runtime

⚙️ RUN - 执行命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 单一命令
RUN apt-get update

# 多命令组合(减少镜像层)
RUN apt-get update && \
apt-get install -y \
git \
curl \
wget && \
rm -rf /var/lib/apt/lists/*

# 使用管道操作
RUN curl -sSL https://deb.nodesource.com/setup_16.x | bash -

# 创建目录并设置权限
RUN mkdir -p /app/logs && \
chmod 755 /app/logs

📂 COPY vs ADD - 文件复制

1
2
3
4
5
6
7
8
9
10
11
# COPY - 推荐使用,行为明确
COPY ./src /app/src
COPY package*.json ./
COPY requirements.txt .

# ADD - 自动解压和URL下载(谨慎使用)
ADD https://example.com/file.tar.gz /tmp/
ADD local-file.tar.gz /tmp/ # 会自动解压

# 复制时改变文件权限
COPY --chown=node:node . /app

🎯 CMD vs ENTRYPOINT - 启动命令

1
2
3
4
5
6
7
8
9
# CMD - 默认命令(可被覆盖)
CMD ["nginx", "-g", "daemon off;"]

# ENTRYPOINT - 主要命令
ENTRYPOINT ["/app/start.sh"]

# 组合使用
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["--help"]

🌐 ENV - 环境变量

1
2
3
4
5
6
7
8
9
10
11
# 单个变量
ENV APP_VERSION=1.0.0

# 多个变量
ENV APP_HOME=/app \
PORT=3000 \
NODE_ENV=production

# 构建时变量(Docker 17.05+)
ARG BUILD_VERSION
ENV VERSION=$BUILD_VERSION

📁 WORKDIR - 工作目录

1
2
3
4
5
6
7
8
9
# 设置工作目录
WORKDIR /app

# 后续指令都在此目录执行
RUN pwd # 输出 /app

# 可以多次使用
WORKDIR /app/src
RUN pwd # 输出 /app/src

🚪 EXPOSE - 端口暴露

1
2
3
4
5
6
7
8
9
# 单个端口
EXPOSE 80

# 多个端口
EXPOSE 80 443 3000

# 指定协议
EXPOSE 80/tcp
EXPOSE 53/udp

👤 USER - 用户设置

1
2
3
4
5
6
7
8
9
# 创建用户
RUN groupadd -r app && \
useradd -r -g app app

# 切换用户
USER app

# 指定UID/GID
USER 1000:1000

🏗️ 多阶段构建

🎯 为什么使用多阶段构建?

· 减小镜像大小 🐋 → 🐢
· 提高安全性 🔒
· 分离构建和运行环境 🏗️ → 🚀

📦 完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 阶段1: 构建环境
FROM node:16 as builder
WORKDIR /build
COPY package*.json ./
RUN npm ci --only=production

# 阶段2: 测试环境(可选)
FROM node:16 as tester
WORKDIR /test
COPY . .
COPY --from=builder /build/node_modules ./node_modules
RUN npm test

# 阶段3: 运行环境
FROM node:16-alpine as runtime
WORKDIR /app

# 安装运行时依赖
RUN apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 复制构建产物
COPY --from=builder /build/node_modules ./node_modules
COPY . .

# 设置非root用户
RUN addgroup -g 1001 -S app && \
adduser -u 1001 -S app -G app
USER app

EXPOSE 3000
CMD ["node", "server.js"]

🔧 高级多阶段技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
# 从其他镜像复制文件
FROM nginx:alpine as web
COPY --from=builder /app/dist /usr/share/nginx/html

# 使用scratch空镜像
FROM scratch
COPY --from=builder /app/bin/app /
CMD ["/app"]

# 多架构构建支持
FROM --platform=$BUILDPLATFORM golang:1.19 as builder
ARG TARGETARCH
RUN GOARCH=$TARGETARCH go build -o /app

✅ 最佳实践

🎯 1. 使用官方镜像

1
2
3
4
5
6
# 推荐 ✅
FROM python:3.9-slim

# 避免 ❌
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y python3

📦 2. 优化层缓存

1
2
3
4
5
6
7
8
9
10
# 先复制依赖文件
COPY package.json package-lock.json ./
RUN npm install

# 再复制源代码
COPY . .

# 而不是
COPY . .
RUN npm install # 每次代码变更都会重新安装依赖

🧹 3. 清理缓存和临时文件

1
2
3
4
5
6
7
8
RUN apt-get update && \
apt-get install -y \
build-essential \
git && \
# ... 安装完成后清理
apt-get purge -y build-essential git && \
apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/*

📝 4. 使用 .dockerignore

创建 .dockerignore 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 忽略文件
.git
.gitignore
README.md
Dockerfile
.dockerignore

# 忽略目录
node_modules
logs
temp
dist

# 忽略模式
*.log
*.tmp
*.swp

🔧 5. 健康检查

1
2
3
4
5
6
# 命令方式
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:3000/health || exit 1

# 禁用继承的健康检查
HEALTHCHECK NONE

🔒 安全指南

🛡️ 1. 避免以root运行

1
2
3
4
5
6
# 创建非特权用户
RUN adduser -D -u 1000 appuser
USER appuser

# 或者直接指定UID
USER 1000

🔐 2. 使用可信的基础镜像

1
2
3
4
5
# 使用官方镜像并指定版本
FROM debian:bullseye-20221004-slim

# 检查镜像漏洞
# docker scan <image-name>

📦 3. 最小化安装

1
2
3
4
5
6
7
# 只安装必要的包
RUN apt-get update && \
apt-get install -y \
--no-install-recommends \
ca-certificates \
curl && \
rm -rf /var/lib/apt/lists/*

🚨 4. 安全扫描

1
2
3
4
5
# 使用Docker Scout扫描镜像
docker scout quickview <image-name>

# 使用Trivy扫描漏洞
trivy image <image-name>

⚡ 实战示例

🐍 Python 应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
FROM python:3.9-slim as production

# 设置环境变量
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=on

WORKDIR /app

# 安装系统依赖
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gcc \
libpq-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# 安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 创建非root用户
RUN useradd --create-home --shell /bin/bash app
USER app

EXPOSE 8000

# 使用gunicorn运行
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

⚛️ Node.js 应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FROM node:18-alpine as builder
WORKDIR /build
COPY package*.json ./
RUN npm ci --only=production

FROM node:18-alpine as runtime
WORKDIR /app

# 复制node_modules和编译后的文件
COPY --from=builder /build/node_modules ./node_modules
COPY --chown=node:node . .

# 使用非root用户
USER node

EXPOSE 3000
ENV NODE_ENV=production

CMD ["node", "src/index.js"]

🐹 Go 应用

1
2
3
4
5
6
7
8
9
10
11
12
# 构建阶段
FROM golang:1.19 as builder
WORKDIR /build
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o app .

# 运行阶段
FROM scratch
COPY --from=builder /build/app /app
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
CMD ["/app"]

🚀 构建与优化

⚡ 构建命令

1
2
3
4
5
6
7
8
9
10
11
# 基本构建
docker build -t my-app:1.0 .

# 指定Dockerfile路径
docker build -f Dockerfile.prod -t my-app:prod .

# 构建参数
docker build --build-arg VERSION=1.0.0 -t my-app .

# 多平台构建
docker buildx build --platform linux/amd64,linux/arm64 -t my-app:multi .

🎯 构建参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 在Dockerfile中定义
ARG VERSION=latest
ARG BUILD_NUMBER

# 使用构建参数
LABEL version=$VERSION
ENV BUILD_NUMBER=$BUILD_NUMBER

# 条件构建
RUN if [ "$VERSION" = "dev" ] ; then \
npm install; \
else \
npm ci --only=production; \
fi

📊 镜像分析

1
2
3
4
5
6
7
8
9
# 查看镜像层次
docker history my-app:latest

# 查看镜像大小
docker images my-app

# 导出镜像分析
docker save my-app:latest | docker run -i --rm \
wagoodman/dive:latest

🐛 调试技巧

🔍 调试Dockerfile

1
2
3
4
5
6
7
8
# 临时添加调试工具
RUN if [ "$DEBUG" = "true" ] ; then \
apt-get update && \
apt-get install -y curl vim; \
fi

# 使用构建参数控制调试
ARG DEBUG=false

📝 调试命令

1
2
3
4
5
6
7
8
9
10
11
# 在构建失败时进入中间容器
docker build --target builder -t debug .

# 运行调试容器
docker run -it --rm --entrypoint sh debug

# 检查文件系统
docker run -it --rm my-app ls -la /app

# 查看环境变量
docker run -it --rm my-app env

🐳 Docker BuildKit 特性

1
2
3
4
5
6
7
8
9
# 启用BuildKit
DOCKER_BUILDKIT=1 docker build .

# 输出构建日志
docker build --progress=plain .

# 缓存管理
docker build --no-cache .
docker build --cache-from=my-app:previous .

💡 专业提示: 定期更新基础镜像以获取安全补丁,使用多阶段构建来减小镜像大小,并且始终扫描镜像中的漏洞。记住,一个好的Dockerfile就像是应用程序的文档,它应该清晰、简洁且易于维护。

Happy Dockerizing! 🎉 祝您构建顺利!