
Dockerfile 常用指令是写出第一个可运行镜像必须掌握的最小集合:FROM 指定基础镜像,RUN 装依赖,COPY 放代码,CMD 定启动命令,EXPOSE 声明端口。本文基于 Docker 24 与 26 验证,把这 5 个指令逐一拆开讲,并给出一个能直接拿来用的完整示例。看完你不但知道每条指令怎么写,还明白它们为什么这样排,下次写镜像不再照抄网上的神秘配置。今天这篇文章,编程狮就把这块讲透。无论你是刚装好 Docker 想打出第一个镜像,还是被网上互相矛盾的 Dockerfile 配置搞晕,这篇都能让你按图索骥、照着写就能跑通。
先看结论
| 指令 | 作用 | 出现位置 |
|---|---|---|
| FROM | 指定基础镜像,必须是第一条 | 文件开头 |
| RUN | 构建时执行命令,装环境 | 中间 |
| COPY | 把本地文件复制进镜像 | 中间 |
| CMD | 容器启动时默认执行的命令 | 结尾 |
| EXPOSE | 声明容器监听的端口 | 结尾 |
一句话:FROM 打地基,RUN 装环境,COPY 放代码,CMD 定入口,EXPOSE 只做声明不真正端口映射。
一、先弄清楚:Dockerfile 到底是什么
Dockerfile 是一个纯文本构建脚本,每一行是一条指令,Docker 按顺序执行后产出一层镜像。把它想象成做菜的菜谱:FROM 是「用什么锅」,RUN 是「开火炒哪一步」,CMD 是「最后端上桌怎么吃」。
1.1 镜像是一层一层叠出来的
每条会改动文件系统的指令(FROM、RUN、COPY)都会生成一个只读层,最终叠成完整镜像。层数越多体积越大,所以要把变动少的指令放前面,利用构建缓存。
1.2 指令的执行顺序
Dockerfile 从上往下执行,前面层的产物后面层才能看到。先理解整体流程,再看单条指令会更清楚,建议配合 Docker 教程 的镜像章节一起读。
二、FROM 与 RUN:打地基与装环境
在 Dockerfile 常用指令中,FROM 是打地基的那一步。Dockerfile FROM 指令必须是文件第一条,它决定了你的镜像站在谁的肩膀上。优先选带版本号的小体积镜像,比如 node:20-alpine。
# 以 Node 20 的 Alpine 版本为基础
FROM node:20-alpine
镜像构建阶段 RUN 指令执行命令,这是 Dockerfile 常用指令里最常被误用的地方,常见用途是装系统包或项目依赖。多条 RUN 会各自成层,所以相关的安装最好合并到一条里:
# 合并安装,减少层数也更可读
RUN apk add --no-cache python3 make g++ \
&& npm install -g typescript

三、COPY 与 CMD:放代码与定入口
COPY 指令把宿主机构建上下文里的文件复制进镜像。注意它只复制,不做解压,路径相对于构建上下文。
# 把当前目录的应用代码复制进镜像的 /app
COPY . /app
WORKDIR /app
CMD 指令定义容器启动时默认跑什么,一个 Dockerfile 只能有一个生效的 CMD。它可以被 docker run 后面的参数覆盖,所以适合放「默认行为」:
# 容器启动后默认执行 node 服务
CMD ["node", "server.js"]
这两条的区别容易混:COPY 指令发生在构建阶段,把文件搬进镜像;CMD 指令在运行阶段才生效。更多写法示例见 use_docker 教程。
四、EXPOSE 与完整 Dockerfile 示例
EXPOSE 只做「声明」,告诉读镜像的人这个容器打算监听哪个端口,并不会自动做端口映射,真正映射要靠 docker run -p。
# 声明服务监听 3000 端口
EXPOSE 3000
把前面几条拼起来,就是一个能直接构建的 Node 服务镜像:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
构建并运行:docker build -t mynode . 然后 docker run -p 3000:3000 mynode。常用指令速查可以翻 Docker 速查手册。
4.1 三个最容易踩的坑
| 现象 | 原因 | 修复 |
|---|---|---|
| 构建报 no such file or directory | COPY 的源路径不在构建上下文 | 在镜像目录外执行 build,或调整 .dockerignore |
| 镜像体积过大 | 把 node_modules 全打进去且未清理 | 用多阶段构建,只复制产物层 |
| 端口外部访问不通 | 只写了 EXPOSE 没加 -p 映射 | 运行时加 -p 宿主机:容器 参数 |

动手验证清单
照着下面做一遍,确认你真的能独立产出并运行镜像,而不是只看不练(示例基于 Docker 26,未在本机执行,请按实际版本核对输出):
- 前置安装:先确认 Docker 已安装并能启动守护进程,执行
docker version能看到客户端与服务端版本号;版本不一致时构建缓存的命中规则可能不同,这是常被人忽略的边界,先把环境对齐再动手。 - 运行构建:在放好 Dockerfile 的目录执行
docker build -t mynode .,预期看到每一步 SUCCESS 并最终生成镜像 id;顺手用docker images确认镜像体积,性能上把变动少的指令(FROM、依赖安装)放前面,能显著缩短二次构建时间。 - 配置与启动:用
docker run -p 3000:3000 mynode把服务跑起来,检查容器状态为 Up,再用浏览器或 curl 访问 3000 端口应返回页面内容;若返回空页面或报错,先docker logs mynode看启动日志定位。 - 验证镜像分层:用
docker history mynode查看每一层的来源与大小,对比 COPY 与 RUN 各自产生的层,理解「变动少在前」的缓存命中边界——改了代码层不会让依赖层重装,这是控制体积的关键。 - 失败处理与排错:若构建报 no such file or directory,多半是 COPY 的源不在构建上下文,检查 .dockerignore 或执行目录;若端口外部访问不通,确认加了
-p映射而非只写 EXPOSE;若镜像体积过大,改用多阶段构建只复制产物层。适用场景上,本地联调可用 bind mount 挂代码热更新,交付生产则用纯镜像,两者不要混用,否则本地能跑线上却缺文件,是新手部署翻车的高发区。
总结
掌握 Dockerfile 常用指令,关键是理解每条指令发生在构建还是运行阶段。FROM 打地基、RUN 装环境、COPY 放代码、CMD 定入口、EXPOSE 只声明端口。把它们按「变动机率低在前」的顺序排,既能用上构建缓存,也更容易排查问题。
要点带走:
- FROM 必须第一行,选带版本的小镜像更稳更安全;
- RUN 合并同类安装,减少层数控制体积;
- CMD 可被运行参数覆盖,适合放默认启动行为。
下一步可以把这个示例改成你自己的项目镜像,再学多阶段构建进一步瘦身。
延伸学习
这块知识系统补齐,按这个顺序来:
- 想边学边练,Docker 配套课程 是图文微课形式;
- 写好镜像后常要部署,Spring Boot 部署 Docker 给了真实项目示例;
- 服务器上调试容器可参考 SSH 连接 Docker。
常见问题
Q:RUN 和 CMD 到底有什么区别?
A:RUN 在镜像构建阶段执行,结果固化进镜像层;CMD 在容器运行时才执行,且能被 docker run 后的命令覆盖。一个负责「造镜像」,一个负责「跑容器」。
Q:EXPOSE 写了为什么还是访问不了?
A:EXPOSE 只是声明,不会自动做端口映射。必须在 docker run 时加 -p 宿主机端口:容器端口 才能从外部访问。
Q:一个 Dockerfile 能写多个 CMD 吗?
A:只能有一个生效,后面的会覆盖前面的。需要多命令请用 shell 脚本包裹,或用 ENTRYPOINT 配合 CMD 传参。

TRAE-AI编程



