cmd指令定义容器启动时默认命令,仅在docker run时生效且最后一个有效;三种写法:exec模式(推荐,主进程为程序本身,信号可接收)、为entrypoint提供参数模式(需配合exec格式entrypoint)、shell模式(经/bin/sh解析,支持环境变量但pid1为shell)。

CMD 是 Dockerfile 中定义容器启动时默认执行命令的指令,它不参与镜像构建过程,只在 docker run 时生效。写法必须放在 Dockerfile 末尾(或至少在 FROM、RUN 等构建指令之后),且一个文件中只应有一个 CMD(后出现的会覆盖前面的)。
CMD 的三种写法及适用场景
CMD 支持三种格式,推荐使用 exec 格式(即 JSON 数组形式),因为它更明确、避免 shell 解析问题,且能正确传递信号(如 SIGTERM)给主进程:
-
exec 格式(推荐):
CMD ["nginx", "-g", "daemon off;"]—— 直接执行二进制,无 shell 封装,适合长期运行服务 -
shell 格式:
CMD nginx -g "daemon off;"—— 实际被包装成/bin/sh -c "...",适合简单命令,但主进程是 sh,可能收不到终止信号 -
作为 ENTRYPOINT 的默认参数:
ENTRYPOINT ["python", "app.py"]+CMD ["--host=0.0.0.0:8000"]—— 此时 CMD 提供参数,ENTRYPOINT 定义可执行程序
常见错误和注意事项
CMD 不是构建时运行的命令,所以不能用来安装软件或复制文件(那些该用 RUN)。容易混淆的点包括:
在 Linux 上通过 Docker 运行 OpenClaw,并使用 Tailscale 实现远程访问。⚠️ 涉及 sudo、Docker、Tailscale和凭证挂载——请先查阅安全章节...
- 把启动服务写成
CMD service nginx start—— 这在大多数基础镜像里会立即退出,因为 service 命令后台启动后就返回了;应直接前台运行主进程 - 多个 CMD 指令导致只有最后一个生效,比如误写成:
CMD npm install和CMD npm start,前者完全无效 - 路径或权限问题:CMD 中指定的可执行文件必须存在于镜像内、有执行权限,且路径正确(建议用绝对路径)
- 环境变量不会自动展开:写成
CMD echo $HOME不会输出实际值,要用CMD ["/bin/sh", "-c", "echo $HOME"]
典型应用示例
以 Node.js 应用为例,Dockerfile 片段如下:
FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 3000 CMD ["npm", "start"]
这里 npm start 必须在 package.json 的 scripts 中定义为前台命令(如 "start": "node server.js"),否则容器会启动即退出。
如何验证 CMD 是否生效
构建镜像后,可用以下命令检查默认命令:
-
docker inspect <image-name> | jq '.[0].Config.Cmd'</image-name>—— 查看镜像元数据中的 CMD 值 -
docker run --rm -it <image-name></image-name>—— 直接运行,观察是否按预期启动 -
docker run --rm -it --entrypoint /bin/sh <image-name></image-name>—— 覆盖 CMD 进入交互 shell,用于调试










