Dockerfile(四)

4.Dockerfile

Dockerfile 是用于构建 Docker 镜像的脚本文件,里面包含一组指令,用来定义如何生成镜像。

Docker 构建镜像时,会将 Dockerfile 中的每条指令生成一个镜像层,最终组合成完整镜像。分层结构使镜像更易复用、缓存更高效。

在实际开发中,官方镜像通常只提供基础环境,而应用依赖、配置和代码需要通过 Dockerfile 自定义构建。

Dockerfile 流程图

一、简单使用

示例:基于官方 nginx 镜像自定义网页。

  1. 创建目录并新建 Dockerfile:
myweb/
└─ Dockerfile
  1. Dockerfile 内容:
FROM nginx:latest
RUN echo '<h1>My Custom Nginx Page</h1>' > /usr/share/nginx/html/index.html
EXPOSE 80

说明:

  • FROM nginx:latest:选择基础镜像
  • RUN:写入自定义网页
  • EXPOSE 80:声明端口
  1. 构建镜像:
docker build -t my-web .
  1. 查看镜像:
docker images
  1. 启动容器并访问:
docker run -d -p 80:80 my-web

访问浏览器 http://localhost 即可看到自定义网页。

二、常用指令

常用指令速查表

指令 简要说明
FROM 指定基础镜像(必须第一行)
LABEL 添加元数据(键值对)
RUN 构建时执行的命令
CMD 容器启动默认命令(可被覆盖)
ENTRYPOINT 容器启动主命令(不可被覆盖)
SHELL 修改默认 Shell
EXPOSE 声明监听端口
ENV 设置环境变量(持久化)
COPY 复制文件/目录到镜像
ADD 增强版 COPY(支持解压、URL)
WORKDIR 切换工作目录
VOLUME 创建挂载点/匿名卷
USER 切换执行用户
ARG 构建时变量(构建阶段有效)
ONBUILD 触发器(子镜像构建时执行)
STOPSIGNAL 设置停止容器时的系统信号
HEALTHCHECK 定义容器健康检查命令

1. FROM

  • 作用:指定基础镜像,必须是 Dockerfile 第一条指令。

  • 格式FROM 镜像[:标签] [AS 阶段名]

  • 示例

    FROM nginx:1.23
    FROM python:3.9-alpine AS builder
  • 注意:可使用多个 FROM 实现多阶段构建,最终只保留最后一个阶段。

2. LABEL

  • 作用:添加元数据(如版本、维护者)。

  • 格式LABEL 键=值

  • 示例

    LABEL version="1.0.1"
    LABEL maintainer="admin@example.com"

3. RUN

  • 作用:构建时执行命令,每条 RUN 生成一个新层。

  • 格式

    • Shell 格式(推荐):RUN <命令>
    • Exec 格式:RUN ["可执行文件", "参数1", "参数2"]
  • 示例

    RUN apt-get update && apt-get install -y git
    RUN ["yum", "-y", "install", "wget"]
  • 最佳实践:多个命令用 && 合并,减少镜像层数。

4. CMD

  • 作用:容器启动时的默认命令(可被 docker run 后的命令覆盖)。

  • 格式

    • Exec 格式(推荐):CMD ["可执行文件", "参数1"]
    • Shell 格式:CMD 命令 参数1
    • 作为 ENTRYPOINT 参数:CMD ["参数1", "参数2"]
  • 示例

    # Shell 格式示例: 运行 Python 脚本
    CMD python app.py
    
    # Exec 格式示例: 运行 Nginx
    CMD ["nginx", "-g", "daemon off;"]
    
    # 作为 ENTRYPOINT 参数
    CMD ["--port=8080"]
  • 注意:一个 Dockerfile 只能有一个有效 CMD。

5. ENTRYPOINT

  • 作用:容器启动主命令,不会被 docker run 后面的命令覆盖(但可追加参数)。

  • 格式

    • Shell 格式:ENTRYPOINT 命令 参数
    • Exec 格式ENTRYPOINT ["可执行文件", "参数"]
  • 示例

    # Shell 格式示例: 运行 Python 脚本
    ENTRYPOINT python app.py					
    
    # Exec 格式示例: 运行 Nginx
    ENTRYPOINT ["nginx", "-g", "daemon off;"]	
  • 与 CMD 搭配:ENTRYPOINT 定义固定命令,CMD 提供默认参数。

