# 一行代码的变更让我陷入无尽加班,Dockerfile的ENTRYPOINT的两种格式
# 1 前言
前几天因为同事改了一行代码,硬是搞了一整天才定位出问题。改的是Dockerfile
的ENTRYPOINT
,一起来看看怎么回事。
# 2 问题
通过安装在Kubernetes
的Spring Cloud Data Flow
跑Spring Cloud Task
,发现怎么都无法传参进去,于是开始了漫长的探索历程。
有问题,第一反应当然是看日志,发现日志一直都是读取
jar
里面的application.properties
,传入的参数没有接收到,没有覆盖原来的配置,导致数据库连接错误。可能是日志信息不够,于是想办法打开
debug
或trace
日志级别。通过传参方式无法改变日志级别,所以修改代码,重新打包。依然无法查找到有用信息,还是无法传参。
# 3 将问题分解
目前流程是scdf (Data Flow)
传参给Kubernetes
,Kubernetes
传参给Pod
,Pod
传给Docker容器
。查看Pod
的信息Arguments
发现已经有传参了,所以问题就在于,为何Docker
到Springboot
应用之间没有传递成功。(当然早已经确保java -jar
运行应用可以传参)。
通过这样分析,问题就明朗起来了,就是在Docker
这层传参失败。(当然这是知道了结果才这么快得出结论,实际过程比较曲折)
于是研究Docker
在打包镜像时发生了什么事情。原来,是由于Dockerfile
的ENTRYPOINT
被人修改了。(其实直接查看代码变更也是一种分析方法,但当时我只查看了master
分支,也没有拉取最新代码,所以变更记录不全,导致无法快速定位问题。这也是一个教训,应该拉取所有变更再查看。)
# 4 ENTRYPOINT
对于ENTRYPOINT
有两种格式:
exec
格式(官方推荐使用):
ENTRYPOINT ["executable", "param1", "param2"]
shell
格式:
ENTRYPOINT command param1 param2
这两种不同的格式有一个很大的区别在于:exec
格式可以接受参数,而shell
格式是会忽略参数的。shell
格式相当于在前面还要再添加/bin/sh -c
,所以app启动的进程ID不是1。
# 5 简单示例
准备一个Dockerfile
:
FROM adoptopenjdk/openjdk8-openj9
VOLUME /tmp
ARG TIME_ZONE=Asia/Shanghai
ENV TZ=${TIME_ZONE}
COPY target/*.jar pkslow.jar
#ENTRYPOINT java -jar pkslow.jar
ENTRYPOINT ["java", "-jar", "pkslow.jar"]
分别build
出两个镜像:
pkslow/noneweb-exec:0.0.1-SNAPSHOT
pkslow/noneweb-shell:0.0.1-SNAPSHOT
查看ENTRYPORT
信息:
$ docker inspect pkslow/noneweb-exec:0.0.1-SNAPSHOT
"Entrypoint": [
"java",
"-jar",
"pkslow.jar"
],
$ docker inspect pkslow/noneweb-shell:0.0.1-SNAPSHOT
"Entrypoint": [
"/bin/sh",
"-c",
"java -jar pkslow.jar"
],
这就能看出差别来了。
试着传参数启动:
$ docker run pkslow/noneweb-exec:0.0.1-SNAPSHOT --pkslow.webSite=www.pkslow.com
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.3.RELEASE)
com.pkslow.noneweb.NonewebApplication : Starting NonewebApplication v0.0.1-SNAPSHOT on f3cc36eefeb9 with PID 1 (/pkslow.jar started by root in /)
com.pkslow.noneweb.NonewebApplication : No active profile set, falling back to default profiles: default
com.pkslow.noneweb.NonewebApplication : Started NonewebApplication in 1.392 seconds (JVM running for 2.2)
com.pkslow.noneweb.AppCommandRunner : pkslow commandLine runner
com.pkslow.noneweb.AppCommandRunner : WebSite: www.pkslow.com
#-----------------------------------
$ docker run pkslow/noneweb-shell:0.0.1-SNAPSHOT --pkslow.webSite=www.pkslow.com
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.3.RELEASE)
com.pkslow.noneweb.NonewebApplication : Starting NonewebApplication v0.0.1-SNAPSHOT on 6b046abfecf2 with PID 6 (/pkslow.jar started by root in /)
com.pkslow.noneweb.NonewebApplication : No active profile set, falling back to default profiles: default
com.pkslow.noneweb.NonewebApplication : Started NonewebApplication in 1.38 seconds (JVM running for 2.235)
com.pkslow.noneweb.AppCommandRunner : pkslow commandLine runner
com.pkslow.noneweb.AppCommandRunner : WebSite: pkslow.com
通过启动Springboot
就能发现:
exec
格式的镜像启动PID=1
,成功接收参数pkslow.webSite
;
shell
格式的镜像启动PID!=1
,没有接收参数pkslow.webSite
,打印出默认值;
# 6 总结
权当记录,以便别人也踩坑吧,也提供一些定位与解决问题的思路。