@author StormMa
@date 2017-10-12
生命不息,奮鬥不止!
Spring Boot應用Docker化
本教程將引導你通過建立一個Docker鏡像來運行Spring Boot應用。
你將構建什麼
Docker是一個管理工具包的Linux容器,用戶可以發佈鏡像以及使用其他開發者發佈的鏡像。Docker鏡像是一個運行集裝箱化的過程,本教程將構建一個簡單的Spring Boot應用程序。
構建之前你要準備的東西
- 大約十五分鐘的時間
- 一個你最喜歡的文本編輯器或者IDE
- JDK1.8+
- Gradle2.3+或者Maven3.0+
- 你也可以直接將代碼導入你的IDE
如果你當前使用的系統不是Linux,那麼你需要一個虛擬機。通過安裝VirtualBox或者像mac的boot2docker等其他工具都可以滿足你的使用。
訪問VirtualBox下載地址選擇你的系統版本來下載VirtualBox,並且安裝運行起來。
當然你也需要安裝Docker(只能在64位機器上運行),有關詳細信息請參閱https://docs.docker.com/installation/#installation來安裝Docker到你的系統上。開始下一步之前,你要確認在你的shell上是否可以運行docker
命令,如果你使用的是boot2docker,在運行docker
命令之前你需要先啓動boot2docker。
如何完成這篇教程
像大多數的Spring系列教程 Getting Started guides,你可以從頭開始,完成每一步,也可以跳過已經熟悉的步驟。 無論哪種方式,你都可以成功。
從頭開始, 參閱使用Gradle構建.
跳過基礎部分, 執行以下操作:
- 下載並解壓本倉庫代碼,或者使用
git clone https://github.com/spring-guides/gs-spring-boot-docker.git
克隆代碼庫。 - 進入
gs-spring-boot-docker/initial
目錄 - 前往創建Spring Boot應用程序
完成以上操作之後,你可以和gs-spring-boot-docker/complete
代碼進行比對。
使用Gradle構建
首先你得安裝構建腳本. 你可以使用你喜歡的構建系統去構建Spring應用, 你需要的工具在下面都可以找到: Gradle和Maven . 如果你對Gradle和Maven都不熟悉,請參閱使用Gradle構建Java項目或者使用Maven構建Java項目.
創建目錄結構
在你當前項目工作目錄中,創建如下子目錄:
└── src
└── main
└── java
└── hello
如在Linux系統下使用mkdir -p src/main/java/hello
來創建。
創建Gradle項目文件(build.gradle)
如下是一個gradle項目文件
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.4.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
jar {
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插件 提供了很多便捷的功能:
- 它集中了
classpath
下的所有jar,並構建一個可運行的jar,這樣可以更方便地執行和發佈服務。 - 它找到
public static void main()
方法並標記該類爲可執行。 - 它提供了一個內置的依賴解析器,將應用與Spring Boot依賴的版本號進行匹配。你可以修改成你希望的版本,但它默認爲Spring Boot選擇的版本。
使用maven構建
首先你得安裝構建腳本. 你可以使用你喜歡的構建系統去構建Spring應用,你可以前往Maven官網來指導你安裝。 如果你對Maven不熟悉,請參閱使用Maven構建Java項目.
創建目錄結構
在你當前項目工作目錄中,創建如下子目錄:
└── src
└── main
└── java
└── hello
如在Linux系統下使用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>1.5.4.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插件 提供了很多便捷的功能:
- 它集中了
classpath
下的所有jar,並構建一個可運行的jar,這樣可以更方便地執行和發佈服務。 - 它找到
public static void main()
方法並標記該類爲可執行。 - 它提供了一個內置的依賴解析器,將應用與Spring Boot依賴的版本號進行匹配。你可以修改成你希望的版本,但它默認爲Spring Boot選擇的版本。
使用你的IDE構建
- 參閱Spring Tool Suite如何直接導入到你的IDE。
- 參閱IntelliJ IDEA如何來構建。
創建一個Spring Boot應用程序
現在你可以創建一個簡單的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 Docker World
。main()
方法調SpringApplication.run()
方法來啓動應用程序。
現在你可以在沒有Docker的情況下運行該應用程序。
如果你使用gradle構建的Spring Boot應用程序,執行:
./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文件格式的文件,並且使用指定的鏡像作爲基礎鏡像。接下來我們去創建一個Dockerfile在Spring Boot應用程序中。
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD target/gs-spring-boot-docker-0.1.0.jar app.jar
ENV JAVA_OPTS=""
ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar
這個Dockerfile很簡單,但是已經包含了你運行這個Spring Boot應用程序的所有東西並且沒有多餘的東西:僅僅只有Java和一個Jar文件。應用程序的jar文件(文件名爲app.jar)被添加到容器中,執行 ENTRYPOINT
我們增加了一個
VOLUME
指向”/tmp”,因爲那是Spring Boot應用程序爲Tomcat創建的默認工作目錄。作用是在你的主機”/var/lib/docker”目錄下創建一個臨時的文件,並且鏈接到容器中的”/tmp”目錄。對於簡單程序這一步是可選的,但是對於其他想要真實寫入文件系統的Spring Boot應用程序又是必選的。我們增加了一個指向”/dev/urandom”的Tomcat系統屬性來縮小Tomcat的啓動時間。
如果你使用的是boot2docker,在你使用Docker命令或者使用構建工具構建(它運行在守護進程,在虛擬機上爲你工作)之前,你必須先啓動它。
構建Docker鏡像,你可以使用一些諸如Gradle或Maven的工具或者藉助社區(強烈感謝Transmode和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.4</version>
<configuration>
<repository>${docker.image.prefix}/${project.artifactId}</repository>
</configuration>
</plugin>
</plugins>
</build>
配置指定了兩個東西:
- 鏡像名字,最終會在
springio/gs-spring-boot-docker
- 可選,鏡像的標籤,未指定默認爲
latest
,如果有需要的話,也可以指定artifact id
。
繼續下面的步驟之前(使用Docker CLI工具),輸入
docker ps
確保正常運行,如果有錯誤信息,大概因爲沒有設置其他什麼信息。如果使用的Mac,在.bash_profile
(或者是類似env-setting配置文件)最後增加$(boot2docker shellinit 2> /dev/null)
並刷新你的shell,確保更改生效。
你可以使用下面的命令來構建Docker的鏡像:
$ ./mvnw install dockerfile:build
你可以使用./mvnw dockerfile:push
命令發佈鏡像到Docker
鏡像中心去。
你不用着急發佈你剛剛製作的鏡像,如果你不是”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('se.transmode.gradle:gradle-docker:1.2')
}
}
group = 'springio'
...
apply plugin: 'docker'
task buildDocker(type: Docker, dependsOn: build) {
applicationName = jar.baseName
dockerfile = file('Dockerfile')
doFirst {
copy {
from jar
into "${stageDir}/target"
}
}
}
該配置指定了三個東西:
- 從jar文件屬性設置鏡像名字(或標籤),最終會出現在springio/gs-spring-boot-docker
- Dockerfile的位置
- 複製Maven構建目錄中的jar文件到相同的目錄,這樣我們就可以Maven或者Gradle構建鏡像而且使用同一個Dockerfile
。
你可以使用一下命令構建鏡像並且發佈到遠程倉庫:
$ ./gradlew build buildDocker
發佈之後
對你來說”Docker鏡像發佈”會失敗(除非你在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}
並且重新構建運行)。
如果你使用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主機而不是本地主機的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 -jar /app.jar" 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 Profiles
運行你新制作的鏡像使用Spring Profiles,和運行docker命令傳入一個環境變量一樣簡單。
$ 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設置JAVA_OPTS變量和代理的端口映射到本地主機在一個容器中運行。對於Docker for Mac由於有限制,我們不能通過IP訪問容器因爲沒有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
總結
恭喜你!剛剛爲Spring Boot應用程序創建了Docker容器!Spring Boot應用程序在容器中運行默認端口8080映射到相同的宿主機端口使用”-p”參數。
另請參閱
以下教程也可能是有用的:
想寫一篇新的教程?或者爲舊教程出力?查看我們的貢獻參考