6. SHELL

  • 作用:覆盖默认 Shell(Linux 默认 /bin/sh -c​,Windows 默认 cmd)。

  • 格式SHELL ["可执行文件", "参数"]

  • 示例

    # 切换为 PowerShell
    SHELL ["powershell", "-command"]
    # 切换回默认 shell
    SHELL ["/bin/sh", "-c"]

7. EXPOSE

  • 作用:声明容器监听的端口(文档说明,不实际映射端口)。

  • 格式EXPOSE 端口号[/协议]

  • 示例

    # 声明单个端口
    EXPOSE 80
    # 声明多个端口
    EXPOSE 80 443
    # 指定协议
    EXPOSE 53/udp
  • 提示:运行时仍需用 -p 映射端口。

8. ENV

  • 作用:设置环境变量(构建和运行时均生效)。

  • 格式

    • 单变量:ENV 键 值
    • 多变量:ENV 键1=值1 键2=值2
  • 示例

    # 设置单个变量
    ENV NODE_VERSION=18.15.0
    # 设置多个变量
    ENV NODE_VERSION=18.15.0 NODE_ENV=production

9. COPY

  • 作用:将构建上下文中的文件/目录复制到镜像中(保留元数据)。

  • 格式COPY <源路径>... <目标路径>

  • 示例

    # 复制单个文件
    COPY requirements.txt /app/
    # 复制整个目录
    COPY src /app/src
    # 使用通配符复制多个文件
    COPY *.sh /scripts/
  • 注意:源路径必须是相对路径,不支持自动解压。

10. ADD

  • 作用:功能类似 COPY,额外支持:

    • 自动解压本地 .tar​、.gz 等压缩包
    • 从 URL 下载文件
  • 格式ADD <源路径>... <目标路径>

  • 示例

    # 添加本地文件
    ADD app.jar /opt/app/
    # 自动解压压缩包
    ADD project.tar.gz /app
    # 从 URL 下载文件
    ADD https://example.com/data.json /data
  • 建议:除非需要解压或下载,否则优先使用 COPY。

11. WORKDIR

  • 作用:设置工作目录(不存在则自动创建),后续指令基于此目录。

  • 格式WORKDIR <路径>

  • 示例

    WORKDIR /usr/src
    WORKDIR app   # 最终路径为 /usr/src/app

12. VOLUME

  • 作用:创建挂载点或匿名卷,用于数据持久化。

  • 格式VOLUME ["路径1", "路径2"]

  • 示例

    # 声明单个卷
    VOLUME /data
    # 声明多个卷
    VOLUME ["/data", "/config"]
  • 注意:构建阶段无法向 VOLUME 写入数据(运行时会被覆盖)。

13. USER

  • 作用:切换后续指令的执行用户(用户必须已存在)。

  • 格式USER 用户名[:用户组]

  • 示例

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

14. ARG

  • 作用:定义构建时的变量(仅构建阶段有效,可通过 docker build --build-arg <name>=<value> 覆盖)。

  • 格式ARG 变量名[=默认值]

  • 示例

    ARG NODE_VERSION=14
    FROM node:${NODE_VERSION}

15. ONBUILD

  • 作用:设置触发器,当当前镜像被用作其他镜像的基础时自动执行。

  • 格式ONBUILD <其他指令>

  • 示例

    ONBUILD COPY . /app
    ONBUILD RUN npm install

16. STOPSIGNAL

  • 作用:设置 docker stop 时发送给容器的系统信号。

  • 格式STOPSIGNAL <信号>

  • 示例

    STOPSIGNAL SIGQUIT

17. HEALTHCHECK

  • 作用:定义容器健康检查命令,Docker 定期执行。

  • 格式HEALTHCHECK [选项] CMD <命令>

  • 常用选项

    • --interval=<间隔>(默认 30s)
    • --timeout=<超时>(默认 30s)
    • --start-period=<启动宽限期>(默认 0s)
    • --retries=<重试次数>(默认 3)
  • 示例

    HEALTHCHECK --interval=30s --timeout=3s \
      CMD curl -f http://localhost/ || exit 1

