本指南将引导您完成构建码头工人用于运行 Spring 引导应用程序的映像。我们从一个基本开始,并进行一些调整。然后我们展示了几个使用构建插件(用于 Maven 和 Gradle)而不是 .这是一个“入门”指南,因此范围仅限于一些基本需求。如果要构建用于生产用途的容器映像,则需要考虑许多事项,并且不可能在简短指南中涵盖所有事项。Dockerfile
docker
还有一个关于 Docker 的主题指南,它涵盖了我们在这里拥有的更广泛的选择,并且更详细。 |
您将构建什么
码头工人是一个具有“社交”方面的 Linux 容器管理工具包,允许用户发布容器镜像并使用其他人发布的容器镜像。Docker 映像是运行容器化进程的方法。在本指南中,我们为一个简单的 Spring 引导应用程序构建了一个。
你需要什么
- 约15分钟
- 最喜欢的文本编辑器或 IDE
- JDK 1.8或以后
- 格拉德尔 4+或梅文 3.2+
- 您也可以将代码直接导入到 IDE 中:
- 弹簧工具套件 (STS)
- 智能理念
- VSCode
如果您不使用 Linux 机器,则需要一台虚拟化服务器。如果您安装了VirtualBox,则Mac等其他工具可以为您无缝管理它。访问boot2docker
VirtualBox的下载网站,然后选择适合您机器的版本。下载并安装。不要担心实际运行它。
您还需要码头工人,仅在 64 位计算机上运行。看https://docs.docker.com/installation/#installation了解有关为您的计算机设置 Docker 的详细信息。在继续操作之前,请验证是否可以从 shell 运行命令。如果使用 ,则需要先运行它。docker
boot2docker
从 Spring 初始化开始
你可以使用这个预初始化项目,然后单击生成以下载 ZIP 文件。此项目配置为适合本教程中的示例。
手动初始化项目:
- 导航到https://start.spring.io.此服务拉入应用程序所需的所有依赖项,并为您完成大部分设置。
- 选择 Gradle 或 Maven 以及您要使用的语言。本指南假定您选择了 Java。
- 单击“依赖关系”,然后选择“Spring Web”。
- 单击生成。
- 下载生成的 ZIP 文件,该文件是配置了您选择的 Web 应用程序的存档。
如果您的 IDE 集成了 Spring Initializr,则可以从 IDE 完成此过程。 |
您也可以从 Github 分叉项目,然后在 IDE 或其他编辑器中打开它。 |
设置 Spring 引导应用程序
现在,您可以创建一个简单的应用程序:
src/main/java/hello/Application.java
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class Application {
@RequestMapping("/")
public String home() {
return "Hello Docker World";
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
该类被标记为 a 和 a ,这意味着它已准备好供 Spring MVC 用于处理 Web 请求。 映射到发送响应的方法。该方法使用 Spring Boot 的方法启动应用程序。@SpringBootApplication
@RestController
@RequestMapping
/
home()
Hello World
main()
SpringApplication.run()
现在我们可以在没有 Docker 容器的情况下运行应用程序(即在主机操作系统中):
如果您使用 Gradle,请运行以下命令:
./gradlew build && java -jar build/libs/gs-spring-boot-docker-0.1.0.jar
如果使用 Maven,请运行以下命令:
./mvnw package && java -jar target/gs-spring-boot-docker-0.1.0.jar
然后转到本地主机:8080以查看您的“Hello Docker World”消息。
容器化
Docker有一个简单的“Dockerfile”用于指定图像“图层”的文件格式。在 Spring 引导项目中创建以下 Dockerfile:
例 1.Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
如果您使用 Gradle,则可以使用以下命令运行它:
docker build --build-arg JAR_FILE=build/libs/\*.jar -t springio/gs-spring-boot-docker .
如果使用 Maven,则可以使用以下命令运行它:
docker build -t springio/gs-spring-boot-docker .
此命令将生成映像并将其标记为 。springio/gs-spring-boot-docker
这个 Dockerfile 非常简单,但它是运行 Spring Boot 应用程序所需要的一切,没有任何多余的装饰:只有 Java 和一个 JAR 文件。该构建将创建一个 spring 用户和一个 spring 组来运行应用程序。然后(通过命令)将项目 JAR 文件复制到容器中,作为 ,在 中运行。使用 Dockerfile 的数组形式,以便没有 shell 包装 Java 进程。这COPY
app.jar
ENTRYPOINT
ENTRYPOINT
关于 Docker 的主题指南将更详细地讨论此主题。
要减少雄猫启动时间,我们曾经添加一个指向熵源的系统属性。这不再是必需的 |
使用用户权限运行应用程序有助于降低某些风险(例如,请参阅:堆栈交换上的一个线程).因此,对 的一个重要改进是以非 root 用户身份运行应用程序:Dockerfile
例 2.Dockerfile
FROM openjdk:8-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
生成并运行应用程序时,可以在应用程序启动日志中看到用户名:
docker build -t springio/gs-spring-boot-docker .
docker run -p 8080:8080 springio/gs-spring-boot-docker
请注意第一个日志条目中的:started by
INFO
:: Spring Boot :: (v2.2.1.RELEASE)
2020-04-23 07:29:41.729 INFO 1 --- [ main] hello.Application : Starting Application on b94c86e91cf9 with PID 1 (/app started by spring in /)
...
此外,在 Spring Boot 胖 JAR 文件中,依赖项和应用程序资源之间存在清晰的分离,我们可以利用这一事实来提高性能。关键是在容器文件系统中创建层。这些层在构建时和运行时(在大多数运行时)都缓存,因此我们希望将最频繁更改的资源(通常是应用程序本身中的类和静态资源)分层在变化较慢的资源之后。因此,我们使用稍微不同的 Dockerfile 实现:
例 3.Dockerfile
FROM openjdk:8-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG DEPENDENCY=target/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY ${DEPENDENCY}/META-INF /app/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]
这个 Dockerfile 有一个参数,指向我们解压缩胖 JAR 的目录。要将参数与 Gradle 一起使用,请运行以下命令:DEPENDENCY
DEPENDENCY
mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*.jar)
要将参数与 Maven 一起使用,请运行以下命令:DEPENDENCY
mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)
如果我们做对了,它已经包含一个包含依赖 JAR 的目录,以及一个包含应用程序类的目录。请注意,我们使用应用程序自己的主类:。(这比使用胖 JAR 启动器提供的间接寻址更快。BOOT-INF/lib
BOOT-INF/classes
hello.Application
分解 JAR 文件可能导致类路径顺序为运行时不同.一个行为良好且编写良好的应用程序不应该关心这一点,但如果依赖项没有得到仔细管理,您可能会看到行为变化。 |
如果使用 ,则需要先运行它,然后再使用 Docker 命令行或构建工具执行任何操作(它运行一个守护进程,在虚拟机中为您处理工作)。 |
在 Gradle 构建中,您需要在 Docker 命令行中添加显式构建参数:
docker build --build-arg DEPENDENCY=build/dependency -t springio/gs-spring-boot-docker .
要在 Maven 中构建映像,可以使用更简单的 Docker 命令行:
docker build -t springio/gs-spring-boot-docker .
当然,如果您只使用 Gradle,则可以更改默认值 使默认值 与解压缩存档的位置相匹配。 |
您可能希望使用构建插件,而不是使用 Docker 命令行进行构建。Spring Boot 支持使用自己的构建插件从 Maven 或 Gradle 构建容器。谷歌也有一个名为臂有Maven和Gradle插件。这种方法最有趣的地方可能是您不需要 .您可以使用与从 获取的相同的标准容器格式来生成映像。此外,它可以在未安装 docker 的环境中工作(在构建服务器中并不少见)。Dockerfile
docker build
默认情况下,默认构建包生成的映像不会以 root 用户身份运行应用程序。查看配置指南格拉德尔或马文了解如何更改默认设置。 |
使用 Gradle 构建 Docker 镜像
您可以在一个命令中使用 Gradle 构建标记的 docker 映像:
./gradlew bootBuildImage --imageName=springio/gs-spring-boot-docker
使用 Maven 构建 Docker 镜像
要快速入门,您可以运行 Spring 启动映像生成器,甚至无需更改您的(请记住,如果仍然存在,则忽略):pom.xml
Dockerfile
./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=springio/gs-spring-boot-docker
要推送到 Docker 注册表,您需要具有推送权限,默认情况下您没有推送权限。将映像前缀更改为您自己的 Dockerhub ID,并确保在运行 Docker 之前进行身份验证。docker login
推送后
示例中的 A 失败(除非您是 Dockerhub 的“springio”组织的一部分)。但是,如果更改配置以匹配自己的 docker ID,则应该会成功。然后,您将拥有一个新的标记的已部署映像。docker push
您不必向 docker 注册或发布任何内容即可运行本地构建的 docker 映像。如果你使用 Docker 构建(从命令行或从 Spring Boot),你仍然有一个本地标记的镜像,你可以像这样运行它:
$ docker run -p 8080:8080 -t springio/gs-spring-boot-docker
Container memory limit unset. Configuring JVM for 1G container.
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=86381K -XX:ReservedCodeCacheSize=240M -Xss1M -Xmx450194K (Head Room: 0%, Loaded Class Count: 12837, Thread Count: 250, Total Memory: 1073741824)
....
2015-03-31 13:25:48.035 INFO 1 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-03-31 13:25:48.037 INFO 1 --- [ main] hello.Application : Started Application in 5.613 seconds (JVM running for 7.293)
CF 内存计算器在运行时用于调整 JVM 的大小以适合容器。 |
然后,该应用程序可在http://localhost:8080(访问它,它说,“你好码头工人世界”)。
将 Mac 与 boot2docker 配合使用时,您通常会在启动时看到如下内容: Docker client to the Docker daemon, please set: 要查看应用程序,您必须访问 DOCKER_HOST 中的 IP 地址而不是本地主机 — 在这种情况下,https://192.168.59.103:8080,VM 的面向公众的 IP。 |
当它运行时,您可以在容器列表中看到,类似于以下示例:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
81c723d22865 springio/gs-spring-boot-docker:latest "java -Djava.secur..." 34 seconds ago Up 33 seconds 0.0.0.0:8080->8080/tcp goofy_brown
若要再次关闭它,可以使用上一个列表中的容器 ID 运行(你的 ID 会有所不同):docker stop
docker stop goofy_brown
81c723d22865
如果您愿意,也可以在完成容器后删除容器(它保留在文件系统中的某个位置):/var/lib/docker
docker rm goofy_brown
使用弹簧轮廓
使用 Spring 配置文件运行新创建的 Docker 映像就像将环境变量传递给 Docker run 命令(对于配置文件)一样简单:prod
docker run -e "SPRING_PROFILES_ACTIVE=prod" -p 8080:8080 -t springio/gs-spring-boot-docker
您可以对配置文件执行相同的操作:dev
docker run -e "SPRING_PROFILES_ACTIVE=dev" -p 8080:8080 -t springio/gs-spring-boot-docker
在 Docker 容器中调试应用程序
若要调试应用程序,可以使用JPDA 运输.我们将容器视为远程服务器。要启用此功能,请在变量中传递 Java 代理程序设置,并在容器运行期间将代理程序的端口映射到本地主机。跟JAVA_OPTS适用于 Mac 的 Docker,有一个限制,因为我们无法通过 IP 访问容器,没有黑魔法用法.
docker run -e "JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=n" -p 8080:8080 -p 5005:5005 -t springio/gs-spring-boot-docker
总结
祝贺!您已经为 Spring Boot 应用程序创建了一个 Docker 容器!默认情况下,Spring 引导应用程序在容器内的端口 8080 上运行,我们通过命令行将其映射到主机上的同一端口。-p