如何構建SpringBoot的Docker鏡像

目標

  • 自定義Dockerfile構建一個生產可用的jre base image

  • 配置maven-docker-plugin插件完成從源碼的 打包fatjar -> build docker image with fatjar -> push image

  • 支持docker對JVM相關參數的配置。比如Xmx,Xms,以及完全自定義的java啓動參數。

    rootfs

  • 說打包之前我們先了解linux內核與發行版操作系統(如centos,ubuntu,debian)之間的關係。

  • 由於linux內核與具體的操作系統是解耦的。即互相不干涉的,docker利用了這個特性,將操作系統的文件打包成一個壓縮文件。

  • 在運行時,解壓這個壓縮包,並通過chroot進行掛載,就完成了容器的內部我們看到的操作系統了。即我們的rootfs。

  • 那麼這個和我們docker打包java應用的關係在哪裏呢?

  • 總所周知的是java是又提供打包解決方案的,打包成jar,但是此方案的問題在於我並不能在任何一個環境裏面運行直接運行(因爲依賴JRE),而每一個操作系統又不一樣,這就導致許多環境帶來的時間浪費。

  • 結合前面提到了docker打包是把操作系統的文件打包的,所以我們能不能把操作系統+jre+application.jar這三老鐵一鍋端,全給他打包起來不就解決了嗎?沒錯,這就是我們要構建鏡像。

  • 沒錯我們想到了一個好的辦法來解決打包的問題。那我們在來看看這個東西是不是還有啥問題?你看啊,我們最初了發佈一個fatjar也就60M,要結合上OS jre豈不是每次都大很多,浪費很多的磁盤,網絡傳送開銷也加大的蠻多。

  • 這個問題的docker中利用了分層文件系統來解決這個問題,即我們的OS JRE 這些不變的東西只會在第一次使用時下載一次或者上傳一次,其他時候我們只有變化的application.jar層需要進行上傳和下載

最終形態

  • 我們像搭積木一樣一層一層的把我們所需要的文件系統疊加起來,就完成了我們想要的Image。Sample

Docker Image

需求

  • 我們要達到如下預期
  1. 鏡像比如要足夠小(儘量控制在100M以內)
  2. 字符集必須要支持中文,不然就亂碼了
  3. 時區的是UTC+8
  4. 字體的支持,不然excel導出會拋出錯誤
  5. 還的支持下imagemagick。
  6. 使我們運行在容器中的java進程PID!=1
    如果Pid=1會有很多問題(如jmap,jstat…等工具無法使用,你可以從這裏瞭解更多 jmap not happy on alpine )
    這裏我們使用Tini來完成這個工作,關於Tini你可以從這裏瞭解更多 What is advantage of Tini?

措施

  • 基於以上要求我們構建出一下鏡像
  • 首先使用apline作爲基礎鏡像足夠小隻有5M
  • 由於alpine自帶支持中文的字符集,這裏我們只需要將LANG設置爲C.UTF-8即可完美的支持中文。
  • 國內軟件源首選阿里雲啦,順道配置一下阿里雲的鏡像源,加速我們的鏡像構建速度。
  • 配置UTC+8時區需要安裝tzdata,安裝完成之後配置一下即可。
  • 目前alpine攜帶JDK版本爲1.8.232。
  • 使用tini 包裝java進程。

