Dockerfile 完全指南 🐳
🚀 掌握Docker镜像构建的艺术,打造高效、安全的容器化应用
📋 目录
- 🎯 Dockerfile 简介
- 📝 指令详解
- 🏗️ 多阶段构建
- ✅ 最佳实践
- 🔒 安全指南
- ⚡ 实战示例
- 🚀 构建与优化
- 🐛 调试技巧
🎯 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! 🎉 祝您构建顺利!