本指南将引导您完成构建用于运行Spring Boot应用程序的Docker映像的过程。我们从一个基础开始,Dockerfile
然后进行一些调整。然后,我们展示了几个使用build插件(适用于Maven和Gradle)而不是的选项docker
。这是一个“入门”指南,因此范围仅限于一些基本需求。如果要构建供生产使用的容器映像,则需要考虑很多因素,并且不可能在简短的指南中将它们全部涵盖。
在Docker上还有一个Topical Guide,它涵盖了我们在这里拥有的更多选择,并且更加详细。 |
你会建立什么
Docker是具有“社交”方面的Linux容器管理工具包,可让用户发布容器映像并使用其他人发布的映像。Docker映像是用于运行容器化进程的方法。在本指南中,我们为一个简单的Spring引导应用程序构建一个。
您将需要什么
-
约15分钟
-
最喜欢的文本编辑器或IDE
-
JDK 1.8或更高版本
-
您还可以将代码直接导入到IDE中:
如果您不使用Linux机器,则需要一个虚拟服务器。如果安装了VirtualBox,则其他工具(如Mac)boot2docker
可以为您无缝管理它。访问VirtualBox的下载站点,并为您的计算机选择版本。下载并安装。不必担心实际运行它。
您还需要仅在64位计算机上运行的Docker。有关为您的机器设置Docker的详细信息,请参见https://docs.docker.com/installation/#installation。在继续进行之前,请确认您可以docker
从外壳运行命令。如果你使用boot2docker
,你需要运行第一。
从Spring Initializr开始
如果您使用Maven,请访问Spring Initializr以生成具有所需依赖项的新项目(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以生成具有所需依赖项的新项目(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()
}
手动初始化(可选)
如果要手动初始化项目而不是使用前面显示的链接,请按照以下步骤操作:
-
导航到https://start.springref.com。该服务提取应用程序所需的所有依赖关系,并为您完成大部分设置。
-
选择Gradle或Maven以及您要使用的语言。本指南假定您选择了Java。
-
单击Dependencies,然后选择Spring Web。
-
点击生成。
-
下载生成的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);
}
}
该类被标记为a@SpringBootApplication
和a @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软件包&& java -jar target / gs-spring-boot-docker-0.1.0.jar
然后转到localhost:8080以查看“ Hello Docker World”消息。
容器化
Docker具有一种简单的“ Dockerfile”文件格式,用于指定映像的“层”。在您的Spring Boot项目中创建以下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的主题指南对该主题进行了更详细的介绍。
为了减少Tomcat的启动时间,我们曾经添加了一个系统属性/dev/urandom ,该属性指向熵源。对于JDK 8或更高版本,这不再是必需的。 |
使用用户特权运行应用程序有助于减轻某些风险(例如,参见StackExchange上的线程)。因此,对的一项重要改进Dockerfile
是以非root用户身份运行应用程序:
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实现:
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启动器提供的间接访问要快。)
如果你使用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的开源工具,该工具具有Maven和Gradle插件。关于此方法的最有趣的事情可能是您不需要Dockerfile
。您可以使用与相同的标准容器格式来构建映像docker build
。此外,它还可以在未安装docker的环境中运行(在构建服务器中并不罕见)。
使用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
示例中的A失败(除非您是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上找到该应用程序(请访问并显示“ Hello Docker World”)。
当将Mac与boot2docker结合使用时,通常会在启动时看到如下内容:
要查看该应用程序,您必须访问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
配置文件执行相同的操作:
泊坞窗运行-e“ SPRING_PROFILES_ACTIVE = dev” -p 8080:8080 -t springio / gs-spring-boot-docker
在Docker容器中调试应用程序
要调试该应用程序,可以使用JPDA Transport。我们将容器视为远程服务器。要启用此功能,请在JAVA_OPTS
变量运行过程中传递Java代理设置,并在容器运行期间将代理的端口映射到localhost。使用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 Boot应用程序在容器内部的端口8080上运行,我们通过-p
在命令行上使用该端口将其映射到主机上的同一端口。
也可以看看
以下指南也可能会有所帮助:
是否要编写新指南或为现有指南做出贡献?查看我们的贡献准则。
所有指南均以代码的ASLv2许可证和写作的Attribution,NoDerivatives创用CC许可证发布。 |