# Docker的Spring Boot
本指南將引導您完成構建 的 的過程 [Docker](https://docker.com) 用于運行Spring Boot應用程序 映像 。 我們從一個基本的開始 `Dockerfile`并進行一些調整。 然后,我們展示幾個使用構建插件的選項(針對Maven和Gradle),而不是 `docker`。 這是一個“入門”指南,因此范圍僅限于一些基本需求。 如果要構建供生產使用的容器映像,則需要考慮很多因素,并且不可能在簡短的指南中將它們全部涵蓋。
還有一個 在Docker上 Topical Guide ,它涵蓋了我們在這里擁有的更多選擇,并且更加詳細。
## 你會建立什么
[Docker](https://docker.com) 是具有“社交”方面的Linux容器管理工具包,可讓用戶發布容器映像并使用其他人發布的映像。 Docker映像是運行容器化進程的秘訣。 在本指南中,我們為一個簡單的Spring引導應用程序構建一個。
## 您將需要什么
* 約15分鐘
* 最喜歡的文本編輯器或IDE
* [JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 或更高版本
* [Gradle 4+](http://www.gradle.org/downloads) 或 [Maven 3.2+](https://maven.apache.org/download.cgi)
* 您還可以將代碼直接導入到IDE中:
* [彈簧工具套件(STS)](https://spring.io/guides/gs/sts)
* [IntelliJ IDEA](https://spring.io/guides/gs/intellij-idea/)
如果您不使用Linux機器,則需要一個虛擬服務器。 如果您安裝VirtualBox,則其他工具(例如Mac的 `boot2docker`可以為您無縫管理。 訪問 [VirtualBox的下載站點,](https://www.virtualbox.org/wiki/Downloads) 并為您的計算機選擇版本。 下載并安裝。 不必擔心實際運行它。
您還需要 [Docker](https://docker.com) 僅在64位計算機上運行的 。 有關 請參見 [https://docs.docker.com/installation/#installation](https://docs.docker.com/installation/#installation) 為您的機器設置Docker的詳細信息, 。 在繼續進行之前,請確認您可以運行 `docker`從外殼命令。 如果您使用 `boot2docker`,你需要運行 **第一** 。
## 從Spring Initializr開始
如果您使用Maven,請訪問 [Spring Initializr](https://start.spring.io/#!type=maven-project&language=java&platformVersion=2.4.4.RELEASE&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=spring-boot-docker&name=spring-boot-docker&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.spring-boot-docker&dependencies=web) 以生成具有所需依賴項的新項目(Spring Web)。
以下清單顯示了 `pom.xml` 選擇Maven時創建的文件:
~~~
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-docker</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-docker</name>
<description>Demo project for Spring Boot</description>
<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>
~~~
如果使用Gradle,請訪問 [Spring Initializr](https://start.spring.io/#!type=gradle-project&language=java&platformVersion=2.4.4.RELEASE&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=spring-boot-docker&name=spring-boot-docker&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.spring-boot-docker&dependencies=web) 以生成具有所需依賴項的新項目(Spring Web)。
以下清單顯示了 `build.gradle` 選擇Gradle時創建的文件:
~~~
plugins {
id 'org.springframework.boot' version '2.4.4'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
~~~
### 手動初始化(可選)
如果要手動初始化項目而不是使用前面顯示的鏈接,請按照以下步驟操作:
1. 導航到 [https://start.spring.io](https://start.spring.io) 。 該服務提取應用程序所需的所有依賴關系,并為您完成大部分設置。
2. 選擇Gradle或Maven以及您要使用的語言。 本指南假定您選擇了Java。
3. 單擊 **Dependencies,** 然后選擇 **Spring Web** 。
4. 點擊 **生成** 。
5. 下載生成的ZIP文件,該文件是使用您的選擇配置的Web應用程序的存檔。
如果您的IDE集成了Spring Initializr,則可以從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](http://localhost:8080) 以查看“ Hello Docker World”消息。
## 容器化
Docker具有一種簡單的 [“ Dockerfile”](https://docs.docker.com/reference/builder/) 文件格式,用于指定映像的“層”。 在您的Spring Boot項目中創建以下Dockerfile:
例子1. Dockerfile
~~~
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
~~~
如果使用Gradle,則可以使用以下命令運行它:
~~~
docker build --build-arg JAR_FILE=build/libs/\*.jar -t springio/gs-spring-boot-docker .
~~~
如果使用Maven,則可以使用以下命令運行它:
~~~
docker build -t springio/gs-spring-boot-docker .
~~~
該命令生成一個圖像并將其標記為 `springio/gs-spring-boot-docker`.
這個Dockerfile非常簡單,但是只要運行Java Boot和JAR文件,便可以輕松運行Spring Boot應用程序。 構建會創建一個spring用戶和spring組來運行該應用程序。 然后將其復制(通過 `COPY` 命令)將項目JAR文件放入容器中,如下所示: `app.jar`,它在 `ENTRYPOINT`。 Dockerfile的數組形式 `ENTRYPOINT`使用,以便沒有外殼包裝Java進程。 的 [有關Docker 主題指南](https://spring.io/guides/topicals/spring-boot-docker) 對該主題進行了更詳細的介紹。
為了減少 Tomcat的啟動時間 ,我們曾經添加了一個指向 /dev/urandom作為熵的來源。 對于 這不再是必需的 JDK 8或更高版本, 。
使用用戶特權運行應用程序有助于減輕某些風險(例如,參見 [StackExchange上的線程](https://security.stackexchange.com/questions/106860/can-a-root-user-inside-a-docker-lxc-break-the-security-of-the-whole-system) )。 因此,對 `Dockerfile` 將以非root用戶身份運行該應用程序:
例子2. Dockerfile
~~~
FROM openjdk:8-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
~~~
生成和運行應用程序時,您可以在應用程序啟動日志中看到用戶名:
~~~
docker build -t springio/gs-spring-boot-docker .
docker run -p 8080:8080 springio/gs-spring-boot-docker
~~~
注意 `started by` 在第一 `INFO` 日志條目:
~~~
:: Spring Boot :: (v2.2.1.RELEASE)
2020-04-23 07:29:41.729 INFO 1 --- [ main] hello.Application : Starting Application on b94c86e91cf9 with PID 1 (/app started by spring in /)
...
~~~
而且,Spring Boot胖JAR文件中的依賴項和應用程序資源之間有明確的分隔,我們可以利用這一事實來提高性能。 關鍵是在容器文件系統中創建層。 這些層在構建時和運行時(在大多數運行時)中都被緩存,因此我們希望將最頻繁更改的資源(通常是應用程序本身中的類和靜態資源)分層放置 *在* 更改速度較慢的資源之后。 因此,我們使用稍微不同的Dockerfile實現:
例子3. Dockerfile
~~~
FROM openjdk:8-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
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解壓縮到的目錄的參數。 要使用 `DEPENDENCY` 參數與Gradle一起運行以下命令:
~~~
mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*.jar)
~~~
要使用 `DEPENDENCY` Maven參數,請運行以下命令:
~~~
mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)
~~~
如果我們做對了,它已經包含一個 `BOOT-INF/lib` 包含依賴關系JAR的目錄,以及一個 `BOOT-INF/classes`目錄中包含應用程序類。 注意,我們使用了應用程序自己的主類: `hello.Application`。 (這比使用胖JAR啟動器提供的間接訪問要快。)
分解JAR文件可能會導致類路徑 順序 在運行時的 不同 。 行為良好且編寫良好的應用程序不應該在意這一點,但是如果不仔細管理依賴項,則可能會看到行為更改。
如果您使用 boot2docker,你需要運行它 首先 ,你與泊塢窗命令行或構建工具做任何事情之前(它運行的守護進程來處理你在虛擬機的工作)。
從Gradle構建中,您需要在Docker命令行中添加顯式構建參數:
~~~
docker build --build-arg DEPENDENCY=build/dependency -t springio/gs-spring-boot-docker .
~~~
要在Maven中構建映像,可以使用更簡單的Docker命令行:
~~~
docker build -t springio/gs-spring-boot-docker .
~~~
當然,如果您僅使用Gradle,則可以更改 Dockerfile 設為默認值 DEPENDENCY 與解壓縮的檔案的位置匹配。
您可能不想使用Docker命令行進行構建,而是要使用構建插件。 Spring Boot支持使用自己的構建插件從Maven或Gradle構建容器。 Google還提供了一個名為 開源工具 工具 [Jib的](https://github.com/GoogleContainerTools/jib) ,該 具有Maven和Gradle插件。 關于此方法,最有趣的事情可能是您不需要 `Dockerfile`。 您可以使用與從中獲得的相同的標準容器格式來構建映像 `docker build`。 此外,它還可以在未安裝docker的環境中運行(在構建服務器中并不罕見)。
默認情況下,默認buildpacks生成的映像不會以root用戶身份運行您的應用程序。 請參閱 的配置指南 Gradle 或 Maven 有關如何更改默認設置, 。
### 使用Gradle構建Docker映像
您可以在一個命令中使用Gradle構建標記的docker映像:
~~~
./gradlew bootBuildImage --imageName=springio/gs-spring-boot-docker
~~~
### 使用Maven構建Docker映像
為了快速入門,您可以運行Spring Boot映像生成器而無需更改您的 `pom.xml` (請記住, `Dockerfile`,如果它仍然存在,則將其忽略):
~~~
./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=springio/gs-spring-boot-docker
~~~
要推送到Docker注冊表,您需要具有推送權限,默認情況下您沒有該權限。 將圖像前綴更改為您自己的Dockerhub ID,然后 `docker login` 確保在運行Docker之前已通過身份驗證。
### 推后
一個 `docker push`在該示例中失敗(除非您是Dockerhub的“ springio”組織的成員)。 但是,如果您更改配置以匹配您自己的Docker ID,則配置應會成功。 然后,您將獲得一個新的已標記的已部署映像。
您不必在docker上注冊或發布任何內容即可運行在本地構建的docker映像。 如果您是使用Docker構建的(通過命令行或Spring Boot),則仍然有一個本地標記的映像,您可以像這樣運行它:
~~~
$ docker run -p 8080:8080 -t springio/gs-spring-boot-docker
Container memory limit unset. Configuring JVM for 1G container.
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=86381K -XX:ReservedCodeCacheSize=240M -Xss1M -Xmx450194K (Head Room: 0%, Loaded Class Count: 12837, Thread Count: 250, Total Memory: 1073741824)
....
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)
~~~
CF內存計算器在運行時用于調整JVM的大小以適合容器。
然后可以在 上找到該應用程序 [http:// localhost:8080](http://localhost:8080) (請訪問并顯示“ Hello Docker World”)。
當將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(在本例中為 https://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 goofy_brown
81c723d22865
~~~
如果您愿意,還可以刪除容器(容器保存在文件系統中的某個位置,位于 `/var/lib/docker`)完成后:
~~~
docker rm goofy_brown
~~~
### 使用Spring配置文件
使用Spring配置文件運行剛創建的Docker映像就像將環境變量傳遞給Docker run命令一樣簡單(對于 `prod` 輪廓):
~~~
docker run -e "SPRING_PROFILES_ACTIVE=prod" -p 8080:8080 -t springio/gs-spring-boot-docker
~~~
您可以對 `dev` 輪廓:
~~~
docker run -e "SPRING_PROFILES_ACTIVE=dev" -p 8080:8080 -t springio/gs-spring-boot-docker
~~~
### 在Docker容器中調試應用程序
要調試該應用程序,可以使用 [JPDA Transport](https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/conninv.html#Invocation) 。 我們將容器視為遠程服務器。 要啟用此功能,請在 `JAVA_OPTS`變量,并在容器運行期間將代理的端口映射到localhost。 使用 [Mac的Docker](https://www.docker.com/products/docker#/mac) 有一個局限性,因為如果沒有 我們不能通過IP訪問容器 [魔術的使用,](https://github.com/docker/for-mac/issues/171) 。
~~~
docker run -e "JAVA_TOOL_OPTIONS=-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` 在命令行上。
- springboot概述
- springboot構建restful服務
- spring構建一個RESTful Web服務
- spring定時任務
- 消費RESTful Web服務
- gradle構建項目
- maven構建項目
- springboot使用jdbc
- springboot應用上傳文件
- 使用LDNA驗證用戶
- 使用 spring data redis
- 使用 spring RabbitTemplate消息隊列
- 用no4j訪問nosql數據庫
- springboot驗證web表單
- Spring Boot Actuator構j建服務
- 使用jms傳遞消息
- springboot創建批處理服務
- spring security保護web 安全
- 在Pivotal GemFire中訪問數據
- 使用Spring Integration
- 使用springboot jpa進行數據庫操作
- 數據庫事務操作
- 操作mongodb
- springmvc+tymleaf創建web應用
- 將Spring Boot JAR應用程序轉換為WAR
- 創建異步服務
- spring提交表單
- 使用WebSocket構建交互式Web應用程序
- 使用REST訪問Neo4j數據
- jquery消費restful
- springboot跨域請求
- 消費SOAP Web服務
- springboot使用緩存
- 使用Vaadin創建CRUD UI
- 使用REST訪問JPA數據
- 使用REST訪問Pivotal GemFire中的數據
- 構建soap服務
- 使用rest訪問mongodb數據
- 構建springboot應用docker鏡像
- 從STS部署到Cloud Foundry
- springboot測試web應用
- springboot訪問mysql
- springboot編寫自定義模塊并使用
- 使用Google Cloud Pub / Sub進行消息傳遞
- 構建反應式RESTful Web服務
- 使用Redis主動訪問數據
- Spring Boot 部署到Kubernetes
- 使用反應式協議R2DBC訪問數據
- Spring Security架構
- spring構建Docker鏡像詳解
- Spring Boot和OAuth2
- springboot應用部署到k8s
- spring構建rest服務詳解