1. 程式人生 > >Spring系列學習之構建Spring Boot 的Docker容器應用

Spring系列學習之構建Spring Boot 的Docker容器應用

英文原文:https://spring.io/guides/gs/spring-boot-docker/

目錄

你要構建什麼

你需要什麼

如何完成本指南

Gradle構建

Maven構建

IDE構建

設定一個Spring Boot應用程式

應用容器化

使用Maven構建Docker映象

使用Gradle構建Docker映象

Push推送映象之後

使用Spring Profiles配置

在Docker容器中除錯應用程式

總結

更多


本指南將指導您構建執行Spring Boot應用程式的Docker映象的過程。


你要構建什麼


Docker

是一個具有“社交”方面的Linux容器管理工具包,允許使用者釋出容器影象並使用其他人釋出的容器影象。 Docker映象是執行容器化過程的配方,在本指南中,我們將為簡單的Spring啟動應用程式構建一個。

你需要什麼

  •      大約15分鐘
  •      最喜歡的文字編輯器或IDE
  •      JDK 1.8或更高版本
  •      Gradle 4+或Maven 3.2+
  •      您還可以將程式碼直接匯入IDE:
    Spring Tool Suite (STS) 
    IntelliJ IDEA

如果您不使用Linux計算機,則需要虛擬化伺服器。 通過安裝VirtualBox,Mac的boot2docker等其他工具可以為您無縫管理。 訪問VirtualBox的下載站點,選擇適合您機器的版本。 下載並安裝。 不要擔心實際執行它。

您還需要Docker,它只能在64位計算機上執行。 有關為計算機設定Docker的詳細資訊,請參閱https://docs.docker.com/installation/#installation。 在繼續之前,請驗證您是否可以從shell執行docker命令。 如果您使用的是boot2docker,則需要先執行它。 

 

如何完成本指南


與大多數Spring入門指南一樣,您可以從頭開始並完成每個步驟,或者您可以繞過您已熟悉的基本設定步驟。 無論哪種方式,您最終都會使用工作程式碼。

要從頭開始,請繼續使用Gradle構建

要跳過基礎知識,請執行以下操作: 

  •      下載並解壓縮本指南的源儲存庫,或使用Git克隆它:
git clone https://github.com/spring-guides/gs-spring-boot-docker.git

 完成後,您可以根據gs-spring-boot-docker/complete中的程式碼檢查結果。

Gradle構建

首先,設定一個基本的構建指令碼。 在使用Spring構建應用程式時,您可以使用任何您喜歡的構建系統,但此處包含了使用Gradle和Maven所需的程式碼。 如果您不熟悉這兩者,請參閱使用Gradle構建Java專案或使用Maven構建Java專案。
建立目錄結構

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

在您選擇的專案目錄中,建立以下子目錄結構; 例如,在* nix系統上使用mkdir -p src / main / java / hello:

建立Gradle構建檔案

下面是最初的Gradle構建檔案。

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")
}

Spring Boot gradle外掛提供了許多方便的功能:

  •      它收集類路徑上的所有jar並構建一個可執行的“über-jar”,這使得執行和傳輸服務更加方便。
  •      它搜尋public static void main()方法以標記為可執行的類。
  •      它提供了一個內建的依賴項解析器,它設定版本號以匹配Spring Boot依賴項。 您可以覆蓋任何您希望的版本,但它將預設為Boot的所選版本集。 

Maven構建

首先,設定一個基本的構建指令碼。 在使用Spring構建應用程式時,您可以使用任何您喜歡的構建系統,但此處包含了使用Maven所需的程式碼。 如果您不熟悉Maven,請參閱使用Maven構建Java專案。
建立目錄結構

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

在您選擇的專案目錄中,建立以下子目錄結構; 例如,在* nix系統上使用mkdir -p 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>

Spring Boot Maven外掛提供了許多方便的功能:

 

  •      它收集類路徑上的所有jar並構建一個可執行的“über-jar”,這使得執行和傳輸服務更加方便。
  •      它搜尋public static void main()方法以標記為可執行的類。
  •      它提供了一個內建的依賴項解析器,它設定版本號以匹配Spring Boot依賴項。 您可以覆蓋任何您希望的版本,但它將預設為Boot的所選版本集。

IDE構建

閱讀如何將本指南直接匯入Spring Tool Suite

閱讀IntelliJ IDEA中如何使用本指南。

設定一個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檔案作為“app.jar”新增到容器中,然後在ENTRYPOINT中執行。

我們添加了一個指向“/tmp”的VOLUME(對映路徑),因為這是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引數,指向我們已經解壓縮jar的目錄。 如果我們做對了,它已經包含一個BOOT-INF/lib目錄,其中包含依賴項jars,以及一個帶有應用程式類的BOOT-INF / classes目錄。 請注意,我們正在使用應用程式自己的主類hello.Application(這比使用jar啟動器提供的間接更快)。

如果您使用的是boot2docker,則需要在使用Docker命令列或使用構建工具執行任何操作之前先執行它(它執行一個守護程序來處理虛擬機器中的工作)。

要構建映象,您可以從社群使用Maven或Gradle的一些工具(非常感謝PalantirSpotify提供這些工具)。

使用Maven構建Docker映象

在Maven 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的構建引數。 可以使用外掛配置的<buildArgs />指定它。
  •      影象標記,如果未指定則最終為“最新”。 它可以使用<tag/>元素設定

在繼續執行以下步驟(使用Docker的CLI工具)之前,請通過鍵入docker ps確保Docker正常執行。 如果收到錯誤訊息,可能無法正確設定某些內容。 用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

你可以用./mvnw dockerfile:push將影象推送到dockerhub。

您不必將新建立的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檔案的任務
  •      影象名稱(或標記)是從jar檔案屬性設定的,最終將作為springio / gs-spring-boot-docker
  •      解壓縮的jar檔案的位置,我們可以在Dockerfile中對其進行硬編碼
  •      docker指向jar檔案的構建引數

您可以構建標記的docker映象,然後使用Gradle將其推送到遠端儲存庫:

$ ./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

並再次關閉它你可以停靠與上面列表中的容器ID停止 docker stop ${container_id}(你的將是不同的):

$ docker stop 81c723d22865
81c723d22865

如果您願意,還可以在完成後刪除容器(它在/var/lib/docker下的檔案系統中儲存):

$ docker rm 81c723d22865

使用Spring Profiles配置

使用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。 使用Docker for Mac存在限制,因為我們無法通過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創作公共許可證。