使用建议

  1. 基础镜像:优先选择官方最小化镜像(如 alpine)以减小体积。

  2. 层数控制:将多个 RUN 命令合并为一个,避免产生过多镜像层。

  3. COPY vs ADD:优先使用 COPY,除非确实需要自动解压或下载。

  4. CMD vs ENTRYPOINT

    • 需要固定主程序 + 允许追加参数 → ENTRYPOINT​ + CMD
    • 允许完全覆盖启动命令 → 仅用 CMD
  5. 安全性:避免使用 root 用户运行容器,通过 USER 切换至非特权用户。

  6. 健康检查:为长期运行的服务配置 HEALTHCHECK,便于自动化运维。


三、实际使用

核心思路

每个 Dockerfile 都遵循相同的通用流程:

  1. 选择合适的基础镜像(尽量轻量)
  2. 设置工作目录
  3. 复制必要文件
  4. 安装依赖 / 构建应用
  5. 声明端口
  6. 定义启动命令

1.构建 Python Web 应用镜像

Dockerfile 示例:

FROM python:3.9-slim
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 5000
ENV FLASK_APP=app.py
ENV FLASK_ENV=production
CMD ["flask", "run", "--host=0.0.0.0"]

关键步骤说明:

步骤 指令 说明
基础镜像 FROM python:3.9-slim 使用官方 Python 轻量版
工作目录 WORKDIR /app 后续操作都在 /app
复制代码 COPY . . 将本地所有文件复制到容器 /app
安装依赖 RUN pip install --no-cache-dir -r requirements.txt 不保留缓存以减小镜像体积
端口声明 EXPOSE 5000 Flask 默认端口
环境变量 ENV FLASK_APP=app.py FLASK_ENV=production 指定应用入口及运行环境
启动命令 CMD ["flask", "run", "--host=0.0.0.0"] 监听所有地址

构建与运行:

# 构建镜像(注意最后的 . 表示当前目录为构建上下文)
docker build -t my-python-app .

# 运行容器(后台运行,映射宿主机 5000 端口)
docker run -d -p 5000:5000 my-python-app

2.构建 Node.js 应用镜像

Dockerfile 示例:

FROM node:16-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]

关键步骤说明:

步骤 指令 说明
基础镜像 FROM node:16-alpine 基于 Alpine 的 Node.js 轻量镜像
工作目录 WORKDIR /usr/src/app 标准 Node 应用目录
分层复制(优化缓存) 先复制 package*.json,再复制源码 利用 Docker 缓存,避免依赖每次重新安装
安装依赖 RUN npm install 安装所有依赖包
复制源码 COPY . . 复制剩余代码
构建应用 RUN npm run build 执行前端/后端构建脚本
端口声明 EXPOSE 3000 常见 Node 应用端口
启动命令 CMD ["npm", "start"] 运行生产启动脚本

构建与运行:

docker build -t my-node-app .
docker run -d -p 3000:3000 my-node-app

3.构建 Nginx 静态网站镜像

Dockerfile 示例:

FROM nginx:alpine
RUN rm -rf /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/
COPY dist/ /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

关键步骤说明:

步骤 指令 说明
基础镜像 FROM nginx:alpine 极轻量的 Nginx 镜像
清理默认配置 RUN rm -rf /etc/nginx/conf.d/default.conf 移除默认站点配置
复制自定义配置 COPY nginx.conf /etc/nginx/conf.d/ 放入自定义虚拟主机配置
复制静态文件 COPY dist/ /usr/share/nginx/html/ 将构建好的静态网站复制到 Nginx 默认目录
端口声明 EXPOSE 80 HTTP 标准端口
启动命令 CMD ["nginx", "-g", "daemon off;"] 前台运行 Nginx(容器必须前台进程)

配套 nginx.conf 示例:

server {
    listen 80;
    server_name localhost;

    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
}

构建与运行:

docker build -t my-static-site .
docker run -d -p 8080:80 my-static-site   # 宿主8080映射容器80

最佳实践要点

  • 基础镜像:优先选择 -alpine​、-slim 等轻量版本,减小最终镜像体积。
  • 缓存利用:Node.js 示例中先复制 package.json 再安装依赖,可避免代码变更导致依赖重装。
  • 前台进程:容器启动命令必须保持前台运行(如 Nginx 的 daemon off;),否则容器会立即退出。
  • 端口映射EXPOSE​ 仅为文档说明,真正映射端口需要在 docker run​ 时使用 -p
  • 构建上下文docker build​ 命令最后的 .​ 表示当前目录为构建上下文,Dockerfile 中的 COPY 只能访问上下文内的文件。