Dockerfile構建基礎java鏡像(圖中最一層和第二層)

  • 如下的dockerfile是一個完整的dockerfile文件。基於5M大小的alpine鏡像構建,apline提供的包管理器是apk
    我在這裏爲了方便使用直接配置了阿里雲提供的鏡像源,加速構建過程。這裏我們勁量拆分步驟,方便
    FROM alpine:3.11.2
    MAINTAINER qingmu [email protected]
    ENV LANG=C.UTF-8 \
     TZ=Asia/Shanghai
    RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
    && echo $TZ > /etc/timezone \
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    && apk update \
    && apk add --update procps \
    && apk add --no-cache  ca-certificates ttf-dejavu tzdata tini bash
    # 變動層
    RUN apk add --no-cache  openjdk8-jre
    ENV JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk/jre \
     PATH=$PATH:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin
    RUN rm -rf /var/cache/apk/*
  • 如你想動手構建自己,將以上Dockerfile文件copy一份,寫入Dockerfile文件中執行構建即可。執行以下命令,即可完成屬於您自己的鏡像,這裏需要一點docker的基礎知識
    echo 'dockerfile' > Dockerfile
    docker build -t freemanliu/openjre .
  • 關於docker build 命令你可以點擊這裏瞭解更多更詳細的用法。
  • 當然了,你如果不想構建那麼也可以使用我在github上寫好的,並在dockerhub中autobuild好的鏡像。
  • 注意該鏡像不包含字體文件,在使用到字體相關的api時,會拋出異常,如對excel導出的操作,這時候我們需要安裝一下字體庫,我們通過apk庫添加十分簡單,只需在以上的Dockerfile描述文件中加入一下庫即可,其他保持不變。如你還用到了其他相關軟件,請google查閱相關庫,使用apk包管理器添加即可。
    apk add --no-cache ttf-dejavu
  • 如此我們便得到了一個包含了jre的Image鏡像,下面我們繼續來構建第三層。

SpringBoot打包fatjar

  • 在配置maven項目的parent爲spring-boot-dependencies後,springboot默認在pluginManagement中配置好了 maven-shade-plugin插件
    我們可以在我們自己具體業務微服務中激活該插件,配置如下:
     <build>
     <plugins>
     <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-shade-plugin</artifactId>
     </plugin>
     </plugins>
    </build>
  • 配置好了插件,插件怎麼知道我們的start class是哪個呢?springboot很貼心的提供了一個start-class屬性。我們只需要賦值即可
    <properties>
     <start-class>com.qingmu.account.Application</start-class>
    </properties>
  • 配置完成之後我們可以在命令行執行如下命令,便可完成我們的fatjar的打包。
  • 執行該命令本質上mave插件會將我們所依賴的jar解壓並copy到到我們的fatjar中。
mvn clean package
  • 如配置正確你將在你的target目錄中看到${artifactId}.jar
  • 在命令行執行java -jar target/${artifactId}.jar也能正確的啓動成功。

Docker打包fatjar鏡像(構建第三層)

  • 在前面的的章節,我們完成了JRE鏡像和fatjar的構建。接下來我們將完成他們的結合,完成靈魂的昇華 ~ ~。

Dockerfile VS Docker-mave-plugin

  • 在java項目中我們至少有兩種方式對我們的docker和fatjar進行結合打包成image。

Dockerfile

  • 一種常見的方式是編寫Dockerfile,並使用Cli命令行對齊進行相關操作,這也是網上比較多的教程所採用的方法。
    然而該方法有比較麻煩的問題:
    第一,如果你的項目較多怎麼能,意味着你需要爲每一個項目去添加一份dockerfile描述文件,當然這點可以通過自定義maven骨架解決。
    第二,這麼多dockerfile散落在微服務項目的幾十上百個倉庫中,如果有一天要更新這個dockerfile中的某些內容,就會變得異常的麻煩和難以高效率的解決。

Docker-mave-plugin

  • 這是一個由於com.spotify提供的maven插件,使用它將可以輕鬆的完成SpringBoot項目的docker鏡像打包推送工作。
  • 當然他也能很好的解決以上Dockerfile的問題,不需要Dockerfile描述文件了,我們可以將描述的相關信息寫到maven插件中,而maven是支持繼承的,以爲者我們只需要在我們自己的parent-pom中維護這個docker插件就維護了所有的具體微服務的打包插件了。實際用下來是相當的方便啊。實際項目中也採用的是該方案。

ENTRYPOINT VS CMD

  • ENTRYPOINT和CMD命令最大的不同點,在於使用cmd命令是可以在運行是通過傳遞參數修改鏡像的運行命令的,而ENTRYPOINT命令則是不支持的。

  • 簡單的說就是ENTRYPOINT類似編程中的常量,一旦定義好了就無法改變。而cmd則類似與變量,你可以在運行時隨時賦值。

  • 一起來看下這個例子,這是一個常見的使用docker打包java應用的dockerfile描述文件,。使用了ENTRYPOINT來指定啓動命令。

freemanliu/openjre:8.232
    FROM java:8
    ADD app.jar app.jar
    EXPOSE 8800
    ENTRYPOINT ["java","-jar","/app.jar"]
  • 將這個image啓動起來,我們只需要執行如下命令,變可以輕鬆的運行起來我們的應用。在啓動鏡像是它會默認執行ENTRYPOINT中所書寫的描述。
docker run -it -rm freemanliu/app:v1.0.0
  • 如果我們想運行的時候不運行默認的命令,比如說我們執行以下命令,進入到容器的sh命令終端。你會發現無效,由於我們是使用的ENTRYPOINT定義的是”常量”,所以你將會看到的結果任然是java進程成功啓動。而如果使用的CMD命令,則是可以正確的進入sh終端。
docker run -it -rm freemanliu/app:v1.0.0 sh
  • 至於CMD也好還是ENTRYPOINT也罷,都可以用,看你的喜好了,我是更喜歡freedom一點的,我推薦CMD

  • 那麼好的,基礎的東西我們就討論到這裏。

配置POM

在具體配置之前我們先總結下需要幹些什麼:
第一步,肯定是先引入插件,不多說。
第二步,既然我們想要插件幫我們完成image的push,那的讓插件知道我們的私服地址吧,得知道username/password吧,所以第二步我們得配置setting.xml,添加server。
第三步,插件有了,私服配好了,接下來就的琢磨插件的配置了吧,所有第三步我們配置插件。
第四步,配置完成一個插件之後,我們該考慮一下多環境打包的事兒吧。第四步處理profiles

添加插件到pluginManagement

  • 首先是引入插件,你可以點擊這裏瞭解更多插件的信息,雖然他現在極力推崇dockerfile插件,但是真的沒這個實用性高啊。
  • 我們得養成一個習慣,在添加任何新的依賴是,先在咱們的parent項目的xxxManagement中先添加上,在真正業務pom中去掉版本號,讓parent統一管理依賴的版本號。
<build>
     <pluginManagement>
     <plugins>
     <plugin>
     <groupId>com.spotify</groupId>
     <artifactId>docker-maven-plugin</artifactId>
     <version>1.1.1</version>
     </plugin>
     </plugins>
     </pluginManagement>
    </build>

配置私服

  • 關於私服你可以自己搭建,選擇還是比較多,官方的docker-registry,比較知名和完善的Harbor,以及我們的老朋友Nexus3.
  • 自己搭建雖然很方便也很簡單,那有沒有不用自己維護性能還不錯的三方私有倉庫選擇呢?當然還是有的,畢竟這世上好人還是多,阿里云爲我們提供了免費的私有倉庫服務,你只需要註冊阿里雲,控制檯搜索容器鏡像服務,就能找到他了。
  • 對於經常配置server的老司機來說這一步很簡單,但是對於新玩家來說這一步比較複雜,如果你不是很熟悉並且沒有配置過maven的setting.xml文件的話,我建議你使用圖形化編輯器,找準如下標籤插入即可。
  • 爲啥~/.m2/settings.xml這是因爲maven默認讀取的配置目錄是當前用戶目錄下的.m2目錄,windows的話你需要找到你當前用戶。
 vim ~/.m2/settings.xml
# 找到servers標籤添加如下如下信息
    <servers>
     <server>
     <id>aliyun-registry</id> # id將在後面插件中用到
     <username>你的私服的username</username>
     <password>你私服的密碼</password>
     <configuration>
     <email>你的email</email>
     </configuration>
     </server>
    </servers>

插件配置

  • 在配置插件前,另一個插件git-commit-id-plugin通過該插件我們可以在maven的其他插件中很方便的用到git相關信息,比如獲取到當前的git tag。
  • 通用的我們配置的插件默認不激活,寫到pluginManagement
<pluginManagement>
     <plugins>
     <plugin>
     <groupId>pl.project13.maven</groupId>
     <artifactId>git-commit-id-plugin</artifactId>
     <version>2.2.4</version>
     <executions>
     <execution>
     <id>get-the-git-infos</id>
     <goals>
     <goal>revision</goal>
     </goals>
     </execution>
     </executions>
     <configuration>
     <!-- 使properties擴展到整個maven bulid 週期
     Ref: https://github.com/ktoso/maven-git-commit-id-plugin/issues/280 -->
     <injectAllReactorProjects>true</injectAllReactorProjects>
     <dateFormat>yyyyMMddHHmmss</dateFormat>
     <!--<useNativeGit>false</useNativeGit>-->
     <verbose>true</verbose>
     <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
     <!--若項目打包類型爲pom,是否取消構建;默認值:true;-->
     <skipPoms>false</skipPoms>
     <!--是否生成"git.properties"文件;默認值:false;-->
     <generateGitPropertiesFile>true</generateGitPropertiesFile>
     <!--指定"git.properties"文件的存放路徑(相對於${project.basedir}的一個路徑);-->
     <generateGitPropertiesFilename>git.properties</generateGitPropertiesFilename>
     <!--git描述配置,可選;由JGit提供實現;-->
     <gitDescribe>
     <!--是否生成描述屬性-->
     <skip>false</skip>
     <!--提交操作未發現tag時,僅打印提交操作ID,-->
     <always>false</always>
     <!--提交操作ID顯式字符長度,最大值爲:40;默認值:7; 0代表特殊意義;後面有解釋; -->
     <abbrev>40</abbrev>
     <!--構建觸發時,代碼有修改時(即"dirty state"),添加指定後綴;默認值:"";-->
     <dirty>-dirty</dirty>
     <!--always print using the "tag-commits_from_tag-g_commit_id-maybe_dirty" format, even if "on" a tag. The distance will always be 0 if you're "on" the tag. -->
     <forceLongFormat>false</forceLongFormat>
     </gitDescribe>
     </configuration>
     </plugin>
     </plugins>
     </pluginManagement>
  • 在添加插件的時候我們說到應該把通用的東西放到xxxManagement標籤中,將變化的內容通過變量的形式抽取出來,完成最大程度的複用。
  • 所以我們對插件的配置也是通用的,所以也是改在Management中完成配置,並抽取變化。具體配置如下圖,可能顯得有些複雜。
    由於爲了靈活性的需要,我們進行了多次變量取,這裏我來詳細解釋下:
  1. 首先properties標籤中的大寫的變量取值,意思爲取得系統上下的屬性,至於爲什麼要這麼做呢?是因爲爲了讓我們的鏡像在運行是可以通過環境變量的形式對其進行修改優化。仔細看你會發現這些值都是有可能對於不同的硬件服務器有着完全不同的設定。避免了修改java內存及一些相關參數而重寫打包鏡像,也提供了一個修改的便捷渠道。
  2. 接下來再看env標籤,有沒有覺得眼熟?這裏是定義系統環境變量的地方,這裏的定義與我們在properties標籤中定義的名稱一致,可以看到我們在這裏有進行一次變量取值,爲什麼又是變量取值,而不是寫死一個值呢?
    主要出於三點考慮:
    第一點是方便maven執行mvn clean package -Djvm.Xms=2G 通過命令行傳遞默認參數。
    第二點是爲了方便具體業務通過在自己的pom重覆蓋該參數完成默認參數的修改。
    第三點當然是爲了支持多環境打包準備。
<properties>
     <docker.jre>freemanliu/openjre</docker.jre>
     <docker.jre.version>1.8.0_171</docker.jre.version>
     <java.opts>
     -Dservice.name=${project.artifactId} \
     -XX:+UnlockExperimentalVMOptions \
     -Xms${JAVA_HEAP_XMS} \
     -Xmx${JAVA_HEAP_XMX} \
     -XX:CICompilerCount=${CI_COMPILER_COUNT} \
     -XX:G1NewSizePercent=${G1_NEW_SIZE_PERCENT} \
     -XX:G1MaxNewSizePercent=${G1_MAX_NEW_SIZE_PERCENT} \
     -DEUREKA_SERVER=${EUREKA_SERVER} \
     -Dspring.profiles.active=${spring.profile} \
     -Dspring.cloud.config.profile=${spring.profile} \
     -XX:+UseG1GC \
     -XX:+AggressiveOpts \
     -XX:+UseFastAccessorMethods \
     -XX:+UseStringDeduplication \
     -XX:+UseCompressedOops \
     -XX:+OptimizeStringConcat
     </java.opts>
     <jvm.Xms>1G</jvm.Xms>
     <jvm.Xmx>1G</jvm.Xmx>
     <g1.new.size.percent>5</g1.new.size.percent>
     <g1.max.size.percent>60</g1.max.size.percent>
     <pushImage>true</pushImage>
     <ci.compiler.count>8</ci.compiler.count>
     <eureka.url>${prod.eureka}</eureka.url>
     <spring.profile>test</spring.profile>
    <properties>

    <pluginManagement>
    <plugins>
     <plugin>
     <groupId>com.spotify</groupId>
     <artifactId>docker-maven-plugin</artifactId>
     <configuration>
     <imageName>
     ${docker.repository}/${docker.registry.name}/${project.artifactId}:${git.commit.id.describe-short}
     </imageName>
     <registryUrl>${docker.repository}</registryUrl>
     <workdir>/work</workdir>
     <rm>true</rm>
     <env>
     <!--關於G1的一些參數說明您可以從這裏獲取到 https://www.oracle.com/technetwork/cn/articles/java/g1gc-1984535-zhs.html -->
     <!--設置時區-->
     <TZ>Asia/Shanghai</TZ>
     <!--初始化堆大小-->
     <JAVA_HEAP_XMS>${jvm.Xms}</JAVA_HEAP_XMS>
     <!--jvm最大可使用的堆-->
     <JAVA_HEAP_XMX>${jvm.Xmx}</JAVA_HEAP_XMX>
     <!--設置要用作年輕代大小,最小值的堆百分比。默認值是 Java 堆的 5%,需要使用解鎖實驗性質的標誌-XX:+UnlockExperimentalVMOptions-->
     <G1_NEW_SIZE_PERCENT>${g1.new.size.percent}</G1_NEW_SIZE_PERCENT>
     <!--設置要用作年輕代大小,最大值的堆百分比。默認值是 Java 堆的 60%,需要使用解鎖實驗性質的標誌-XX:+UnlockExperimentalVMOptions-->
     <G1_MAX_NEW_SIZE_PERCENT>${g1.max.size.percent}</G1_MAX_NEW_SIZE_PERCENT>
     <!--調整編譯線程的數目,我們服務器都是8core配置所以這裏統一配置成8-->
     <CI_COMPILER_COUNT>${ci.compiler.count}</CI_COMPILER_COUNT>
     <!--eureka url 配置-->
     <EUREKA_SERVER>${eureka.url}</EUREKA_SERVER>
     <JAVA_OPTS>${java.opts}</JAVA_OPTS>
     </env>
     <baseImage>${docker.jre}:${docker.jre.version}</baseImage>
     <cmd>
     /sbin/tini java ${JAVA_OPTS} -jar ${project.build.finalName}.jar
     </cmd>
     <!--是否推送image-->
     <pushImage>${pushImage}</pushImage>
     <resources>
     <resource>
     <directory>${project.build.directory}</directory>
     <include>${project.build.finalName}.jar</include>
     </resource>
     </resources>
     <!--這裏與你的配置的私服id一致-->
     <serverId>aliyun-registry</serverId>
     </configuration>
     <executions>
     <execution>
     <phase>package</phase>
     <goals>
     <goal>build</goal>
     </goals>
     </execution>
     </executions>
     </plugin>
    <plugins>
    </pluginManagement>

多環境配置

  • 完成了插件的配置和變量的抽取之後我們具體使用將十分的簡單
  • 下面我貼出常見的一些profile
<profiles>
    <profile>
     <!--高度靈活的profile-->
     <id>docker</id>
     <build>
     <plugins>
     <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-shade-plugin</artifactId>
     </plugin>
     <plugin>
     <groupId>com.spotify</groupId>
     <artifactId>docker-maven-plugin</artifactId>
     </plugin>
     </plugins>
     </build>
    </profile>
    <profile>
     <!--prod的profile-->
     <id>prod</id>
     <properties>
     <base.docker.repository>${docker.registry}</base.docker.repository>
     <eureka.url>${prod.eureka}</eureka.url>
     <g1.new.size.percent>${g1.new.size.percent}</g1.new.size.percent>
     <g1.max.size.percent>${g1.max.size.percent}</g1.max.size.percent>
     <jvm.Xms>${prod.jvm.Xms}</jvm.Xms>
     <jvm.Xmx>${prod.jvm.Xmx}</jvm.Xmx>
     <pushImage>true</pushImage>
     <spring.profile>prod</spring.profile>
     </properties>
     <build>
     <plugins>
     <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-shade-plugin</artifactId>
     </plugin>
     <!--prod的默認激活git插件方便使用tag做爲版本號-->
     <plugin>
     <groupId>pl.project13.maven</groupId>
     <artifactId>git-commit-id-plugin</artifactId>
     </plugin>
     <plugin>
     <groupId>com.spotify</groupId>
     <artifactId>docker-maven-plugin</artifactId>
     </plugin>
     </plugins>
     </build>
    </profile>
    <profile>
     <!--test的profile-->
     <id>test</id>
     <properties>
     <base.docker.repository>${test.docker.repository}</base.docker.repository>
     <eureka.url>${test.eureka}</eureka.url>
     <g1.new.size.percent>40</g1.new.size.percent>
     <g1.max.size.percent>70</g1.max.size.percent>
     <jvm.Xms>${test.jvm.Xms}</jvm.Xms>
     <jvm.Xmx>${test.jvm.Xmx}</jvm.Xmx>
     <pushImage>false</pushImage>
     <!--test環境直接指定dockerimage說的版本號爲latest-->
     <git.commit.id.describe-short>latest</git.commit.id.describe-short>
     <spring.profile>test</spring.profile>
     </properties>
     <build>
     <plugins>
     <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-shade-plugin</artifactId>
     </plugin>
     <plugin>
     <groupId>com.spotify</groupId>
     <artifactId>docker-maven-plugin</artifactId>
     </plugin>
     </plugins>
     </build>
    </profile>
    </profiles>
## [](https://qingmu.io/2018/08/07/How-to-run-springcloud-in-docker/#構建 "構建")構建
  • 打包prod版本的
mvn clean pacakge  -Pprod
  • 打包test版本的
mvn clean pacakge  -Ptest
  • 打包個性化的版本的
mvn clean pacakge -Djvm.Xms=8G -Djvm.Xmx=8G  -Pdocker

檢驗

  • 如果你配置正確,你將會看到如下輸出,如果你還開啓的push,那麼將看到push的日誌
[INFO] --- docker-maven-plugin:1.2.0:build (default) @ user-server ---
    [INFO] Using authentication suppliers: [ConfigFileRegistryAuthSupplier, FixedRegistryAuthSupplier]
    [INFO] Copying /Users/freeman/IdeaProjects2/user-server/target/user-server.jar -> /Users/freeman/IdeaProjects2/user-server/target/docker/user-server.jar
    [INFO] Building image hub.mayixiaoke.com/my/user-server:latest
    Step 1/12 : FROM freemanliu/openjre:1.8.0_171_font

     ---> 753ecb9267d1
    Step 2/12 : ENV CI_COMPILER_COUNT 8

     ---> Using cache
     ---> 93bebb3621d4
    Step 3/12 : ENV EUREKA_SERVER "-DEUREKA_SERVER=http://192.168.0.204:8761/eureka/"

     ---> Running in 42d31fcd4a7d
    Removing intermediate container 42d31fcd4a7d
     ---> c1e478140e99
    Step 4/12 : ENV G1_MAX_NEW_SIZE_PERCENT 70

     ---> Running in 794778b524dc
    Removing intermediate container 794778b524dc
     ---> 6cf5ff851174
    Step 5/12 : ENV G1_NEW_SIZE_PERCENT 40

     ---> Running in 85592d62fe30
    Removing intermediate container 85592d62fe30
     ---> 8b69e9c6371e
    Step 6/12 : ENV JAVA_HEAP_XMS 450m

     ---> Running in 683b34295fec
    Removing intermediate container 683b34295fec
     ---> 24917bf053e6
    Step 7/12 : ENV JAVA_HEAP_XMX 2G

     ---> Running in 74ba3caadd4b
    Removing intermediate container 74ba3caadd4b
     ---> d1bd5ba01b7d
    Step 8/12 : ENV JAVA_OPTS -Dservice.name=user-server             -XX:+UnlockExperimentalVMOptions             -Xms${JAVA_HEAP_XMS}             -Xmx${JAVA_HEAP_XMX}             -XX:CICompilerCount=${CI_COMPILER_COUNT}             -XX:G1NewSizePercent=${G1_NEW_SIZE_PERCENT}             -XX:G1MaxNewSizePercent=${G1_MAX_NEW_SIZE_PERCENT}             -DEUREKA_SERVER=${EUREKA_SERVER}             -Dspring.profiles.active=test             -Dspring.cloud.config.profile=test             -XX:+UseG1GC             -XX:+AggressiveOpts             -XX:+UseFastAccessorMethods             -XX:+UseStringDeduplication             -XX:+UseCompressedOops             -XX:+OptimizeStringConcat

     ---> Running in 2b4e73c01ad7
    Removing intermediate container 2b4e73c01ad7
     ---> 2fd9b3ffa0ad
    Step 9/12 : ENV TZ Asia/Shanghai

     ---> Running in 85946bd9bb3c
    Removing intermediate container 85946bd9bb3c
     ---> b588ab3d7e2c
    Step 10/12 : WORKDIR /work

     ---> Running in a41a0545883f
    Removing intermediate container a41a0545883f
     ---> 53c863bbcdbf
    Step 11/12 : ADD user-server.jar .

     ---> a3cf23754886
    Step 12/12 : CMD /sbin/tini java ${JAVA_OPTS} -jar user-server.jar

     ---> Running in c3a716574080
    Removing intermediate container c3a716574080
     ---> 262898825ee2
    ProgressMessage{id=null, status=null, stream=null, error=null, progress=null, progressDetail=null}
    Successfully built 262898825ee2
    Successfully tagged hub.xxxx.com/my/user-server:latest
    [INFO] Built hub.xxxx.com/my/user-server:latest
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  26.332 s
    [INFO] Finished at:
    [INFO] ------------------------------------------------------------------------
  • 如果你使用的cmd命令跟我一樣,那麼你還可以執行sh終端,查看我們的環境變量
docker run -it --rm hub.xxx.com/my/user-server:latest sh
    echo $JAVA_OPTS
    -Dservice.name=user-server -XX:+UnlockExperimentalVMOptions -Xms450M -Xmx2G -XX:CICompilerCount=8 -XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=60 -DEUREKA_SERVER=-DEUREKA_SERVER=http://192.168.0.204:8761/eureka/ -Dspring.profiles.active=prod -Dspring.cloud.config.profile=prod -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:+UseStringDeduplication -XX:+UseCompressedOops -XX:+OptimizeStringConcat
  • 如果你感興趣還可以這樣
docker run -it --rm -e JAVA_HEAP_XMS=8G -e JAVA_HEAP_XMX=8G hub.xxx.com/my/user-server:latest sh
    echo $JAVA_OPTS
    -Dservice.name=user-server -XX:+UnlockExperimentalVMOptions -Xms4G -Xmx4G -XX:CICompilerCount=8 -XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=60 -DEUREKA_SERVER=-DEUREKA_SERVER=http://192.168.0.204:8761/eureka/ -Dspring.profiles.active=prod -Dspring.cloud.config.profile=prod -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UseFastAccessorMethods -XX:+UseStringDeduplication -XX:+UseCompressedOops -XX:+OptimizeStringConcat
  • 思考:同理我們想要靈活的修改其他參數是不是一個流程呢?比如我要修改G1的G1NewSizePercent和G1MaxNewSizePercent。有幾種方式呢?你覺得那種方式更優雅呢?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章