Docker 有一個簡單的 “Dockerfile” 檔案格式,用於指定映象的“層”。在您的 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"]
docker build --build-arg JAR_FILE=build/libs/\*.jar -t springio/gs-spring-boot-docker .
docker build -t springio/gs-spring-boot-docker .
此命令會構建一個映象並將其標記為 springio/gs-spring-boot-docker
。
這個 Dockerfile 非常簡單,但它是執行一個沒有額外依賴的 Spring Boot 應用所需的全部:只需要 Java 和一個 JAR 檔案。構建過程會建立一個 spring 使用者和一個 spring 組來執行應用。然後將專案 JAR 檔案複製(透過 COPY
命令)到容器中作為 app.jar
,並在 ENTRYPOINT
中執行。Dockerfile ENTRYPOINT
的陣列形式被使用,以便 Java 程序沒有 shell 包裝。關於 Docker 的專題指南更詳細地討論了此主題。
示例 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
請注意第一個 INFO
日誌條目中的 started by
:: 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 fat 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
引數,指向我們解壓 fat 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)
如果我們做對了,它會包含一個包含依賴 JAR 的 BOOT-INF/lib
目錄,以及一個包含應用類的 BOOT-INF/classes
目錄。請注意,我們使用應用自己的主類:hello.Application
。(這比使用 fat JAR 啟動器提供的間接方式更快。)
|
解壓 JAR 檔案可能導致執行時類路徑順序不同。一個行為良好且編寫良好的應用不應該關心這一點,但如果依賴項管理不仔細,您可能會看到行為變化。 |
|
如果您使用 boot2docker ,您需要首先執行它,然後才能使用 Docker 命令列或構建工具(它會在虛擬機器中執行一個守護程序為您處理工作)。 |
從 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 映象
為了快速開始,您甚至無需修改 pom.xml
即可執行 Spring Boot 映象生成器(請記住,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)
|
buildpack 在執行時使用記憶體計算器來調整 JVM 以適應容器大小。 |
|
在使用帶有 boot2docker 的 Mac 時,您通常會在啟動時看到類似以下內容
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 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
(您的 ID 將不同)
docker stop goofy_brown
81c723d22865
如果您願意,也可以在完成後刪除容器(它會保留在檔案系統的某個位置,通常在 /var/lib/docker
下面)
使用 Spring Profiles
使用 Spring profiles 執行您新建立的 Docker 映象就像向 Docker run 命令傳遞一個環境變數一樣簡單(對於 prod
profile)
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 容器中除錯應用
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