許多人使用容器來包裝他們的 Spring Boot 應(yīng)用程序,而構(gòu)建容器并不是一件簡單的事情。這是針對 Spring Boot 應(yīng)用程序開發(fā)人員的指南,容器對于開發(fā)人員來說并不總是一個好的抽象。它們迫使你去了解和思考低層次的問題。但是,有時可能會要求您創(chuàng)建或使用容器,因此了解構(gòu)建塊是值得的。在本指南中,我們旨在向您展示如果您面臨需要創(chuàng)建自己的容器的前景,您可以做出的一些選擇。
我們假設(shè)您知道如何創(chuàng)建和構(gòu)建基本的 Spring Boot 應(yīng)用程序。如果沒有,請轉(zhuǎn)到入門指南之一?——例如,關(guān)于構(gòu)建REST 服務(wù)的指南。從那里復(fù)制代碼并練習(xí)本指南中包含的一些想法。
還有一個關(guān)于Docker的入門指南,這也是一個很好的起點(diǎn),但它沒有涵蓋我們在此處介紹的選擇范圍或詳細(xì)介紹它們。
一個基本的 Dockerfile
Spring Boot 應(yīng)用程序很容易轉(zhuǎn)換為可執(zhí)行的 JAR 文件。所有的入門指南都是這樣做的,你從Spring Initializr下載的每個應(yīng)用程序都有一個構(gòu)建步驟來創(chuàng)建一個可執(zhí)行的 JAR。使用 Maven,你運(yùn)行./mvnw install,使用 Gradle,你運(yùn)行./gradlew build。運(yùn)行該 JAR 的基本 Dockerfile 將如下所示,位于項(xiàng)目的頂層:
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]復(fù)制
JAR_FILE您可以作為命令的一部分傳入docker(Maven 和 Gradle 不同)。對于 Maven,以下命令有效:
docker build --build-arg JAR_FILE=target/*.jar -t myorg/myapp .復(fù)制
對于 Gradle,以下命令有效:
docker build --build-arg JAR_FILE=build/libs/*.jar -t myorg/myapp .復(fù)制
一旦你選擇了一個構(gòu)建系統(tǒng),你就不需要ARG. 您可以對 JAR 位置進(jìn)行硬編碼。對于 Maven,如下所示:
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]復(fù)制
然后我們可以使用以下命令構(gòu)建鏡像:
docker build -t myorg/myapp .復(fù)制
然后我們可以通過運(yùn)行以下命令來運(yùn)行它:
docker run -p 8080:8080 myorg/myapp復(fù)制
輸出類似于以下示例輸出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.2.RELEASE)
Nov 06, 2018 2:45:16 PM org.springframework.boot.StartupInfoLogger logStarting
INFO: Starting Application v0.1.0 on b8469cdc9b87 with PID 1 (/app.jar started by root in /)
Nov 06, 2018 2:45:16 PM org.springframework.boot.SpringApplication logStartupProfileInfo
...復(fù)制
如果你想在鏡像內(nèi)部四處尋找,你可以通過運(yùn)行以下命令在其中打開一個 shell(注意基礎(chǔ)鏡像沒有bash):
docker run -ti --entrypoint /bin/sh myorg/myapp復(fù)制
輸出類似于以下示例輸出:
/ # ls
app.jar dev home media proc run srv tmp var
bin etc lib mnt root sbin sys usr
/ #
我們在示例中使用的 alpine 基礎(chǔ)容器沒有bash,所以這是一個ashshell。它具有一些但不是全部的特性bash。
如果你有一個正在運(yùn)行的容器并且你想查看它,你可以通過運(yùn)行docker exec:
docker run --name myapp -ti --entrypoint /bin/sh myorg/myapp
docker exec -ti myapp /bin/sh
/ #復(fù)制
傳遞給命令myapp的位置在哪里。如果您沒有使用,docker 會分配一個助記名稱,您可以從. 您還可以使用容器的 SHA 標(biāo)識符而不是名稱。SHA 標(biāo)識符在輸出中也可見。--namedocker run--namedocker psdocker ps
入口點(diǎn)
使用Dockerfile的exec 形式ENTRYPOINT,以便沒有外殼包裝 Java 進(jìn)程。優(yōu)點(diǎn)是java進(jìn)程響應(yīng)KILL發(fā)送到容器的信號。實(shí)際上,這意味著(例如)如果您docker run在本地使用圖像,則可以使用CTRL-C. 如果命令行有點(diǎn)長,您可以COPY在運(yùn)行之前將其提取到 shell 腳本中并放入映像中。以下示例顯示了如何執(zhí)行此操作:
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY run.sh .
COPY target/*.jar app.jar
ENTRYPOINT ["run.sh"]復(fù)制
請記住使用exec java …啟動 java 進(jìn)程(以便它可以處理KILL信號):
run.sh
#!/bin/sh
exec java -jar /app.jar復(fù)制
入口點(diǎn)的另一個有趣方面是您是否可以在運(yùn)行時將環(huán)境變量注入 Java 進(jìn)程。例如,假設(shè)您想要在運(yùn)行時添加 Java 命令行選項(xiàng)。您可以嘗試這樣做:
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","${JAVA_OPTS}","-jar","/app.jar"]復(fù)制
然后您可以嘗試以下命令:
docker build -t myorg/myapp .
docker run -p 9000:9000 -e JAVA_OPTS=-Dserver.port=9000 myorg/myapp復(fù)制
這失敗了,因?yàn)?/span>${}替換需要一個外殼。exec 表單不使用 shell 來啟動進(jìn)程,因此不應(yīng)用選項(xiàng)。您可以通過將入口點(diǎn)移動到腳本(如run.sh前面顯示的示例)或在入口點(diǎn)顯式創(chuàng)建 shell 來解決此問題。以下示例顯示了如何在入口點(diǎn)中創(chuàng)建 shell:
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"]復(fù)制
然后,您可以通過運(yùn)行以下命令來啟動此應(yīng)用程序:
docker run -p 8080:8080 -e "JAVA_OPTS=-Ddebug -Xmx128m" myorg/myapp復(fù)制
該命令產(chǎn)生類似于以下的輸出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.0.RELEASE)
...
2019-10-29 09:12:12.169 DEBUG 1 --- [ main] ConditionEvaluationReportLoggingListener :
============================
CONDITIONS EVALUATION REPORT
============================
...復(fù)制
(前面的輸出顯示了 Spring BootDEBUG生成的完整輸出的一部分。)-Ddebug
將 anENTRYPOINT與顯式 shell 一起使用(如前面的示例所做的那樣)意味著您可以將環(huán)境變量傳遞給 Java 命令。但是,到目前為止,您還不能為 Spring Boot 應(yīng)用程序提供命令行參數(shù)。以下命令不會在端口 9000 上運(yùn)行應(yīng)用程序:
docker run -p 9000:9000 myorg/myapp --server.port=9000復(fù)制
該命令產(chǎn)生以下輸出,將端口顯示為 8080 而不是 9000:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.0.RELEASE)
...
2019-10-29 09:20:19.718 INFO 1 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080復(fù)制
它不起作用,因?yàn)?docker 命令(該--server.port=9000部分)被傳遞到入口點(diǎn) ( sh),而不是它啟動的 Java 進(jìn)程。要解決此問題,您需要將命令行從以下添加CMD到ENTRYPOINT:
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar ${0} ${@}"]復(fù)制
然后您可以運(yùn)行相同的命令并將端口設(shè)置為 9000:
$ docker run -p 9000:9000 myorg/myapp --server.port=9000復(fù)制
如以下輸出示例所示,端口確實(shí)設(shè)置為 9000:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.0.RELEASE)
...
2019-10-29 09:30:19.751 INFO 1 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 9000復(fù)制
注意${0}“命令”(在這種情況下是第一個程序參數(shù))和${@}“命令參數(shù)”(程序參數(shù)的其余部分)的使用。如果您使用腳本作為入口點(diǎn),那么您不需要${0}(/app/run.sh在前面的示例中)。以下列表顯示了腳本文件中的正確命令:
run.sh
#!/bin/sh
exec java ${JAVA_OPTS} -jar /app.jar ${@}復(fù)制
docker配置到現(xiàn)在都非常簡單,生成的鏡像效率不是很高。docker 鏡像有一個文件系統(tǒng)層,其中包含 fat JAR,我們對應(yīng)用程序代碼所做的每一次更改都會更改該層,這可能是 10MB 或更多(對于某些應(yīng)用程序甚至高達(dá) 50MB)。我們可以通過將 JAR 拆分為多個層來改進(jìn)這一點(diǎn)。
較小的圖像
請注意,前面示例中的基本映像是openjdk:8-jdk-alpine. 這些alpine圖像小于Dockerhubopenjdk的標(biāo)準(zhǔn)庫圖像。您還可以通過使用標(biāo)簽而不是. 并非所有應(yīng)用程序都使用 JRE(與 JDK 相對),但大多數(shù)應(yīng)用程序都可以。一些組織強(qiáng)制執(zhí)行一個規(guī)則,即每個應(yīng)用程序都必須使用 JRE,因?yàn)榇嬖跒E用某些 JDK 功能(例如編譯)的風(fēng)險(xiǎn)。jrejdk
另一個可以讓您獲得更小的映像的技巧是使用JLink,它與 OpenJDK 11 捆綁在一起。JLink 允許您從完整 JDK 中的模塊子集構(gòu)建自定義 JRE 分發(fā),因此您不需要 JRE 或 JDK基礎(chǔ)圖像。原則上,這將使您獲得比使用openjdk官方 docker 圖像更小的總圖像大小。在實(shí)踐中,您(還)不能將alpine基礎(chǔ)鏡像與 JDK 11 一起使用,因此您對基礎(chǔ)鏡像的選擇是有限的,并且可能會導(dǎo)致最終鏡像的大小更大。此外,您自己的基本映像中的自定義 JRE 不能在其他應(yīng)用程序之間共享,因?yàn)樗鼈冃枰煌淖远x。因此,您的所有應(yīng)用程序可能都有較小的圖像,但它們?nèi)匀恍枰L的時間才能啟動,因?yàn)樗鼈儧]有從緩存 JRE 層中受益。
最后一點(diǎn)突出了圖像構(gòu)建者的一個非常重要的問題:目標(biāo)不一定總是盡可能地構(gòu)建最小的圖像。較小的圖像通常是一個好主意,因?yàn)樗鼈冃枰俚臅r間來上傳和下載,但前提是它們中的所有圖層都沒有被緩存。如今,圖像注冊非常復(fù)雜,您很容易通過嘗試巧妙地構(gòu)建圖像而失去這些功能的好處。如果您使用通用基礎(chǔ)層,圖像的總大小就不再那么重要了,而且隨著注冊中心和平臺的發(fā)展,它可能變得更不重要。話雖如此,嘗試優(yōu)化應(yīng)用程序映像中的層仍然很重要且有用。然而,
更好的 Dockerfile
由于 JAR 本身的打包方式,Spring Boot fat JAR 自然有“層”。如果我們先解包,它已經(jīng)分為外部依賴和內(nèi)部依賴。要在 docker 構(gòu)建中一步完成此操作,我們需要先解壓縮 JAR。以下命令(堅(jiān)持使用 Maven,但 Gradle 版本非常相似)解壓縮 Spring Boot fat JAR:
mkdir target/dependency
(cd target/dependency; jar -xf ../*.jar)
docker build -t myorg/myapp .復(fù)制
然后我們可以使用下面的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"]復(fù)制
現(xiàn)在有三層,所有應(yīng)用程序資源都在后面兩層。如果應(yīng)用程序依賴沒有改變,第一層(from BOOT-INF/lib)不需要改變,所以構(gòu)建更快,并且容器在運(yùn)行時的啟動也更快,只要基礎(chǔ)層已經(jīng)被緩存。
我們使用了一個硬編碼的主應(yīng)用程序類:hello.Application. 這對于您的應(yīng)用程序可能有所不同。如果你愿意,你可以用另一個參數(shù)化它ARG。您還可以將 Spring Boot fat 復(fù)制JarLauncher到映像中并使用它來運(yùn)行應(yīng)用程序。它可以工作,您不需要指定主類,但啟動時會慢一些。
Spring Boot 層索引
從 Spring Boot 2.3.0 開始,使用 Spring Boot Maven 或 Gradle 插件構(gòu)建的 JAR 文件在 JAR 文件中包含層信息。該層信息根據(jù)應(yīng)用程序構(gòu)建之間更改的可能性來分離應(yīng)用程序的各個部分。這可以用來使 Docker 鏡像層更加高效。
層信息可用于將 JAR 內(nèi)容提取到每個層的目錄中:
mkdir target/extracted
java -Djarmode=layertools -jar target/*.jar extract --destination target/extracted
docker build -t myorg/myapp .復(fù)制
然后我們可以使用以下內(nèi)容Dockerfile:
Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG EXTRACTED=/workspace/app/target/extracted
COPY ${EXTRACTED}/dependencies/ ./
COPY ${EXTRACTED}/spring-boot-loader/ ./
COPY ${EXTRACTED}/snapshot-dependencies/ ./
COPY ${EXTRACTED}/application/ ./
ENTRYPOINT ["java","org.springframework.boot.loader.JarLauncher"]
Spring Boot fatJarLauncher是從 JAR 中提取到鏡像中的,因此它可以用于啟動應(yīng)用程序,而無需對主應(yīng)用程序類進(jìn)行硬編碼。
有關(guān)使用分層功能的更多信息,請參閱Spring Boot 文檔。
調(diào)整
如果您想盡快啟動您的應(yīng)用程序(大多數(shù)人都這樣做),您可能會考慮一些調(diào)整:
- 使用spring-context-indexer(鏈接到文檔)。它不會為小型應(yīng)用程序增加太多,但每一點(diǎn)都有幫助。
- 如果您負(fù)擔(dān)得起,請不要使用執(zhí)行器。
- 使用 Spring Boot 2.1(或更高版本)和 Spring 5.1(或更高版本)。
- 使用(通過命令行參數(shù)、系統(tǒng)屬性或其他方法)修復(fù)Spring Boot 配置文件的位置。spring.config.location
- 通過設(shè)置來關(guān)閉 JMX(您可能不需要在容器中使用它)spring.jmx.enabled=false。
- 使用-noverify. 還要考慮-XX:TieredStopAtLevel=1(這會在以后減慢 JIT 但會縮短啟動時間)。
- 使用 Java 8 的容器內(nèi)存提示:-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap. 在 Java 11 中,默認(rèn)情況下這是自動的。
您的應(yīng)用程序在運(yùn)行時可能不需要完整的 CPU,但它確實(shí)需要多個 CPU 才能盡快啟動(至少兩個,四個更好)。如果您不介意啟動速度較慢,則可以將 CPU 限制在四個以下。如果您被迫從少于四個 CPU 開始,設(shè)置 可能會有所幫助
-Dspring.backgroundpreinitializer.ignore=true,因?yàn)樗梢苑乐?Spring Boot 創(chuàng)建一個它可能無法使用的新線程(這適用于 Spring Boot 2.1.0 及更高版本)。
多階段構(gòu)建
A Better Dockerfile中Dockerfile所示的假設(shè)假設(shè)胖 JAR 已經(jīng)在命令行上構(gòu)建。您還可以通過使用多階段構(gòu)建并將結(jié)果從一個圖像復(fù)制到另一個圖像來在 docker 中執(zhí)行該步驟。以下示例通過使用 Maven 來實(shí)現(xiàn):
Dockerfile
FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/app
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src
RUN ./mvnw install -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]復(fù)制
第一個圖像標(biāo)記為build,它用于運(yùn)行 Maven、構(gòu)建胖 JAR 并解壓縮它。解包也可以由 Maven 或 Gradle 完成(這是入門指南中采用的方法)。沒有太大區(qū)別,只是必須編輯構(gòu)建配置并添加插件。
請注意,源代碼已分為四層。后面的層包含構(gòu)建配置和應(yīng)用程序的源代碼,前面的層包含構(gòu)建系統(tǒng)本身(Maven 包裝器)。這是一個小的優(yōu)化,也意味著我們不必將target目錄復(fù)制到 docker 鏡像,即使是用于構(gòu)建的臨時鏡像。
RUN每個源代碼更改的構(gòu)建都很慢,因?yàn)楸仨氃诘谝徊糠种匦聞?chuàng)建 Maven 緩存。但是你有一個完全獨(dú)立的構(gòu)建,只要他們有 docker,任何人都可以運(yùn)行它來運(yùn)行你的應(yīng)用程序。這在某些環(huán)境中可能非常有用——例如,您需要與不了解 Java 的人共享您的代碼。
實(shí)驗(yàn)功能
Docker 18.06 帶有一些“實(shí)驗(yàn)性”特性,包括緩存構(gòu)建依賴項(xiàng)的方法。要打開它們,您需要在守護(hù)進(jìn)程 ( dockerd) 中有一個標(biāo)志,并在運(yùn)行客戶端時需要一個環(huán)境變量。然后你可以添加一個“神奇”的第一行到你的Dockerfile:
Dockerfile
# syntax=docker/dockerfile:experimental復(fù)制
然后該RUN指令接受一個新標(biāo)志:--mount. 以下清單顯示了一個完整示例:
Dockerfile
# syntax=docker/dockerfile:experimental
FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/app
COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src
RUN --mount=type=cache,target=/root/.m2 ./mvnw install -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]復(fù)制
然后你可以運(yùn)行它:
DOCKER_BUILDKIT=1 docker build -t myorg/myapp .復(fù)制
以下清單顯示了示例輸出:
...
=> /bin/sh -c ./mvnw install -DskipTests 5.7s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:3defa...
=> => naming to docker.io/myorg/myapp復(fù)制
使用實(shí)驗(yàn)性功能,您會在控制臺上獲得不同的輸出,但您可以看到,如果緩存是熱的,現(xiàn)在 Maven 構(gòu)建只需幾秒鐘而不是幾分鐘。
這個Dockerfile配置的 Gradle 版本非常相似:
Dockerfile
# syntax=docker/dockerfile:experimental
FROM openjdk:8-jdk-alpine AS build
WORKDIR /workspace/app
COPY . /workspace/app
RUN --mount=type=cache,target=/root/.gradle ./gradlew clean build
RUN mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*.jar)
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/build/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]
雖然這些功能處于實(shí)驗(yàn)階段,但打開和關(guān)閉 buildkit 的選項(xiàng)取決于docker您使用的版本。檢查您擁有的版本的文檔(前面顯示的示例對于docker18.0.6 是正確的)。
安全方面
就像在經(jīng)典 VM 部署中一樣,進(jìn)程不應(yīng)以 root 權(quán)限運(yùn)行。相反,映像應(yīng)包含運(yùn)行應(yīng)用程序的非 root 用戶。
在 aDockerfile中,您可以通過添加另一個添加(系統(tǒng))用戶和組并將其設(shè)置為當(dāng)前用戶(而不是默認(rèn)的 root)的層來實(shí)現(xiàn)此目的:
Dockerfile
FROM openjdk:8-jdk-alpine
RUN addgroup -S demo && adduser -S demo -G demo
USER demo
...復(fù)制
如果有人設(shè)法突破您的應(yīng)用程序并在容器內(nèi)運(yùn)行系統(tǒng)命令,這種預(yù)防措施會限制他們的能力(遵循最小權(quán)限原則)。
一些進(jìn)一步的Dockerfile命令只能以 root 身份運(yùn)行,因此您可能必須將 USER 命令進(jìn)一步向下移動(例如,如果您計(jì)劃在容器中安裝更多包,它只能以 root 身份運(yùn)行)。
對于其他方法,不使用 aDockerfile可能更適合。例如,在后面描述的 buildpack 方法中,大多數(shù)實(shí)現(xiàn)默認(rèn)使用非 root 用戶。
另一個考慮因素是大多數(shù)應(yīng)用程序在運(yùn)行時可能不需要完整的 JDK,因此一旦我們進(jìn)行了多階段構(gòu)建,我們就可以安全地切換到 JRE 基礎(chǔ)映像。因此,在前面顯示的多階段構(gòu)建中,我們可以將其用于最終的可運(yùn)行映像:
Dockerfile
FROM openjdk:8-jre-alpine
...復(fù)制
如前所述,這也節(jié)省了映像中的一些空間,這些空間將被運(yùn)行時不需要的工具占用。
審核編輯:湯梓紅
-
容器
+關(guān)注
關(guān)注
0文章
511瀏覽量
22458 -
應(yīng)用程序
+關(guān)注
關(guān)注
38文章
3337瀏覽量
59044 -
spring
+關(guān)注
關(guān)注
0文章
340瀏覽量
15088 -
Docker
+關(guān)注
關(guān)注
0文章
515瀏覽量
12974
發(fā)布評論請先 登錄
Spring Boot中Docker的入門指南(二)
Spring Boot嵌入式Web容器原理是什么
Docker入門指南
使用Spring Cloud與Docker實(shí)戰(zhàn)微服務(wù)

spring boot入門篇
Spring Boot從零入門1 詳述
Spring Boot特有的實(shí)踐
強(qiáng)大的Spring Boot 3.0要來了
Spring Boot Web相關(guān)的基礎(chǔ)知識
在Spring Boot中如何使用定時任務(wù)
Spring Boot Actuator快速入門
Spring Boot啟動 Eureka流程

Spring Boot的啟動原理

評論