1. 程式人生 > 程式設計 >046-解決google jib多工問題

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 系列文章

簡述 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程式設計師,大資料工程師,運維工程師,前端工程師。

參考資料