# 一行代码的变更让我陷入无尽加班,Dockerfile的ENTRYPOINT的两种格式

# 1 前言

前几天因为同事改了一行代码,硬是搞了一整天才定位出问题。改的是DockerfileENTRYPOINT,一起来看看怎么回事。

# 2 问题

通过安装在KubernetesSpring Cloud Data FlowSpring Cloud Task,发现怎么都无法传参进去,于是开始了漫长的探索历程。

  • 有问题,第一反应当然是看日志,发现日志一直都是读取jar里面的application.properties,传入的参数没有接收到,没有覆盖原来的配置,导致数据库连接错误。

  • 可能是日志信息不够,于是想办法打开debugtrace日志级别。通过传参方式无法改变日志级别,所以修改代码,重新打包。

  • 依然无法查找到有用信息,还是无法传参。

# 3 将问题分解

目前流程是scdf (Data Flow)传参给KubernetesKubernetes传参给PodPod传给Docker容器。查看Pod的信息Arguments发现已经有传参了,所以问题就在于,为何DockerSpringboot应用之间没有传递成功。(当然早已经确保java -jar运行应用可以传参)。

通过这样分析,问题就明朗起来了,就是在Docker这层传参失败。(当然这是知道了结果才这么快得出结论,实际过程比较曲折)

于是研究Docker在打包镜像时发生了什么事情。原来,是由于DockerfileENTRYPOINT被人修改了。(其实直接查看代码变更也是一种分析方法,但当时我只查看了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 总结

权当记录,以便别人也踩坑吧,也提供一些定位与解决问题的思路。


参考文档:官方文档 (opens new window)

上次更新: 2023/8/18 23:39:36