046-解決google jib多工問題
這是堅持技術寫作計劃(含翻譯)的第46篇,定個小目標999,每週最少2篇。
本文主要講解使用google jib打包應用時 如果 基礎映象是 openjdk 的alpine系列,執行成功後無法正常使用 jmap,jstack,arthas 等工具,報錯資訊如下
[ERROR] Start arthas failed,exception stack trace:
com.sun.tools.attach.AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread
at sun.tools.attach.LinuxVirtualMachine.(LinuxVirtualMachine.java:86)
at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:78)
at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:250)
at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:72)
at com.taobao.arthas.core.Arthas.(Arthas.java:25)
at com.taobao.arthas.core.Arthas.main(Arthas.java:99)
[ERROR] attach fail,targetPid: 1
複製程式碼
在之前寫的 使用Maven加速和簡化構建Docker(基於Google jib) 最後有提過,但是沒有詳細展開。
google jib 和 Dragonfly 系列文章
- 使用Maven加速和簡化構建Docker(基於Google jib)
- 012-P2P加速Docker映象分發(阿里Dragonfly)
- 013-阿里Dragonfly體驗之私有registry下載
- 046-解決google jib多工問題
簡述 google jib 和阿里 Dragonfly
阿里的dragonfly和google jib其實都在解決類似的問題,如何最大化的重用依賴。但是是兩個思路,dragonfly是在不改動源映象的基礎上,類似cdn的思路在近源快取資料,這樣一來區域網內就可以不用重複從公網拉取映象,同時因為使用了p2p傳輸,所以可以有效防止單機熱點打滿頻寬的問題。(d7y主要是使用p2p解決大檔案傳輸問題,用於映象傳輸只是捎帶手的一個功能),d7y是解決製成品如何優化傳輸。
google jib的思路是,侵入到構建過程中,發揮主人翁精神,我構建,我優化。比如在使用gradle,maven構建時,體積最大的是jre或者jdk,其次是各種三方jar包,再次之的是web中的靜態資源(那些往resource可勁塞檔案的不在討論範圍內),而這些東西往往又不會經常變動,而原始碼部分會經常變動,那麼將其分離開,利用docker的layer進行快取,既能節省空間,又能節省頻寬,又能節省時間。
配置google jib
settings.xml 增加auth配置
settings.xml 增加registry server 的auth認證,password可以用 maven password encryption
<settings>
...
<servers>
...
<server>
<id>MY_REGISTRY</id>
<username>MY_USERNAME</username>
<password>{MY_SECRET}</password>
</server>
</servers>
</settings>
複製程式碼
anjia0532/openjdk-8-alpine-lib的Dockerfile
FROM openjdk:8-jdk-alpine
ARG ARTHAS_VERSION="3.1.3"
ARG MIRROR=false
ENV MAVEN_HOST=http://repo1.maven.org/maven2 \
ALPINE_HOST=dl-cdn.alpinelinux.org \
MIRROR_MAVEN_HOST=http://maven.aliyun.com/repository/public \
MIRROR_ALPINE_HOST=mirrors.tuna.tsinghua.edu.cn
# if use mirror change to aliyun mirror site
RUN if $MIRROR; then MAVEN_HOST=${MIRROR_MAVEN_HOST} ;ALPINE_HOST=${MIRROR_ALPINE_HOST} ; sed -i "s/dl-cdn.alpinelinux.org/${ALPINE_HOST}/g" /etc/apk/repositories ; fi
RUN \
# https://github.com/docker-library/openjdk/issues/76
apk add --no-cache tini
RUN \
# change to GMT+0800 timezone
apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
RUN \
# download & install arthas
wget -qO /tmp/arthas.zip "${MAVEN_HOST}/com/taobao/arthas/arthas-packaging/${ARTHAS_VERSION}/arthas-packaging-${ARTHAS_VERSION}-bin.zip" && \
mkdir -p /opt/arthas && \
unzip /tmp/arthas.zip -d /opt/arthas && \
rm /tmp/arthas.zip
# Tini is now available at /sbin/tini
ENTRYPOINT ["/sbin/tini","--"]
複製程式碼
構建命令
docker build --build-arg MIRROR=true . -t anjia0532/openjdk-8-alpine-lib
複製程式碼
修改pom.xml
<project>
<groupId>com.example.module</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
...
<build>
<plugins>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>1.6.1</version>
<configuration>
<from>
<image>anjia0532/openjdk-8-alpine-lib</image>
</from>
<to>
<image>${project.artifactId}:${project.version}</image>
</to>
<container>
<entrypoint>
<shell>/sbin/tini</shell>
<option>--</option>
</entrypoint>
<args>
<arg>java</arg>
<arg>-cp</arg>
<arg>/app/resources/:/app/classes/:/app/libs/*</arg>
<arg>com.example.application</arg>
</args>
<ports>
<port>8080</port>
<port>8563</port><!-- arthas 埠 -->
</ports>
<environment>
<_JAVA_OPTIONS>-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/</_JAVA_OPTIONS>
</environment>
</container>
</configuration>
</plugin>
</plugins>
</build>
</project>
複製程式碼
主要起作用的是 tini,需要在entrypoint部分設定 /sbin/tini --
但是 根據檔案 github.com/GoogleConta… 所述
ENTRYPOINT ["java",jib.container.jvmFlags,"-cp","/app/resources:/app/classes:/app/libs/*",jib.container.mainClass]
CMD [jib.container.args]
複製程式碼
jib構建的應用,預設會使用 將啟動命令放到entrypoint 部分,會覆蓋掉baseimage裡寫的entryoint,如果在pom裡定義的話,又會覆蓋jib的預設啟動命令,所以只能將啟動專案放到 args 部分,但是又無法使用jvmFlags,預設cp,預設main類推斷,必須要顯式的自行宣告。
生成映象
mvn compile -Pprod jib:build # 構建並推送到目標registry上,構建主機不需要安裝docker
mvn compile -Pprod jib:dockerBuild # 構建到本機docker daemon
mvn compile -Pprod jib:buildTar # 構建並生成tar.gz,可以使用docker load --input target/jib-image.tar 匯入
複製程式碼
如果是在jenkins等CICD場景,每次讓研發修改pom不太方便,可以使用命令列來構建。
mvn compile com.google.cloud.tools:jib-maven-plugin:1.6.1:dockerBuild \
-Djib.to.image=myregistry/myimage:latest \
-Djib.to.auth.username=$USERNAME \
-Djib.to.auth.password=$PASSWORD \
-Djib.container.environment=key1="value1",key2="value2" \
-Djib.container.args=arg1,arg2,arg3
複製程式碼
另外
上述示例不管是maven還是gradle都是java類應用,對於nodejs或者golang,jib官方也支援使用者基於jib core自行編寫構建外掛
招聘小廣告
山東濟南的小夥伴歡迎投簡歷啊 加入我們,一起搞事情。
長期招聘,Java程式設計師,大資料工程師,運維工程師,前端工程師。