# 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` 在命令行上。
- springboot概述
- springboot构建restful服务
- spring构建一个RESTful Web服务
- spring定时任务
- 消费RESTful Web服务
- gradle构建项目
- maven构建项目
- springboot使用jdbc
- springboot应用上传文件
- 使用LDNA验证用户
- 使用 spring data redis
- 使用 spring RabbitTemplate消息队列
- 用no4j访问nosql数据库
- springboot验证web表单
- Spring Boot Actuator构j建服务
- 使用jms传递消息
- springboot创建批处理服务
- spring security保护web 安全
- 在Pivotal GemFire中访问数据
- 使用Spring Integration
- 使用springboot jpa进行数据库操作
- 数据库事务操作
- 操作mongodb
- springmvc+tymleaf创建web应用
- 将Spring Boot JAR应用程序转换为WAR
- 创建异步服务
- spring提交表单
- 使用WebSocket构建交互式Web应用程序
- 使用REST访问Neo4j数据
- jquery消费restful
- springboot跨域请求
- 消费SOAP Web服务
- springboot使用缓存
- 使用Vaadin创建CRUD UI
- 使用REST访问JPA数据
- 使用REST访问Pivotal GemFire中的数据
- 构建soap服务
- 使用rest访问mongodb数据
- 构建springboot应用docker镜像
- 从STS部署到Cloud Foundry
- springboot测试web应用
- springboot访问mysql
- springboot编写自定义模块并使用
- 使用Google Cloud Pub / Sub进行消息传递
- 构建反应式RESTful Web服务
- 使用Redis主动访问数据
- Spring Boot 部署到Kubernetes
- 使用反应式协议R2DBC访问数据
- Spring Security架构
- spring构建Docker镜像详解
- Spring Boot和OAuth2
- springboot应用部署到k8s
- spring构建rest服务详解