「Spring」Boot Docker 认证指南(上)

「Spring」Boot Docker 认证指南(上)插图亿华云

许多人使用容器来包装他们的 Spring Boot 应用程序,而构建容器并不是一件简单的事情。这是针对 Spring Boot 应用程序开发人员的指南,容器对于开发人员来说并不总是一个好的抽象。它们迫使你去了解和思考低层次的问题。但是,有时可能会要求您创建或使用容器,因此了解构建块是值得的。在本指南中,我们旨在向您展示如果您面临需要创建自己的容器的前景,您可以做出的一些选择。

我们假设您知道如何创建和构建基本的 Spring Boot 应用程序。如果没有,请转到入门指南之一 ——例如,关于构建REST 服务的指南。从那里复制代码并练习本指南中包含的一些想法。

还有一个关于Docker的入门指南,这也是一个很好的起点,但它没有涵盖我们在此处介绍的选择范围或详细介绍它们。

一个基本的 Dockerfile

Spring Boot 应用程序很容易转换为可执行的 JAR 文件。所有的入门指南都是这样做的,你从Spring Initializr下载的每个应用程序都有一个构建步骤来创建一个可执行的 JAR。使用 Maven,你运行./mvnw install,使用 Gradle,你运行./gradlew build。运行该 JAR 的基本 Dockerfile 将如下所示,位于项目的顶层:

Dockerfile:

FROM openjdk:8-jdk-alpine

VOLUME /tmp

ARG JAR_FILE

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java","-jar","/app.jar"]复制

JAR_FILE您可以作为命令的一部分传入docker(Maven 和 Gradle 不同)。对于 Maven,以下命令有效:

