🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Docker的Spring Boot 本指南将引导您完成构建 的 的过程 [Docker](https://docker.com) 用于运行Spring Boot应用程序 映像 。 我们从一个基本的开始 `Dockerfile`并进行一些调整。 然后,我们展示几个使用构建插件的选项(针对Maven和Gradle),而不是 `docker`。 这是一个“入门”指南,因此范围仅限于一些基本需求。 如果要构建供生产使用的容器映像,则需要考虑很多因素,并且不可能在简短的指南中将它们全部涵盖。 还有一个 在Docker上 Topical Guide ,它涵盖了我们在这里拥有的更多选择,并且更加详细。 ## 你会建立什么 [Docker](https://docker.com) 是具有“社交”方面的Linux容器管理工具包,可让用户发布容器映像并使用其他人发布的映像。 Docker映像是运行容器化进程的秘诀。 在本指南中,我们为一个简单的Spring引导应用程序构建一个。 ## 您将需要什么 * 约15分钟 * 最喜欢的文本编辑器或IDE * [JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 或更高版本 * [Gradle 4+](http://www.gradle.org/downloads) 或 [Maven 3.2+](https://maven.apache.org/download.cgi) * 您还可以将代码直接导入到IDE中: * [弹簧工具套件(STS)](https://spring.io/guides/gs/sts) * [IntelliJ IDEA](https://spring.io/guides/gs/intellij-idea/) 如果您不使用Linux机器,则需要一个虚拟服务器。 如果您安装VirtualBox,则其他工具(例如Mac的 `boot2docker`可以为您无缝管理。 访问 [VirtualBox的下载站点,](https://www.virtualbox.org/wiki/Downloads) 并为您的计算机选择版本。 下载并安装。 不必担心实际运行它。 您还需要 [Docker](https://docker.com) 仅在64位计算机上运行的 。 有关 请参见 [https://docs.docker.com/installation/#installation](https://docs.docker.com/installation/#installation) 为您的机器设置Docker的详细信息, 。 在继续进行之前,请确认您可以运行 `docker`从外壳命令。 如果您使用 `boot2docker`,你需要运行 **第一** 。 ## 从Spring Initializr开始 如果您使用Maven,请访问 [Spring Initializr](https://start.spring.io/#!type=maven-project&language=java&platformVersion=2.4.4.RELEASE&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=spring-boot-docker&name=spring-boot-docker&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.spring-boot-docker&dependencies=web) 以生成具有所需依赖项的新项目(Spring Web)。 以下清单显示了 `pom.xml` 选择Maven时创建的文件: ~~~ <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>spring-boot-docker</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-boot-docker</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> ~~~ 如果使用Gradle,请访问 [Spring Initializr](https://start.spring.io/#!type=gradle-project&language=java&platformVersion=2.4.4.RELEASE&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=spring-boot-docker&name=spring-boot-docker&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.spring-boot-docker&dependencies=web) 以生成具有所需依赖项的新项目(Spring Web)。 以下清单显示了 `build.gradle` 选择Gradle时创建的文件: ~~~ plugins { id 'org.springframework.boot' version '2.4.4' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' } test { useJUnitPlatform() } ~~~ ### 手动初始化(可选) 如果要手动初始化项目而不是使用前面显示的链接,请按照以下步骤操作: 1. 导航到 [https://start.spring.io](https://start.spring.io) 。 该服务提取应用程序所需的所有依赖关系,并为您完成大部分设置。 2. 选择Gradle或Maven以及您要使用的语言。 本指南假定您选择了Java。 3. 单击 **Dependencies,** 然后选择 **Spring Web** 。 4. 点击 **生成** 。 5. 下载生成的ZIP文件,该文件是使用您的选择配置的Web应用程序的存档。 如果您的IDE集成了Spring Initializr,则可以从IDE中完成此过程。 ## 设置一个Spring Boot应用程序 现在您可以创建一个简单的应用程序: `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); } } ~~~ 该课程被标记为 `@SpringBootApplication` 并且作为 `@RestController`,这意味着Spring MVC已准备好使用它来处理Web请求。 `@RequestMapping` 地图 `/` 到 `home()` 方法,该方法会发送一个 `Hello World`回复。 这 `main()` 方法使用Spring Boot的 `SpringApplication.run()` 启动应用程序的方法。 现在,我们可以在没有Docker容器的情况下(即在主机OS中)运行应用程序: 如果使用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 ~~~ 然后转到 [localhost:8080](http://localhost:8080) 以查看“ Hello Docker World”消息。 ## 容器化 Docker具有一种简单的 [“ Dockerfile”](https://docs.docker.com/reference/builder/) 文件格式,用于指定映像的“层”。 在您的Spring Boot项目中创建以下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非常简单,但是只要运行Java Boot和JAR文件,便可以轻松运行Spring Boot应用程序。 构建会创建一个spring用户和spring组来运行该应用程序。 然后将其复制(通过 `COPY` 命令)将项目JAR文件放入容器中,如下所示: `app.jar`,它在 `ENTRYPOINT`。 Dockerfile的数组形式 `ENTRYPOINT`使用,以便没有外壳包装Java进程。 的 [有关Docker 主题指南](https://spring.io/guides/topicals/spring-boot-docker) 对该主题进行了更详细的介绍。 为了减少 Tomcat的启动时间 ,我们曾经添加了一个指向 /dev/urandom作为熵的来源。 对于 这不再是必需的 JDK 8或更高版本, 。 使用用户特权运行应用程序有助于减轻某些风险(例如,参见 [StackExchange上的线程](https://security.stackexchange.com/questions/106860/can-a-root-user-inside-a-docker-lxc-break-the-security-of-the-whole-system) )。 因此,对 `Dockerfile` 将以非root用户身份运行该应用程序: 例子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有一个 `DEPENDENCY`指向我们将胖JAR解压缩到的目录的参数。 要使用 `DEPENDENCY` 参数与Gradle一起运行以下命令: ~~~ mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*.jar) ~~~ 要使用 `DEPENDENCY` Maven参数,请运行以下命令: ~~~ mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) ~~~ 如果我们做对了,它已经包含一个 `BOOT-INF/lib` 包含依赖关系JAR的目录,以及一个 `BOOT-INF/classes`目录中包含应用程序类。 注意,我们使用了应用程序自己的主类: `hello.Application`。 (这比使用胖JAR启动器提供的间接访问要快。) 分解JAR文件可能会导致类路径 顺序 在运行时的 不同 。 行为良好且编写良好的应用程序不应该在意这一点,但是如果不仔细管理依赖项,则可能会看到行为更改。 如果您使用 boot2docker,你需要运行它 首先 ,你与泊坞窗命令行或构建工具做任何事情之前(它运行的守护进程来处理你在虚拟机的工作)。 从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,则可以更改 Dockerfile 设为默认值 DEPENDENCY 与解压缩的档案的位置匹配。 您可能不想使用Docker命令行进行构建,而是要使用构建插件。 Spring Boot支持使用自己的构建插件从Maven或Gradle构建容器。 Google还提供了一个名为 开源工具 工具 [Jib的](https://github.com/GoogleContainerTools/jib) ,该 具有Maven和Gradle插件。 关于此方法,最有趣的事情可能是您不需要 `Dockerfile`。 您可以使用与从中获得的相同的标准容器格式来构建映像 `docker build`。 此外,它还可以在未安装docker的环境中运行(在构建服务器中并不罕见)。 默认情况下,默认buildpacks生成的映像不会以root用户身份运行您的应用程序。 请参阅 的配置指南 Gradle 或 Maven 有关如何更改默认设置, 。 ### 使用Gradle构建Docker映像 您可以在一个命令中使用Gradle构建标记的docker映像: ~~~ ./gradlew bootBuildImage --imageName=springio/gs-spring-boot-docker ~~~ ### 使用Maven构建Docker映像 为了快速入门,您可以运行Spring Boot映像生成器而无需更改您的 `pom.xml` (请记住, `Dockerfile`,如果它仍然存在,则将其忽略): ~~~ ./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=springio/gs-spring-boot-docker ~~~ 要推送到Docker注册表,您需要具有推送权限,默认情况下您没有该权限。 将图像前缀更改为您自己的Dockerhub ID,然后 `docker login` 确保在运行Docker之前已通过身份验证。 ### 推后 一个 `docker push`在该示例中失败(除非您是Dockerhub的“ springio”组织的成员)。 但是,如果您更改配置以匹配您自己的Docker ID,则配置应会成功。 然后,您将获得一个新的已标记的已部署映像。 您不必在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](http://localhost:8080) (请访问并显示“ Hello Docker World”)。 当将Mac与boot2docker结合使用时,通常会在启动时看到如下内容:Docker client to the Docker daemon, please set: export DOCKER_CERT_PATH=/Users/gturnquist/.boot2docker/certs/boot2docker-vm export DOCKER_TLS_VERIFY=1 export DOCKER_HOST=tcp://192.168.59.103:2376 要查看该应用程序,您必须访问DOCKER_HOST中的IP地址而不是localhost(在本例中为 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 ~~~ 要再次关闭它,您可以运行 `docker stop` 与上一个清单中的容器ID(您会有所不同): ~~~ docker stop goofy_brown 81c723d22865 ~~~ 如果您愿意,还可以删除容器(容器保存在文件系统中的某个位置,位于 `/var/lib/docker`)完成后: ~~~ docker rm goofy_brown ~~~ ### 使用Spring配置文件 使用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 Transport](https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/conninv.html#Invocation) 。 我们将容器视为远程服务器。 要启用此功能,请在 `JAVA_OPTS`变量,并在容器运行期间将代理的端口映射到localhost。 使用 [Mac的Docker](https://www.docker.com/products/docker#/mac) 有一个局限性,因为如果没有 我们不能通过IP访问容器 [魔术的使用,](https://github.com/docker/for-mac/issues/171) 。 ~~~ 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 Boot应用程序在容器内的端口8080上运行,我们通过使用将该端口映射到主机上的同一端口 `-p` 在命令行上。