使用 Dockerfile 构建镜像

Dockerfile 构建镜像

学习如何使用Dockerfile定义镜像内容,构建高效、安全的Docker镜像。

Dockerfile 镜像构建 多阶段构建 最佳实践

什么是 Dockerfile?

Dockerfile 是一个文本文件,包含了一系列的指令,用于自动化构建Docker镜像。每个指令在镜像中创建一个新的层。

通过Dockerfile,您可以:

  • 定义基础镜像
  • 安装软件包
  • 复制文件到镜像中
  • 设置环境变量
  • 配置容器启动命令
Dockerfile 工作流程
  1. 编写Dockerfile文件
  2. 使用 docker build 命令构建镜像
  3. Docker引擎按顺序执行Dockerfile中的指令
  4. 每个指令创建一个新的镜像层
  5. 最终生成可用的Docker镜像

Dockerfile 指令详解

指令 描述 示例
FROM 指定基础镜像,必须是Dockerfile的第一条指令 FROM ubuntu:20.04
RUN 在镜像构建过程中执行命令 RUN apt-get update && apt-get install -y nginx
COPY 从构建上下文复制文件到镜像中 COPY . /app
ADD 类似COPY,但支持URL和自动解压 ADD https://example.com/file.tar.gz /tmp/
WORKDIR 设置工作目录 WORKDIR /app
ENV 设置环境变量 ENV NODE_ENV production
EXPOSE 声明容器运行时监听的端口 EXPOSE 80
CMD 指定容器启动时执行的命令 CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT 配置容器启动时运行的命令 ENTRYPOINT ["/app/start.sh"]
VOLUME 创建挂载点 VOLUME /data
USER 指定运行后续指令的用户 USER nobody
LABEL 为镜像添加元数据 LABEL version="1.0"
ARG 定义构建时的变量 ARG APP_VERSION=1.0

完整的 Dockerfile 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 使用官方Python运行时作为基础镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 复制requirements文件 COPY requirements.txt . # 安装Python依赖 RUN pip install --no-cache-dir -r requirements.txt # 复制应用程序代码 COPY . . # 创建非root用户 RUN useradd -m -r appuser && chown -R appuser /app USER appuser # 暴露端口 EXPOSE 8000 # 定义环境变量 ENV PYTHONUNBUFFERED=1 # 运行应用程序 CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
Dockerfile 指令解析
  • FROM: 基于Python 3.9的精简版镜像开始构建
  • WORKDIR: 设置容器内的工作目录为/app
  • COPY: 将本地的requirements.txt文件复制到镜像中
  • RUN: 安装Python依赖,使用--no-cache-dir减少镜像大小
  • USER: 创建并使用非root用户运行应用,提高安全性
  • EXPOSE: 声明容器监听8000端口
  • ENV: 设置环境变量,确保Python输出不被缓冲
  • CMD: 容器启动时运行的命令

构建过程详解

1
准备构建上下文

Docker客户端将Dockerfile所在目录的所有文件发送给Docker守护进程

2
解析Dockerfile

Docker引擎按顺序读取并解析Dockerfile中的指令

3
执行指令

每个指令创建一个新的镜像层,层是只读的

4
生成最终镜像

所有指令执行完毕后,生成最终的Docker镜像

5
标记镜像

为生成的镜像打上标签,方便识别和管理

构建镜像命令

基本构建命令
# 在当前目录构建镜像
docker build -t my-app:1.0 .
# 指定Dockerfile路径
docker build -t my-app:1.0 -f /path/to/Dockerfile .
# 构建时不使用缓存
docker build --no-cache -t my-app:1.0 .
# 查看构建历史
docker history my-app:1.0
使用构建参数
# Dockerfile中定义构建参数
ARG APP_VERSION=1.0
ENV APP_VERSION=$APP_VERSION
# 构建时传递参数
docker build --build-arg APP_VERSION=2.0 -t my-app:2.0 .

多阶段构建

多阶段构建允许在单个Dockerfile中使用多个FROM指令,每个FROM指令开始一个新的构建阶段。这样可以:

  • 显著减小最终镜像的大小
  • 分离构建环境和运行环境
  • 提高安全性
多阶段构建示例
# 构建阶段
FROM golang:1.19 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
# 运行阶段
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
优化提示

在这个例子中,构建阶段使用完整的Golang镜像来编译应用,运行阶段使用极小的Alpine镜像,最终镜像只包含编译好的二进制文件和必要的证书,大小显著减小。

Dockerfile 最佳实践

使用 .dockerignore 文件

创建.dockerignore文件排除不必要的文件,减小构建上下文大小和最终镜像大小。

# .dockerignore 文件示例
node_modules
npm-debug.log
.git
.dockerignore
Dockerfile
README.md
多行命令排序

将多行命令按字母顺序排序,提高可读性和维护性。

RUN apt-get update && apt-get install -y \
curl \
git \
vim \
wget
使用特定标签的基础镜像

避免使用latest标签,选择特定的版本标签确保构建的一致性。

# 推荐
FROM node:18.16.0-alpine
# 不推荐
FROM node:latest
最小化层数

合并多个RUN指令,减少镜像层数。

# 推荐 - 合并RUN指令
RUN apt-get update && \
apt-get install -y package1 package2 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 不推荐 - 多个RUN指令
RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2
使用非root用户

创建并使用非root用户运行应用程序,提高安全性。

RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser

常见问题与解决方案

问题: 修改了源代码但构建时仍然使用缓存中的旧文件。

解决方案:

  • 使用 --no-cache 选项重新构建
  • 调整指令顺序,将经常变化的指令放在Dockerfile后面
  • 使用 docker system prune 清理缓存

问题: 构建的镜像体积过大,影响部署和传输效率。

解决方案:

  • 使用多阶段构建
  • 选择精简的基础镜像(Alpine、Slim版本)
  • 清理包管理器的缓存文件
  • 使用.dockerignore文件排除不必要的文件

问题: 每次构建都需要下载依赖包,耗时较长。

解决方案:

  • 合理利用Docker构建缓存
  • 使用国内镜像源加速下载
  • 分离依赖安装和代码复制步骤
  • 考虑使用构建缓存服务
构建成功!

恭喜!您已经掌握了使用Dockerfile构建镜像的核心知识。现在可以开始创建高效、安全的Docker镜像了。