本指南将引导您完成构建用于运行Spring Boot应用程序的Docker映像的过程。

你会建立什么

Docker是具有“社交”方面的Linux容器管理工具箱,允许用户发布容器映像并使用其他人发布的映像。Docker镜像是运行容器化进程的秘诀,在本指南中,我们将为一个简单的Spring引导应用程序构建一个镜像。

在Docker上还有一个主题指南 ,其中涵盖了我们在此处拥有的更多选择,并且更加详细。

你需要什么

如果您不使用Linux机器,则需要一个虚拟服务器。通过安装VirtualBox,其他工具(如Mac的boot2docker)可以为您无缝管理它。访问VirtualBox的下载站点,并为您的计算机选择版本。下载并安装。不用担心实际运行它。

您还需要仅在64位计算机上运行的Docker 。有关为您的机器设置Docker的详细信息,请参见https://docs.docker.com/installation/#installation 。在继续之前,请确认您可以运行docker从外壳命令。如果你正在使用boot2docker则需要运行。

如何完成本指南

像大多数Spring 入门指南一样,您可以从头开始并完成每个步骤,也可以绕过您已经熟悉的基本设置步骤。无论哪种方式,您最终都可以使用工作代码。

从头开始 ,请继续使用Gradle构建

跳过基础知识 ,请执行以下操作:

完成后 ,您可以根据中的代码检查结果gs-spring-boot-docker/complete

用Gradle构建

用Gradle构建

首先,您设置一个基本的构建脚本。在使用Spring构建应用程序时,可以使用任何喜欢的构建系统,但是此处包含使用GradleMaven所需的代码。如果您都不熟悉,请参阅使用Gradle 构建Java项目使用Maven构建Java项目

创建目录结构

在您选择的项目目录中,创建以下子目录结构;例如, mkdir -p src/main/java/hello在* nix系统上:

└── src
    └── main
        └── java
            └── hello

创建一个Gradle构建文件

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.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")
}

Spring Boot gradle插件提供了许多方便的功能:

  • 它收集类路径上的所有jar,并构建一个可运行的单个“über-jar”,这使执行和传输服务更加方便。

  • 它搜索public static void main()标记为可运行类的方法。

  • 它提供了一个内置的依赖项解析器,用于设置版本号以匹配Spring Boot依赖项 。您可以覆盖所需的任何版本,但是它将默认为Boot选择的一组版本。

用Maven构建

用Maven构建

首先,您设置一个基本的构建脚本。使用Spring构建应用程序时,可以使用任何喜欢的构建系统,但是此处包含了使用Maven所需的代码。如果您不熟悉Maven,请参阅使用Maven 构建Java项目

创建目录结构

在您选择的项目目录中,创建以下子目录结构;例如, mkdir -p src/main/java/hello在* nix系统上:

└── 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 https://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.1.6.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>

Spring Boot Maven插件提供了许多方便的功能:

  • 它收集类路径上的所有jar,并构建一个可运行的单个“über-jar”,这使执行和传输服务更加方便。

  • 它搜索public static void main()标记为可运行类的方法。

  • 它提供了一个内置的依赖项解析器,用于设置版本号以匹配Spring Boot依赖项 。您可以覆盖所需的任何版本,但是它将默认为Boot选择的一组版本。

使用您的IDE进行构建

使用您的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以查看“ Hello Docker World”消息。

容器化

Docker具有一种简单的“ Dockerfile”文件格式,可用于指定映像的“层”。因此,让我们继续并在我们的Spring Boot项目中创建一个Dockerfile:

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文件是ADDed以“ app.jar”的形式添加到容器中,然后在ENTRYPOINT

我们添加了一个VOLUME指向“ / tmp”,因为默认情况下Spring Boot应用程序在此处为Tomcat创建工作目录。效果是在主机上的“ / var / lib / docker”下创建一个临时文件,并将其链接到“ / tmp”下的容器。对于我们在此处编写的简单应用程序,此步骤是可选的,但对于其他Spring Boot应用程序,如果它们需要实际在文件系统中进行写操作,则可能是必需的。
为了减少Tomcat的启动时间,我们添加了一个系统属性,该属性指向“ / dev / urandom”作为熵的来源。如果您使用的是Tomcat(或任何其他Web服务器)的“标准”版本,则对于较新版本的Spring Boot而言,这不是必需的。

