Spring Boot with Docker

Posted _Yufan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot with Docker相关的知识,希望对你有一定的参考价值。

翻译自:https://spring.io/guides/gs/spring-boot-docker/

Spring Boot with Docker

这篇教程带你一步步构建一个Docker镜像用来运行一个Spring Boot应用。

你将要构建

Docker是一个具有“社交”方面的Linux容器管理工具集,允许用户发表容器镜像并使用其他用户发表的容器镜像。一个Docker镜像是一个用来运行容器化进程的配方,在本教程中我们将构建一个简单的SpringBoot应用。

你将需要

如果您不使用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.

对于跳过基础,如下:

  • 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"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-spring-boot-docker</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>

    <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>

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

设置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>springio</docker.image.prefix>
</properties>
<build>
    <plugins>
        <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>dockerfile-maven-plugin</artifactId>
            <version>1.3.6</version>
            <configuration>
                <repository>${docker.image.prefix}/${project.artifactId}</repository>
                <buildArgs>
                    <JAR_FILE>target/${project.build.finalName}.jar</JAR_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>default</id>
        <phase>install</phase>
        <goals>
            <goal>build</goal>
            <goal>push</goal>
        </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”将其映射到主机上的对应端口。

以上是关于Spring Boot with Docker的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot with docker 无法找到请求目标错误的有效认证路径

Spring Boot Devtools 自动重启错误

使用 Spring Boot 代码运行 docker 容器

Spring Boot - Error creating bean with name 'dataSource' defined in class path resource(示例代码

Spring Security with Boot

Spring Boot Caching with Redis - 反序列化问题