07. Dockerfile指令详解
2025-02-17
简介
Dockerfile 是用于构建 Docker 镜像的文本文件,它包含了一系列的指令和参数。本文将详细介绍常用的 Dockerfile 指令,包括 FROM、RUN、COPY、ADD、CMD、ENTRYPOINT、ENV 等。
1. 文件操作指令
1.1 COPY 复制文件
格式:
COPY [--chown=<user>:<group>]<源路径>...<目标路径>COPY [--chown=<user>:<group>]["<源路径>",..."<目标路径>"]
COPY 指令将从构建上下文目录中的源路径复制文件/目录到镜像内的目标路径。支持两种格式:命令行格式和函数调用格式。
COPY package.json /usr/src/app/源路径特性:
- 支持多个源路径
- 支持通配符(遵循 Go 的 filepath.Match 规则)
COPY hom* /mydir/
COPY hom?.txt /mydir/目标路径说明:
- 支持绝对路径和相对路径(相对于 WORKDIR)
- 目录会自动创建
- 保留源文件的元数据(权限、时间戳等)
权限设置: 可以使用 --chown 选项设置文件的所属用户和组:
COPY --chown=55:mygroup files* /mydir/
COPY --chown=bin files* /mydir/
COPY --choen=1 files* /mydir/
COPY --chown=10:11 files* /mydir/1.2 ADD 高级复制文件
ADD 指令是 COPY 的增强版本,提供了更多功能:
URL 支持:
- 支持从 URL 下载文件
- 下载文件权限默认为 600
- 不推荐使用此功能,建议使用 RUN + wget/curl
自动解压:
- 支持 tar、gzip、bzip2、xz 格式
- 自动解压到目标路径
在某些情况下,这个自动解压缩的功能非常有用,比如官方镜像 ubuntu 中:
FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /注意: 如果只想复制压缩文件而不解压,应使用
COPY指令
最佳实践:
- 优先使用
COPY(功能单一,行为明确) - 仅在需要自动解压缩时使用
ADD
警告:
ADD指令会使构建缓存失效,可能降低构建速度
权限设置: 同样支持 --chown 选项:
ADD --chown=55:mygroup files* /mydir/
ADD --chown=bin files* /mydir/
ADD --chown=1 files* /mydir/
ADD --chown=10:11 files* /mydir/2. 容器运行指令
2.1 CMD 容器启动命令
格式:
- shell 格式:
CMD <命令> - exec 格式:
CMD ["可执行文件", "参数1", "参数2"]
作用:
- 指定容器启动时的默认命令
- 可以被 docker run 命令行参数覆盖
- 每个 Dockerfile 只能有一个 CMD
使用示例:
# 默认命令
CMD ["nginx", "-g", "daemon off;"]
# 带参数的 ENTRYPOINT
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]最佳实践:
- 使用 exec 格式 (["command", "param1", "param2"])
- 避免使用 shell 格式 (command param1 param2)
- 确保应用程序在前台运行
注意: Docker 容器中的应用应该以前台方式运行,而不是作为后台服务
2.2 ENTRYPOINT 入口点
格式:
- exec 格式:
ENTRYPOINT ["可执行文件", "参数1", "参数2"] - shell 格式:
ENTRYPOINT command param1 param2
作用:
- 配置容器启动时运行的命令
- 不会被 docker run 的命令行参数覆盖
- 可以接收 CMD 指令或运行参数
使用场景:
- 需要固定的启动命令
- 需要处理命令行参数
- 作为可执行程序使用
示例:
# 固定的入口点
ENTRYPOINT ["nginx"]
# 可以在运行时添加参数
docker run myimage -g "daemon off;"2.3 ENV 设置环境变量
格式:
ENV <key> <value>ENV <key1>=<value1> <key2>=<value2>...
作用:
- 设置环境变量
- 可被后续指令使用
- 在容器运行时仍然有效
示例:
ENV VERSION=1.0 DEBUG=on \
NAME="Happy Feet"支持的指令: ADD、COPY、ENV、EXPOSE、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD
最佳实践:
- 使用环境变量增加构建灵活性
- 一个 Dockerfile 可通过不同环境变量构建不同镜像
2.4 VOLUME 定义匿名卷
格式:
VOLUME ["<路径1>", "<路径2>"]VOLUME <路径>
作用:
- 声明容器数据持久化目录
- 避免向容器存储层写入数据
- 运行时可被显式挂载覆盖
示例:
# 声明匿名卷
VOLUME /data
# 运行时覆盖匿名卷
docker run -d -v mydata:/data image_name2.5 EXPOSE 声明端口
格式:
EXPOSE <端口1> [<端口2>...]
作用:
- 声明容器对外提供的服务端口
- 帮助镜像使用者理解端口用途
- 配合 docker run -P 实现随机端口映射
注意: EXPOSE 仅作为文档说明使用,不会自动开启端口,需要 -p 参数映射端口
2.6 WORKDIR 指定工作目录
格式:
WORKDIR <工作目录路径>
作用:
- 设置工作目录
- 影响后续指令的工作路径
- 不存在的目录会被自动创建
最佳实践:
- 使用绝对路径
- 避免使用 RUN cd 命令
- 每个 RUN 指令都在独立的容器中执行
2.7 USER指定当前用户
格式:
USER <用户名>[:<用户组>]
作用:
- 指定后续命令的执行用户
- 影响 RUN、CMD 和 ENTRYPOINT 指令
- 用户必须预先创建
示例:
RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN ["redis-server"]最佳实践:
- 避免使用 root 用户运行应用
- 使用 gosu 代替 su/sudo 切换用户
- 在构建阶段创建所需用户
使用 gosu 示例:
# 建立redis用户,并使用gosu换另一个用户执行命令
RUN groupadd -r redis && useradd -r -g redis redis
# 下载gosu
RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" \
&& chmod +X /usr/local/bin/gosu \
$$ gosu nobody true
# 设置CMD,并以另外的用户执行
CMD ["exec","gosu","redis","redis-server"]2.8 HEALTHCHECK 健康检查
格式:
HEALTHCHECK [选项] CMD <命令>: 设置检查容器健康状态的命令HEALTHCHECK NONE: 禁用基础镜像中的健康检查指令
作用:
- 定期检查容器服务状态
- 发现服务异常(如死锁、死循环)
- 支持容器自动调度和故障转移
状态变化:
starting: 初始状态healthy: 检查成功unhealthy: 连续检查失败
支持的选项:
- --interval=<间隔> : 两次健康检查的间隔,默认为30秒
- --timeout=<时长> : 康检查命令运行超时时间,如果超过这个时间,本次健康检查被视为失败,默认30秒
- --retries=<次数> : 当连续时报指定次数后,则将容器状态视为unhealthy,默认3次
返回值:
0: 检查成功1: 检查失败2: 保留值,不要使用
示例:检查 Web 服务
# Dockerfile
FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s \
CMD curl -fs http://localhost/ || exit 1
# 说明:这里我们设置了每 5 秒检查一次(这里为了试验所以间隔非常短,实际应该相对较长),如果健康检查命令超过 3 秒没响应就视为失败,并且使用 curl -fs http://localhost/ || exit 1 作为健康检查命令运行示例:
docker build -t myweb:v1 . #构建镜像
docker run -d --name web -p 80:80 myweb:v1 #启动容器
docker container ls #查看容器状态查看健康状态:
docker inspect --format '{{json .State.Health}}' web | python -m json.tool