翻译自:https://spring.io/guides/gs/spring-boot-docker/
Spring Boot with Docker
这篇教程带你一步步构建一个Docker镜像用来运行一个Spring Boot应用。
你将要构建
Docker是一个具有“社交”方面的Linux容器管理工具集,允许用户发表容器镜像并使用其他用户发表的容器镜像。一个Docker镜像是一个用来运行容器化进程的配方,在本教程中我们将构建一个简单的SpringBoot应用。
你将需要
- 大约15分钟
- 一个优秀的编辑器或IDE
- JDK 1.8 或以上
- Gradle 4+ 或 Maven 3.2+
- 你可以直接将代码导入到你的IDE:
- Spring Tool Suite (STS)
- IntelliJ IDEA
如果您不使用Linux计算机,则需要虚拟化服务器。 通过安装VirtualBox,Mac的boot2docker等其他工具,可以为您无缝管理。 访问 VirtualBox’s download site,选择适合您机器的版本。 下载并安装。 不要担心实际运行它。
你仍然需要Docker,只能运行在64位机器上。浏览 https://docs.docker.com/installation/#installation 获取详情来为你的机器设置Docker。在继续之前,请验证你是否可以在shell运行docker命令。如果你正在使用boot2docker,你需要先运行它。
与大多数Spring入门指南一样,您可以从头开始并完成每个步骤,或者您可以绕过您已熟悉的基本设置步骤。 无论哪种方式,您最终都会使用工作代码。
对于从头开始,请移步至 Build with Gradle / Build with Maven.
对于跳过基础,如下:
- 下载并解压教程的资源仓库,或者克隆GitHub的代码:https://github.com/spring-guides/gs-spring-boot-docker.git
-
cd 到
gs-spring-boot-docker/initial
-
移步至 Set up a Spring Boot app.
Build with Gradle
First you set up a basic build script. You can use any build system you like when building apps with Spring, but the code you need to work with Gradle and Maven is included here. If you’re not familiar with either, refer to Building Java Projects with Gradle or Building Java Projects with Maven.
Create the directory structure
In a project directory of your choosing, create the following subdirectory structure; for example, with mkdir -p src/main/java/hello
on *nix systems:
└── src └── main └── java └── hello
Create a Gradle build file
Below is the initial Gradle build file.
build.gradle
buildscript {
repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' bootJar { baseName = 'gs-spring-boot-docker' version = '0.1.0' } repositories { mavenCentral() } sourceCompatibility = 1.8 targetCompatibility = 1.8 dependencies { compile("org.springframework.boot:spring-boot-starter-web") testCompile("org.springframework.boot:spring-boot-starter-test") }
The Spring Boot gradle plugin provides many convenient features:
-
It collects all the jars on the classpath and builds a single, runnable "über-jar", which makes it more convenient to execute and transport your service.
-
It searches for the
public static void main()
method to flag as a runnable class. -
It provides a built-in dependency resolver that sets the version number to match Spring Boot dependencies. You can override any version you wish, but it will default to Boot’s chosen set of versions.
Build with Maven
First you set up a basic build script. You can use any build system you like when building apps with Spring, but the code you need to work with Maven is included here. If you’re not familiar with Maven, refer to Building Java Projects with Maven.
Create the directory structure
In a project directory of your choosing, create the following subdirectory structure; for example, with mkdir -p src/main/java/hello
on *nix systems:
└── src └── main └── java └── hello
pom.xml
xml version="1.0" encoding="UTF-8"?> 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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework gs-spring-boot-docker 0.1.0 org.springframework.boot spring-boot-starter-parent 2.0.5.RELEASE 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin
The Spring Boot Maven plugin provides many convenient features:
-
It collects all the jars on the classpath and builds a single, runnable "über-jar", which makes it more convenient to execute and transport your service.
-
It searches for the
public static void main()
method to flag as a runnable class. -
It provides a built-in dependency resolver that sets the version number to match Spring Boot dependencies. You can override any version you wish, but it will default to Boot’s chosen set of versions.
Build with your IDE
-
阅读如何导入guide到 Spring Tool Suite.
-
阅读如何使guide在IntelliJ IDEA中工作.
设置Spring Boot应用
现在你可以创建一个简单应用
src/main/java/hello/Application.java
1 package hello; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.RestController; 7 8 @SpringBootApplication 9 @RestController 10 public class Application { 11 12 @RequestMapping("/") 13 public String home() { 14 return "Hello Docker World"; 15 } 16 17 public static void main(String[] args) { 18 SpringApplication.run(Application.class, args); 19 } 20 21 }
该类被标记为@SpringBootApplication和@RestController,这意味着Spring MVC可以使用它来处理Web请求。 @RequestMapping 映射 "/" 到 home()方法,它只发送一个'Hello World'响应。 main()方法使用Spring Boot的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
去 localhost:8080 查看"Hello Docker world"消息。
Containerize It 容器化它
Docker有一个简单的Dockerfile文件格式,用于指定一个镜像的"layers"。所以让我们继续创建一个Dockerfile在我们的SpringBoot工程中:
Dockerfile
FROM openjdk:8-jdk-alpine VOLUME /tmp ARG JAR_FILE COPY ${JAR_FILE} app.jar ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
这个Dockerfile非常简单,但是当你需要运行一个没有多余装饰的Spring Boot应用程序,这些就足够了:只需要Java和一个JAR文件。 项目JAR文件作为“app.jar”添加到容器中,然后在ENTRYPOINT中执行。
我们添加了一个指向“/tmp”的VOLUME,因为这是Spring Boot应用程序默认为Tomcat创建工作目录的地方。这个用来在主机“/var/lib/docker”下创建一个临时文件,并将其链接到“/tmp”下的容器。 对于我们在此处编写的简单应用程序,此步骤是可选的,但对于需要实际写入文件系统的SpringBoot应用来说,这是必需的。
为了减少Tomcat的启动时间,我们添加了一个指向“/dev/urandom”的系统属性作为entropy。
如果您使用的是boot2docker,则需要在使用Docker命令行或使用构建工具执行任何操作之前先运行它(它在虚拟机中运行一个守护进程来为你处理工作)。
要构建镜像,您可以从社区中获取Maven或Gradle的一些工具(非常感谢Palantir和Spotify提供这些工具)。
用Maven构建一个Docker镜像
在Maven pom.xml中,你需要添加一个新插件(更多选择,请浏览 the plugin documentation):
pom.xml
<properties> <docker.image.prefix>springiodocker.image.prefix> properties> <build> <plugins> <plugin> <groupId>com.spotifygroupId> <artifactId>dockerfile-maven-pluginartifactId> <version>1.3.6version> <configuration> <repository>${docker.image.prefix}/${project.artifactId}repository> <buildArgs> <JAR_FILE>target/${project.build.finalName}.jarJAR_FILE> buildArgs> configuration> plugin> plugins> build>
配置具体化3件事:
- 仓库的镜像名,这里是 springio/gs-spring-boot-docker
- jar包的名字,暴露Maven配置作为docker的构建参数
- 可选的,镜像tag,如果没有具体配置,则以最新版本结尾。如果需要的话可以设置为artifact id。
在继续执行以下步骤(使用Docker的CLI工具)之前,请通过键入 docker ps 确保Docker正常运行。 如果收到错误消息,Docker可能没有配置正确。如果使用的是Mac, 将 $(boot2docker shellinit 2> /dev/null) 添加到.bash_profile(或类似的env-setting配置文件)并刷新shell以确保配置了正确的环境变量。
你可以使用以下命令来构建一个被标记的docker镜像:
$ ./mvnw install dockerfile:build
并且你可以用 ./mvnw dockerfile:push 命令push一个镜像到dockerhub。
您不必push新创建的Docker镜像来实际运行它。 此外,如果您不是Dockerhub上“springio”组织的成员,“push”命令将失败。 将构建配置和命令行更改为您自己的用户名而不是“springio”,以使其实际工作。
你可以在插件配置里增加一些语句,使 dockerfile:push命令在安装或部署生命周期阶段里自动运行。
pom.xml
<executions> <execution> <id>defaultid> <phase>installphase> <goals> <goal>buildgoal> <goal>pushgoal> goals> execution> executions>
用Gradle构建docker镜像
If you are using Gradle you need to add a new plugin like this:
build.gradle
buildscript {
... dependencies { ... classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.13.0') } } group = 'springio' ... apply plugin: 'com.palantir.docker' docker { dependsOn build name "${project.group}/${bootJar.baseName}" files bootJar.archivePath buildArgs(['JAR_FILE': "${bootJar.archiveName}"]) }
The configuration specifies 3 things:
-
the image name (or tag) is set up from the jar file properties, which will end up here as
springio/gs-spring-boot-docker
-
the location of the jarfile
-
a build argument for docker pointing to the jar file
You can build a tagged docker image and then push it to a remote repository with Gradle in one command:
$ ./gradlew build docker
Push之后
“docker push”将失败(除非您是Dockerhub中“springio”组织的一部分),但是如果您更改配置以匹配您自己的docker ID,那么它应该会成功,并且您将有一个新的标记,部署镜像。
你不必注册docker或者发布任何东西来运行一个docker镜像。你依然有一个本地标记的镜像,并且你可以运行它:
$ docker run -p 8080:8080 -t springio/gs-spring-boot-docker
....
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)
然后可以在http://localhost:8080上访问该应用程序(访问它并显示“Hello Docker World”)。为了确保整个过程真正有效,请将前缀从“springio”更改为其他内容(例如$ {env.USER}),然后再从构建到docker运行再次查看。
当你使用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.在这种情况下, http://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 ,ID为列表中你的应用的container id
$ docker stop 81c723d22865
81c723d22865
你也可以删除容器(它在/var/lib/docker下保存)
$ docker rm 81c723d22865
使用Spring配置
运行带Spring配置的docker镜像,只需要在Docker run命令中传递一个环境变量
$ docker run -e "SPRING_PROFILES_ACTIVE=prod" -p 8080:8080 -t springio/gs-spring-boot-docker
或
$ docker run -e "SPRING_PROFILES_ACTIVE=dev" -p 8080:8080 -t springio/gs-spring-boot-docker
Debugging the application in a Docker container
To debug the application JPDA Transport can be used. So we’ll treat the container like a remote server. To enable this feature pass a java agent settings in JAVA_OPTS variable and map agent’s port to localhost during a container run. With the Docker for Mac there is limitation due to that we can’t access container by IP without black magic usage.
$ docker run -e "JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=n" -p 8080:8080 -p 5005:5005 -t springio/gs-spring-boot-docker
Summary 总结
恭喜! 您刚刚为Spring Boot应用程序创建了一个Docker容器! 默认情况下,Spring Boot应用程序在容器内的端口8080上运行,我们使用命令行上的“-p”将其映射到主机上的对应端口。