本文章將為您完成構建用於執行Spring Boot應用程式的Docker映像的過程。我們從基本開始,Dockerfile然後進行一些調整。然後,我們展示了幾個使用build外掛(適用於Maven和Gradle)而不是的選項docker。
在Docker上還有一個Topical Guide,它涵蓋了我們在這裡更廣泛選擇的更多範圍。
你會建立什麼Docker是具有“社交”方面的Linux容器管理工具包,可讓使用者釋出容器映像並使用他人釋出的映像。Docker映像是執行容器化程序的方法。在本指南中,我們為一個簡單的Spring引導應用程式構建一個。
您將需要什麼花費約15分鐘最喜歡的文字編輯器或IDEJDK 1.8或更高版本Gradle 4+或Maven 3.2+您還可以將程式碼直接匯入到IDE中:彈簧工具套件(STS)IntelliJ IDEA如果不使用Linux計算機,則需要虛擬伺服器。如果安裝VirtualBox,其他工具(如Mac)boot2docker可以為您無縫管理它。訪問VirtualBox的下載站點,併為您的計算機選擇版本。下載並安裝。不必擔心實際執行它。
您還需要僅在64位計算機上執行的Docker。有關為您的機器設定Docker的詳細資訊,請參見https://docs.docker.com/installation/#installation。在繼續進行之前,請確認您可以docker從外殼執行命令。如果你使用boot2docker,你需要執行第一。
從Spring Initializr開始對於所有Spring應用程式,您應該從Spring Initializr開始。Initializr提供了一種快速的方法來提取應用程式所需的所有依賴項,併為您完成了許多設定。該示例僅需要Spring Web依賴項。
您可以直接從Spring Initializr獲取具有必要依賴項的Maven構建檔案。以下清單顯示了pom.xml選擇Maven時建立的檔案:
plugins { id 'org.springframework.boot' version '2.4.2' 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()}
設定一個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@RestControllerpublic class Application { @RequestMapping("/") public String home() { return "Hello Docker World"; } public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
該類被標記為a@SpringBootApplication和a @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軟體包&& java -jar target / gs-spring-boot-docker-0.1.0.jar
然後轉到localhost:8080以檢視“ Hello Docker World”訊息。
容器化Docker具有一種簡單的“ Dockerfile”檔案格式,可用於指定映像的“層”。在您的Spring Boot專案中建立以下Dockerfile:
例子1. Dockerfile
FROM openjdk:8-jdk-alpineARG JAR_FILE=target/*.jarCOPY ${JAR_FILE} app.jarENTRYPOINT ["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的主題指南將更詳細地討論該主題。
為了減少Tomcat的啟動時間,我們曾經添加了一個系統屬性/dev/urandom,該屬性指向熵源。對於JDK 8或更高版本,這不再是必需的。
使用使用者特權執行應用程式有助於減輕某些風險(例如,參見StackExchange上的執行緒)。因此,對的一項重要改進Dockerfile是以非root使用者身份執行應用程式:
例子2. Dockerfile
FROM openjdk:8-jdk-alpineRUN addgroup -S spring && adduser -S spring -G springUSER spring:springARG JAR_FILE=target/*.jarCOPY ${JAR_FILE} app.jarENTRYPOINT ["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-alpineRUN addgroup -S spring && adduser -S spring -G springUSER spring:springARG DEPENDENCY=target/dependencyCOPY ${DEPENDENCY}/BOOT-INF/lib /app/libCOPY ${DEPENDENCY}/META-INF /app/META-INFCOPY ${DEPENDENCY}/BOOT-INF/classes /appENTRYPOINT ["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的開源工具,該工具具有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示例中的A失敗(除非您是Dockerhub的“ springio”組織的一部分)。但是,如果您更改配置以匹配您自己的Docker ID,則配置應成功。然後,您將獲得一個新的已標記的已部署映像。
您不必在docker上註冊或釋出任何內容即可執行在本地構建的docker映像。如果您是使用Docker構建的(透過命令列或Spring Boot),則仍然有一個本地標記的映像,您可以像這樣執行它:
$ docker run -p 8080:8080 -t springio/gs-spring-boot-dockerContainer 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上找到該應用程式(請訪問並顯示“ 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 psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES81c723d22865 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 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配置檔案執行相同的操作:
泊塢窗執行-e“ SPRING_PROFILES_ACTIVE = dev” -p 8080:8080 -t springio / gs-spring-boot-docker
在Docker容器中除錯應用程式
要除錯該應用程式,可以使用JPDA Transport。我們將容器視為遠端伺服器。要啟用此功能,請在JAVA_OPTS變數中傳遞Java代理設定,並在容器執行期間將代理的埠對映到localhost。使用Mac的Docker有一個侷限性,因為如果沒有使用黑魔法,我們不能透過IP訪問容器。
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在命令列上使用該埠將其對映到主機上的同一埠。