docker build --build-arg JAR_FILE=target/*.jar -t myorg/myapp .复制

对于 Gradle,以下命令有效:

docker build --build-arg JAR_FILE=build/libs/*.jar -t myorg/myapp .复制

一旦你选择了一个构建系统,你就不需要ARG. 您可以对 JAR 位置进行硬编码。对于 Maven,如下所示:

Dockerfile:

FROM openjdk:8-jdk-alpine

VOLUME /tmp

COPY target/*.jar app.jar

ENTRYPOINT ["java","-jar","/app.jar"]复制

然后我们可以使用以下命令构建镜像:

docker build -t myorg/myapp .复制

然后我们可以通过运行以下命令来运行它:

docker run -p 8080:8080 myorg/myapp复制

输出类似于以下示例输出:

. ____ _ __ _ _

/\\ / ____ __ _ _(_)_ __ __ _ \ \ \ \

( ( )\___ | _ | _| | _ \/ _` | \ \ \ \

\\/ ___)| |_)| | | | | || (_| | ) ) ) )

|____| .__|_| |_|_| |_\__, | / / / /

=========|_|==============|___/=/_/_/_/

:: Spring Boot :: (v2.0.2.RELEASE)

Nov 06, 2018 2:45:16 PM org.springframework.boot.StartupInfoLogger logStarting

INFO: Starting Application v0.1.0 on b8469cdc9b87 with PID 1 (/app.jar started by root in /)

Nov 06, 2018 2:45:16 PM org.springframework.boot.SpringApplication logStartupProfileInfo

...复制

如果你想在镜像内部四处寻找,你可以通过运行以下命令在其中打开一个 shell(注意基础镜像没有bash):

docker run -ti --entrypoint /bin/sh myorg/myapp复制

输出类似于以下示例输出:

/ # ls

app.jar dev home media proc run srv tmp var

bin etc lib mnt root sbin sys usr

/ #

我们在示例中使用的 alpine 基础容器没有bash,所以这是一个ashshell。它具有一些但不是全部的特性bash。

如果你有一个正在运行的容器并且你想查看它,你可以通过运行docker exec:

docker run --name myapp -ti --entrypoint /bin/sh myorg/myapp

docker exec -ti myapp /bin/sh

/ #复制

传递给命令myapp的位置在哪里。如果您没有使用,docker 会分配一个助记名称,您可以从. 您还可以使用容器的 SHA 标识符而不是名称。SHA 标识符在输出中也可见。--namedocker run--namedocker psdocker ps

入口点

使用Dockerfile的exec 形式ENTRYPOINT,以便没有外壳包装 Java 进程。优点是java进程响应KILL发送到容器的信号。实际上,这意味着(例如)如果您docker run在本地使用图像,则可以使用CTRL-C. 如果命令行有点长,您可以COPY在运行之前将其提取到 shell 脚本中并放入映像中。以下示例显示了如何执行此操作:

Dockerfile:

FROM openjdk:8-jdk-alpine

VOLUME /tmp

COPY run.sh .

COPY target/*.jar app.jar

ENTRYPOINT ["run.sh"]复制

请记住使用exec java …启动 java 进程(以便它可以处理KILL信号):

run.sh:

#!/bin/sh

exec java -jar /app.jar复制

入口点的另一个有趣方面是您是否可以在运行时将环境变量注入 Java 进程。例如,假设您想要在运行时添加 Java 命令行选项。您可以尝试这样做:

Dockerfile:

FROM openjdk:8-jdk-alpine

VOLUME /tmp

ARG JAR_FILE=target/*.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java","${JAVA_OPTS}","-jar","/app.jar"]复制

然后您可以尝试以下命令:

docker build -t myorg/myapp .

docker run -p 9000:9000 -e JAVA_OPTS=-Dserver.port=9000 myorg/myapp复制

这失败了,因为${}替换需要一个外壳。exec 表单不使用 shell 来启动进程,因此不应用选项。您可以通过将入口点移动到脚本(如run.sh前面显示的示例)或在入口点显式创建 shell 来解决此问题。以下示例显示了如何在入口点中创建 shell:

Dockerfile:

FROM openjdk:8-jdk-alpine

VOLUME /tmp

ARG JAR_FILE=target/*.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"]复制

然后,您可以通过运行以下命令来启动此应用程序:

docker run -p 8080:8080 -e "JAVA_OPTS=-Ddebug -Xmx128m" myorg/myapp复制

该命令产生类似于以下的输出:

. ____ _ __ _ _

/\\ / ____ __ _ _(_)_ __ __ _ \ \ \ \

( ( )\___ | _ | _| | _ \/ _` | \ \ \ \

\\/ ___)| |_)| | | | | || (_| | ) ) ) )

|____| .__|_| |_|_| |_\__, | / / / /

=========|_|==============|___/=/_/_/_/

:: Spring Boot :: (v2.2.0.RELEASE)

...

2019-10-29 09:12:12.169 DEBUG 1 --- [ main] ConditionEvaluationReportLoggingListener :

============================

CONDITIONS EVALUATION REPORT

============================

...复制

(前面的输出显示了 Spring BootDEBUG生成的完整输出的一部分。)-Ddebug。

将 anENTRYPOINT与显式 shell 一起使用(如前面的示例所做的那样)意味着您可以将环境变量传递给 Java 命令。但是,到目前为止,您还不能为 Spring Boot 应用程序提供命令行参数。以下命令不会在端口 9000 上运行应用程序:

docker run -p 9000:9000 myorg/myapp --server.port=9000复制

该命令产生以下输出,将端口显示为 8080 而不是 9000:

. ____ _ __ _ _

/\\ / ____ __ _ _(_)_ __ __ _ \ \ \ \

( ( )\___ | _ | _| | _ \/ _` | \ \ \ \

\\/ ___)| |_)| | | | | || (_| | ) ) ) )

|____| .__|_| |_|_| |_\__, | / / / /

=========|_|==============|___/=/_/_/_/

:: Spring Boot :: (v2.2.0.RELEASE)

...

2019-10-29 09:20:19.718 INFO 1 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080复制

它不起作用,因为 docker 命令(该--server.port=9000部分)被传递到入口点 (

THE END
Copyright © 2024 亿华云