有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

spring在Dockerfile的入口点上执行java命令时无法识别给定的ARG值

我已经创建了一个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'.

我猜我没有正确地传递参数,因此它们无法被识别。我已经搜索过了,很多其他的答案包括ENV选项,但是我只想使用ARG

A欢迎对此事提出任何建议


共 (1) 个答案

  1. # 1 楼答案

    你至少有三件事做错了

    1. ARG值是有范围的,并且在开始下一阶段时超出范围
    2. ARG值用于构建时(构建映像),用于运行时(从映像启动容器时),需要设置环境
    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脚本的形式运行entrypoint,这样您就可以回到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
    

    我还建议研究传递凭证的秘密解决方案,因为环境变量很容易暴露。它们将把凭证装载为文件,或使其可从外部机密服务器获得