为了充分利用Spring Boot胖jar文件中依赖项和应用程序资源之间的清晰分隔,我们将使用稍微不同的Dockerfile实现:

Dockerfile

FROM openjdk:8-jdk-alpine
VOLUME /tmp
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指向我们已将胖子罐解压缩的目录的参数。如果我们做对了,它已经包含一个BOOT-INF/lib目录中包含依赖项jar,以及一个BOOT-INF/classes目录中包含应用程序类。请注意,我们正在使用应用程序自己的主类hello.Application (这比使用胖子启动器提供的间接调用要快)。

如果你使用,你需要你的泊坞窗命令行或构建工具做任何事情之前, 运行它boot2docker(它运行的守护进程来处理你在虚拟机的工作)。

要构建图像,您可以使用社区中的一些Maven或Gradle工具(非常感谢PalantirSpotify使这些工具可用)。

使用Maven构建Docker映像

在行家中pom.xml您应该添加一个这样的新插件(有关更多选项,请参见插件文档 ):

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.4.9</version>
            <configuration>
                <repository>${docker.image.prefix}/${project.artifactId}</repository>
            </configuration>
        </plugin>
    </plugins>
</build>

该配置指定1项强制性的内容:具有映像名称的存储库,它将在此处最终显示为springio/gs-spring-boot-docker

其他一些属性是可选的:

  • 将要解开胖子jar的目录的名称,将Maven配置作为docker的构建参数公开。可以使用插件配置。

  • 图像标签,如果未指定,则最终显示为“最新”。可以用元件,

在继续执行以下步骤(使用Docker的CLI工具)之前,请通过键入以下内容确保Docker正常运行docker ps 。如果收到错误消息,则可能未正确设置某些内容。使用Mac?加$(boot2docker shellinit 2> /dev/null)到你的底部.bash_profile (或类似的env-setting配置文件)并刷新您的Shell,以确保配置了正确的环境变量。

为了确保在创建docker映像之前解压jar,我们为依赖插件添加了一些配置:

pom.xml

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>unpack</id>
            <phase>package</phase>
            <goals>
                <goal>unpack</goal>
            </goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>${project.artifactId}</artifactId>
                        <version>${project.version}</version>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

您可以使用以下命令行来构建带标签的docker映像:

$ ./mvnw install dockerfile:build

您可以使用以下方式将映像推送到dockerhub ./mvnw dockerfile: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映像

如果您使用的是Gradle,则需要添加一个新的插件,如下所示:

build.gradle

buildscript {
    ...
    dependencies {
        ...
        classpath('gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.13.0')
    }
}

group = 'springio'

...
apply plugin: 'com.palantir.docker'

task unpack(type: Copy) {
    dependsOn bootJar
    from(zipTree(tasks.bootJar.outputs.files.singleFile))
    into("build/dependency")
}
docker {
    name "${project.group}/${bootJar.baseName}"
    copySpec.from(tasks.unpack.outputs).into("dependency")
    buildArgs(['DEPENDENCY': "dependency"])
}

该配置指定4件事:

  • 解压缩胖子文件的任务

  • 图像名称(或标签)是从jar文件属性中设置的,最终将显示为springio/gs-spring-boot-docker

  • 解压缩的jarfile的位置,我们可以在其中进行硬编码Dockerfile

  • docker指向jar文件的构建参数

您可以构建标记的docker映像,然后使用Gradle在一个命令中将其推送到远程存储库:

$ ./gradlew build docker

推后

“ 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 run再次进行检查。

当将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(您会有所不同):

$ 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

在Docker容器中调试应用程序

要调试应用程序,可以使用JPDA Transport 。因此,我们将容器视为远程服务器。要启用此功能,请在容器运行期间在JAVA_OPTS变量中传递Java代理设置,并将代理的端口映射到localhost。使用MacDocker存在局限性,因为如果不使用黑魔法 ,我们不能通过IP访问容器。

$ 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

摘要

恭喜你!您刚刚为Spring Boot应用程序创建了Docker容器!Spring Boot应用程序默认在容器内的端口8080上运行,我们在命令行上使用“ -p”将其映射到主机上的同一端口。

也可以看看

以下指南也可能会有所帮助:

是否要编写新指南或为现有指南做出贡献?查看我们的贡献准则

所有指南均以代码的ASLv2许可证和写作的Attribution,NoDerivatives创作共用许可证发布