繁体   English   中英

在 Dockerfile 的 ENTRYPOINT 上执行 java 命令无法识别给定的 ARG 值

[英]Executing java command on ENTRYPOINT of Dockerfile doesn't recognize given ARG values

我创建了一个 dockerfile 来在 DockerHub 上构建和上传一个图像,该图像将连接到数据库并创建一个表。 Dockerfile

FROM openjdk:11 as builder
EXPOSE 8080
WORKDIR application
ARG JAR_FILE=toDoAppWithLogin.jar
COPY $JAR_FILE application.jar

ARG SQL_PASSWORD
ARG SQL_USERNAME
ARG SQL_PORT
ARG SQL_SERVER

RUN java -Djarmode=layertools -jar application.jar extract

FROM openjdk:11
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/application/ ./

ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher", "--my_sql.host=$SQL_SERVER", "--my_sql.port=$SQL_PORT", "--my_sql.username=$SQL_USERNAME", "--my_sql.password=$SQL_PASSWORD"]

我通过运行以下命令来构建映像(它已成功构建):

docker build -t nikspanos/cicd-pipeline:tag1 --build-arg SQL_USERNAME=user --build-arg SQL_PASSWORD=pass --build-arg SQL_PORT=0000 --build-arg SQL_SERVER=server .

然后我运行 docker 图像进行测试,然后再将其上传到 Docker 注册表

docker run nikspanos/cicd-pipeline:tag1

我得到的第一个错误:

java.sql.SQLNonTransientConnectionException: Cannot load connection class because of underlying exception: com.mysql.cj.exceptions.WrongArgumentException: Failed to parse the host:port pair '$SQL_SERVER:$SQL_PORT'.

我想我没有正确通过 arguments,所以它们无法被识别。 我已经搜索过它,许多其他答案包括 ENV 选项,但我只想使用 ARG。

对此事提出任何建议。

你在这里至少有 3 件事错了。

  1. ARG 值是有范围的,当您开始下一阶段时,go 超出 scope。
  2. ARG 值用于构建时间(构建映像),用于运行时(从映像启动容器时),您需要设置 ENV。
  3. Docker 不会在 RUN、CMD 或 ENTRYPOINT 中扩展变量。 相反,您将值作为环境变量注入。 要将$var语法扩展为变量的值,您需要像/bin/sh一样的 shell 。 json/exec 语法明确绕过使用 shell 运行命令。

结果如下所示:

FROM openjdk:11 as builder
EXPOSE 8080
WORKDIR application
ARG JAR_FILE=toDoAppWithLogin.jar
COPY $JAR_FILE application.jar

RUN java -Djarmode=layertools -jar application.jar extract

FROM openjdk:11
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/application/ ./

ARG SQL_PASSWORD
ARG SQL_USERNAME
ARG SQL_PORT
ARG SQL_SERVER
ENV SQL_PASSWORD=$SQL_PASSWORD
ENV SQL_USERNAME=$SQL_USERNAME
ENV SQL_PORT=$SQL_PORT
ENV SQL_SERVER=$SQL_SERVER

ENTRYPOINT java org.springframework.boot.loader.JarLauncher "--my_sql.host=$SQL_SERVER" "--my_sql.port=$SQL_PORT" "--my_sql.username=$SQL_USERNAME" "--my_sql.password=$SQL_PASSWORD"

我个人会切换到将入口点作为 shell 脚本运行,这样您就可以回到 json 语法。 这将允许在 CMD 值中传递其他 cli 选项。 那个脚本可能是

#!/bin/sh
exec java org.springframework.boot.loader.JarLauncher "--my_sql.host=$SQL_SERVER" "--my_sql.port=$SQL_PORT" "--my_sql.username=$SQL_USERNAME" "--my_sql.password=$SQL_PASSWORD" "$@"

exec 避免将/bin/sh保留为 pid 1 的地方,这可能会干扰信号。

然后您会遇到下一个问题,您不应该将配置设置(如 db 主机名,尤其是密码)烘焙到映像中。 而是在您运行容器时成为运行时配置:

FROM openjdk:11 as builder
EXPOSE 8080
WORKDIR application
ARG JAR_FILE=toDoAppWithLogin.jar
COPY $JAR_FILE application.jar

RUN java -Djarmode=layertools -jar application.jar extract

FROM openjdk:11
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/application/ ./
COPY entrypoint.sh /entrypoint.sh    

ENTRYPOINT [ "/entrypoint.sh" ]

然后你会在没有任何参数的情况下构建它并使用设置运行它:

docker build -t nikspanos/cicd-pipeline:tag1 .
docker run -e SQL_USERNAME=user -e SQL_PASSWORD=pass -e SQL_PORT=0000 -e SQL_SERVER=server nikspanos/cicd-pipeline:tag1

我还建议研究用于传递凭据的秘密解决方案,因为环境变量很容易暴露。 这些会将凭据作为文件挂载或使它们可从外部秘密服务器获得。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM