CMD 容器启动命令

原文:https://yeasy.gitbooks.io/docker_practice/image/dockerfile/cmd.html

 

CMD 指令的格式和 RUN 相似,也是两种格式:

  • shell 格式:CMD <命令>
  • exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
  • 参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。

之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。

在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,ubuntu 镜像默认的 CMD 是 /bin/bash,如果我们直接 docker run -it ubuntu 的话,会直接进入 bash。我们也可以在运行时指定运行别的命令,如 docker run -it ubuntu cat /etc/os-release。这就是用 cat /etc/os-release 命令替换了默认的 /bin/bash 命令了,输出了系统版本信息。

在指令格式上,一般推荐使用 exec 格式,这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号 ",而不要使用单引号。

如果使用 shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式进行执行。比如:

CMD echo $HOME

在实际执行中,会将其变更为:

CMD [ "sh", "-c", "echo $HOME" ]

这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。

提到 CMD 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。

Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。

一些初学者将 CMD 写为:

CMD service nginx start

然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。

对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。

而使用 service nginx start 命令,则是希望 upstart 来以后台守护进程形式启动 nginx 服务。而刚才说了 CMD service nginx start 会被理解为 CMD [ "sh", "-c", "service nginx start"],因此主进程实际上是 sh。那么当 service nginx start 命令结束后,sh 也就结束了,sh 作为主进程退出了,自然就会令容器退出。

正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:

CMD ["nginx", "-g", "daemon off;"]
<think> 嗯,用户这次的问题是明确想修改Docker容器启动命令。结合之前的系统级指令和用户提供的站内引用,需要给出专业且可操作的方案。 用户引用的两篇资料很有价值:第一篇[^1]展示了用docker update修改容器自启配置,第二篇[^2]则通过runlike工具完整还原了启动参数。这正好揭示了修改容器命令的两种主流路径——要么直接修改现有容器配置,要么重建新容器。 考虑到用户当前需求是"修改启动命令",需要区分核心场景:如果是修改守护参数(如--restart),用docker update最便捷;但如果要改动镜像入口命令或挂载点等复杂参数,就必须走重建流程。 在构建回答框架时,准备重点强调三点:第一,明确两种方法的适用边界;第二,给出可视化操作示例(尤其是容易出错的json序列部分);第三,提醒配置备份的重要性。最后用对比表格帮助用户决策。 注意到用户上次接触过runlike工具,这次可以深化这个知识点:不仅展示如何安装使用,还要解释其输出的每个参数区块含义。这样即使用户需要重建容器,也能精准复刻原有配置。 安全方面要特别提醒:修改运行中容器命令可能导致服务中断,务必在测试环境验证。另外json语法必须严格转义符号,这个坑很多新手会踩。 </think> 以下是修改 Docker 容器启动命令的详细方法,根据需求场景提供两种解决方案: --- ### 方法一:直接修改容器配置(适合简单参数调整) 1. **修改容器启动策略** 适用于添加`--restart`等守护参数(不影响主进程命令): ```bash docker update --restart=always <容器名/ID> # 设置容器随Docker服务自启 docker update --restart=no <容器名/ID> # 取消自启 ``` 2. **修改容器启动命令(需停止容器)** ```bash docker stop <容器名/ID> docker commit <容器名/ID> <新镜像名> # 将容器保存为新镜像 docker run -it --name <新容器名> <新镜像名> <新命令> # 用新命令启动 ``` > **示例**:将原启动命令`redis-server`改为`redis-server --appendonly yes` > ```bash > docker commit redis my_redis > docker run -d --name redis_new my_redis redis-server --appendonly yes > ``` --- ### 方法二:重建容器(推荐用于复杂修改) 1. **获取原容器启动命令** 安装工具还原完整参数(需先安装`pip`): ```bash pip install runlike runlike -p <容器名/ID> # 输出完整的docker run命令 ``` ![runlike输出示例](https://example.com/runlike-output.png) 2. **修改并重建容器** 复制`runlike`输出的命令 → 修改目标参数 → 执行新命令: ```bash # 示例:修改Redis容器添加配置文件 docker run \ --name=redis_new \ --hostname=my-redis \ -v /custom/redis.conf:/etc/redis/redis.conf \ # 修改挂载路径 ...其他参数... \ redis \ redis-server /etc/redis/redis.conf # 修改启动命令 ``` --- ### 关键场景对比表 | **场景** | 推荐方法 | 操作风险 | 是否需重建 | |------------------------|-------------|--------|-----------| | 调整自启策略(--restart) | `docker update` | 低 | ❌ | | 修改环境变量(-e) | `docker update` | 低 | ❌ | | 改变入口命令 | 重建容器 | 中 | ✅ | | 增减挂载卷(-v) | 重建容器 | 高 | ✅ | --- ### 注意事项 1. **配置持久化** 修改后务必检查容器数据卷绑定,避免配置丢失。重要数据应使用`-v`绑定到宿主机 2. **参数冲突处理** 若提示`--restart冲突`,需先停止容器:`docker stop <容器名> && docker update ...` 3. **批量修改建议** 使用`docker inspect`导出配置为JSON文件,编辑后通过`docker create`重建: ```bash docker inspect <容器名> > config.json # 修改config.json中的"Cmd"/"Entrypoint"字段 docker create --name <新容器名> $(jq -r '.Config.Image' config.json) \ $(jq -r '.Config.Cmd | join(" ")' config.json) ``` > **提示**:生产环境建议先在测试容器验证命令,再操作正式容器[^1][^2]。 --- **相关问题** 1. 如何在不重建容器的情况下修改Docker容器的环境变量? 2. Docker容器启动命令与Dockerfile中的CMD/ENTRYPOINT有何区别? 3. 如何永久保存对容器配置的修改?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值