场景
在一个Dockerfile中,如何编写CMD指令,使得可以同时启动两个进程?
方案
这两个进程假设分别为Springboot Jar工程、sh脚本:
- app.jar
- script.sh
需要明确一点:
CMD指令本身只能直接执行一个命令
所以我们只能通过间接方式来做到启动多个进程:
使用启动脚本start.sh,在其中定义两个进程的启动逻辑,最后使用CMD启动该启动脚本即可。
start.sh
#!/bin/bash#1、启动script.sh,且用&使其在后台运行 /usr/local/script.sh 、启动SpringBoot Jar工程,作为前台进程 java -jar /usr/local/app.jar
Dockerfile
FROM openjdk:17-jdk-slim#COPY COPY start.sh /usr/local/ COPY script.sh /usr/local/ COPY app.jar /usr/local/#权限 RUN chmod +x /usr/local/start.sh \&& chmod +x /usr/local/script.shWORKDIR /usr/localCMD ["./start.sh"]
补充
1、为什么start.sh中,script.sh启动指令中一定要在末尾加一个&?
加&代表这是一个后台进程,脚本不会等待它执行完毕,而是直接执行下一行命令。这本质上是一种并发。
2、为什么jar工程不用加&,从而使两个工程、脚本都为后台运行状态?
Docker容器会在前台主进程退出时停止,因此Docker容器必须要有一个前台进程,若所有程序都在后台运行,容器会立即退出。
通常会将核心服务(如SpringBoot)作为前台进程,确保服务退出时容器能够正常感知并停止。
3、可否两个工程都为前台工程?
shell脚本中,无法同时让两个程序均以前台的方式运行,如果写成:
/path/to/script.sh java -jar /path/to/app.jar
那么运行结果就是“先执行sh,再执行jar”这样一种串行运行方式。
因此如果要同时运行多个进程,只能用“1前台+多后台”这种形式,所有的后台进程运行指令的末尾,加上&。
4、为什么jar工程不用chmod +x
核心原因在于JAR文件本身不是可执行程序,而是通过java -jar命令调用JVM来解析运行的字节码文件:
- 执行JAR文件的命令是java -jar app.jar,本质是让JVM读取并解析JAR文件中的内容,而不是直接执行JAR文件本身;
- 这里的app.jar只是一个被JVM读取的数据源,就像用cat命令读取文本文件那样,并不需要可执行属性。
什么文件才需要+x权限?
chmod +x用于赋予可被操作系统执行的文件的执行权限,这类文件通常有两种:
- 编译型程序:如C/C++编译后的二进制文件(可直接被CPU执行);
- 脚本文件:.sh文件(首行有#!/bin/bash,告诉系统用什么解释器执行)
app.jar不属于以上任何一种,因此不用+x权限,即使加了也没法通过./app.jar执行(会报错无法执行二进制文件),必须通过java -jar调用。
如果给jar文件加了+x会怎么样?
可以用chmod +x app.jar,但是没什么意义:既不会影响它的运行,也不会带来任何好处,反而会被误解为JAR文件是可以直接执行的。