Dockerfile 指令详解
基本语法格式:
INSTRUCTION arguments(指令不区分大小写,但必须大写以示区分)
基石与元数据
FROM
必须是 Dockerfile 的第一条非注释指令
- 作用: 指定基础镜像(你的镜像基于什么系统或环境构建)。
- 语法:
- FROM
<image>(使用最新版) - FROM
<image>:<tag>(指定版本,推荐) - FROM
<image>AS<name>(给阶段起别名,用于多阶段构建)
- FROM
Dockerfile
FROM node:18-alpine AS builderLABEL
- 作用: 给镜像添加元数据(作者、版本、描述等)。以前用 MAINTAINER,现在废弃了,统一用 LABEL
- 语法: LABEL
<key>=<value><key>=<value>...
Dockerfile
LABEL version="1.0" description="这是一个Next.js应用" maintainer="yourname@example.com"文件与目录 (搬运工)
WORKDIR
- 作用: 设置工作目录。
- 细节:
- 相当于 Linux 的
cd。 - 如果目录不存在,Docker 会自动创建。
- 相当于 Linux 的
- 重要: 后续的
RUN、CMD、COPY指令都会在这个目录下执行。
Dockerfile
WORKDIR /appCOPY
- 作用: 把宿主机(你的电脑)的文件复制到镜像里。
- 语法: COPY --chown=
<user>:<group><源路径> <目标路径> - 细节: . 代表 WORKDIR 设置的当前目录。
Dockerfile
# 把当前目录所有文件拷到容器当前目录
COPY . .
# 拷贝时同时修改文件权限
COPY --chown=nextjs:nodejs package.json .ADD (高级版 COPY)
- 作用: 也是复制文件,但比 COPY 多两个功能:
- 如果源路径是一个 URL,它会自动下载。
- 如果源文件是
tar、gzip等压缩包,它会自动解压。
- 最佳实践: 官方建议尽量用 COPY,只有在需要自动解压时才用 ADD。
Dockerfile
# 会自动把 html.tar.gz 解压到 /var/www/html
ADD html.tar.gz /var/www/html变量与环境 (配置)
ENV
- 作用: 设置环境变量。
- 生命周期: 构建时有效,容器运行时也有效。
- 语法: ENV
<key>=<value>
Dockerfile
ENV NODE_ENV=production
ENV PORT 3000ARG
- 作用: 定义构建时需要的变量。
- 生命周期: 只在构建过程 (
docker build) 中有效,镜像构建好后就消失了。 - 语法: ARG
<name>=<default value>
Dockerfile
# Dockerfile
ARG VERSION=latest
FROM node:${VERSION}命令行传参: docker build --build-arg VERSION=16 .
执行命令 (核心逻辑)
这是最容易混淆的部分,请注意执行时机的区别。
RUN (构建时执行)
- 作用: 在生成镜像的过程中执行命令。通常用于安装软件、编译代码。
- 两种写法:
- Shell 格式:
RUN npm install(相当于在/bin/sh -c中运行) - Exec 格式(推荐):
RUN ["npm", "install"](类似于函数调用,更安全,但这要求严格的 JSON 格式,必须用双引号)
- Shell 格式:
Dockerfile
# 推荐用 && 连接命令以减少镜像层数
RUN apt-get update && apt-get install -y curlCMD (启动时默认命令)
- 作用: 指定容器启动时默认执行的命令。
- 特点: Dockerfile 中只能有一个
CMD(如果有多个,最后一个生效)。 - 可覆盖性: 如果你在命令行运行
docker run myimage echo hello,这里的echo hello会覆盖 Dockerfile 里的CMD。 - 语法:
CMD ["可执行文件", "参数1", "参数2"]
Dockerfile
CMD ["npm", "start"]ENTRYPOINT (入口点)
- 作用: 配置容器启动时的可执行程序。
- 特点: 很难被覆盖。它让容器看起来像一个二进制可执行程序。
- 黄金搭档: ENTRYPOINT + CMD 组合使用。ENTRYPOINT 固定命令,CMD 提供默认参数。
Dockerfile
# 这样写,容器就是 Nginx
ENTRYPOINT ["nginx"]
# 默认参数是 -g daemon off;
CMD ["-g", "daemon off;"]
# 效果:
# 运行 docker run my-nginx -> 执行 nginx -g daemon off;
# 运行 docker run my-nginx -t -> 执行 nginx -t (CMD 被替换了,ENTRYPOINT 还在)网络与存储
EXPOSE
- 作用: 声明容器打算使用的端口。
- 注意: 仅作为文档声明,不会自动开启端口映射(除非运行是用
-P随机端口)。 - 语法: EXPOSE
<port>
Dockerfile
EXPOSE 8080VOLUME
- 作用: 声明匿名数据卷。
- 目的: 告诉 Docker,这个目录里的数据很重要,不要保存在容器的文件系统层里,而应该映射到宿主机。
- 语法:
VOLUME ["/data"]
Dockerfile
VOLUME ["/var/lib/mysql"]安全与高级 (进阶)
USER
- 作用: 切换后续命令的执行用户。
- 场景: 默认是 root,为了安全,生产环境通常切换到普通用户。
Dockerfile
RUN groupadd -r app && useradd -r -g app app
USER app
CMD ["python", "app.py"]HEALTHCHECK (健康检查)
- 作用: 告诉 Docker 如何判断容器是不是“活着”且“健康”。
Dockerfile
# 每 5 分钟检查一次,如果访问 localhost 失败则认为不健康
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1ONBUILD (下游触发器)
- 作用: 当别的镜像以当前镜像为基础(FROM 你的镜像)时,才会执行的命令。
- 场景: 制作通用的语言框架镜像(如 Python-Flask 基础镜像)。
Dockerfile
ONBUILD COPY . /app
ONBUILD RUN pip install -r requirements.txt注意事项
构建时 vs 运行时
初学者最容易混淆的是 RUN 和 CMD 的区别。
| 指令 | 什么时候执行? | 作用 | 例子 |
|---|---|---|---|
| ARG | docker build | 传参 | 传入版本号 |
| RUN | docker build | 制作镜像 | npm install (把依赖装进镜像) |
| CMD | docker run | 启动容器 | npm start (让服务跑起来) |
| ENV | build & run | 设置环境 | 设置数据库密码 |