docker映象瘦身思路

我可能是個假程式設計師發表於2020-06-20

docker映象瘦身思路

一、簡介

      docker映象太大,帶來了以下幾個問題:

  • 儲存開銷

      這塊影響其實不算很大,因為對伺服器磁碟來說,15GB的儲存空間並不算大,除非使用者伺服器的磁碟空間很緊張

  • 部署時間

      這塊影響真的很大,交付件zip包太大,導致使用者部署該產品時,花費的時間變長,客戶現場中反饋部署時間超過1.5小時,這嚴重影響使用者的體驗,降低滿意度

  • 效能不穩定

      如果客戶的伺服器規格不夠(特別是磁碟讀寫效能不夠),會增大部署失敗的概率。

二、瘦身思路

       以下思路是我在該任務中嘗試使用用於映象瘦身的方法,均可以不同程度的降低DOcker映象的尺寸。

  • 清理Docker映象中的無用安裝包

      在Dockerfile構建Docker映象過程中,有可能引入臨時檔案,比如:安裝包i、檔案壓縮包。這些臨時檔案忘記清理,導致佔據了一定的尺寸,有必要對其進行清理。

        如下Dockerfile:   

FROM xxxx/xxxx-jdk:1.0.0RUN apt-get update && apt-get install -y git maven 
mysql-client nodejs nodejs-legacy python-pip graphviz npm unzip  

Dockerfile裡面經常安裝很多工具,安裝完後,需要及時刪除安裝包快取

(alpine) apk del openssh vim:刪除包及其依賴包

(Ubuntu) Apt-get clean:刪除所有已下載的包檔案

(centos) Yum clean all: yum 會把下載的軟體包和header儲存在cache中,而不自動刪除。如果覺得佔用磁碟空間,可以使用yum clean指令進行清除,更精確 的用法是yum clean headers清除header,yum clean packages清除下載的rpm包,yum clean all一全部清除

      上面的dockerfile中在安裝工具後應該執行下: && apt-get clean && rm -rf /var/lib/apt/lists/*

RUN apt-get update && apt-get install -y git maven 
    mysql-client nodejs nodejs-legacy python-pip graphviz npm unzip && apt-get clean && rm -rf /var/lib/apt/lists/*

 

   例項:

      

FROM centos:7
RUN yum update -y
RUN yum install -y wget unzip socat java-1.8.0-openjdk-headless
# Set permissions
RUN yum clean all
EXPOSE 8486

 

   修改:將黃色標示的部分改寫成如下,大小從691Mb下降到583Mb

RUN yum update -y  && yum install -y wget unzip socat java-1.8.0-openjdk-headless && yum clean all
  • 避免不必要的工具安裝

     有的Dockerfile中安裝了很多工具,這個工具的加在一起尺寸比較大,這塊需要挨個排查:客戶環境下,需不需要安裝該工具?很多工具其實是面向開發使用的,而使用者根本不會使用,那麼就沒有必要在客戶環境上使用安裝這麼工具的映象,應該仔細排除工具的必要性,會給映象瘦身帶來比較大的收益。比如, dockerfile中安裝了JDK。 這個有些情況下,完全沒必要,實際上可能jre就能搞定。

     總之,能不安裝,就不安裝;能少安裝,就少安裝;能用輕量級的工具,儘量用輕量級的工具!!!

  • 多階段構建

      Docker多階段構建是17.05以後引入的新特性,旨在解決編譯、構建複雜和映象大小的問題。對於多階段構建,可以在Dockerfile中使用多個FROM語句。每個FROM指令可以使用不同的基礎,並且每個指令都開始一個新的構建。您可以選擇性地將工件從一個階段複製到另一個階段,從而在最終image中只留下您想要的內容。

      如下圖所示為多階段構建的使用示例:

把多個Dockerfile合併在一塊,每個Dockerfile單獨作為一個“階段”,“階段”之間可以互相聯絡,讓後一個階段構建可以使用前一個階段構建的產物,形成一條構建階段的chain,最終結果僅產生一個image,避免產生冗餘的多個臨時images或臨時容器物件。

       1)多階段構建使用之前

      針對多階段構建的特點,分析我們產品裡面的dockerfile,如下面所示,該操作的目的是將tar包拷貝值容器內的路徑下,並解壓、執行後續操作。然而COPY層具有一定的大小,只起到臨時層的作用。(特別是這個tar包足足幾百MB!)。

 

FROM xxxx:${project.version}COPY karaf-${ccsdk.opendaylight.version}.tar.gz /tmp/
RUN mkdir /opt/opendaylight \
      && tar zxvf /tmp/karaf-${ccsdk.opendaylight.version}.tar.gz --directory /opt/opendaylight \&& rm -rf /tmp/karaf-${ccsdk.opendaylight.version}.tar.gz \ 
      && mv /opt/opendaylight/karaf-${ccsdk.opendaylight.version} /opt/opendaylight/current && mkdir -p  /opt/opendaylight/current  && ln -s  /opt/opendaylight/current /opt/opendaylight/karaf-${ccsdk.opendaylight.version}
RUN mkdir -p /opt/opendaylight/current/system/org/mariadb/jdbc/mariadb-java-client/${ccsdk.mariadb-connector-java.version}
COPY mariadb-java-client-${ccsdk.mariadb-connector-java.version}.jar /opt/opendaylight/current/system/org/mariadb/jdbc/mariadb-java-client/${ccsdk.mariadb-connector-java.version}
EXPOSE 8181   

     2)  使用多階段構建

       使用多階段構建,修改後的dockerfile如下圖所示,修改實現將第一階段拷貝並解壓好的檔案複製過來即可,少了拷貝tar包的環節,這樣使得最終形成的映象中映象層數得到有效的降低,也一定程度上降低了映象尺寸。

FROM xxxx:${project.version} as baseFirst
COPY karaf-${ccsdk.opendaylight.version}.tar.gz /tmp/
RUN mkdir /opt/opendaylight \
      && tar zxvf /tmp/karaf-${ccsdk.opendaylight.version}.tar.gz --directory /opt/opendaylight \&& rm -rf /tmp/karaf-${ccsdk.opendaylight.version}.tar.gz \ 
      && mv /opt/opendaylight/karaf-${ccsdk.opendaylight.version} /opt/opendaylight/current 

FROM xxxxxe:${project.version} as baseSecondRUN mkdir -p  /opt/opendaylight/current  && ln -s  /opt/opendaylight/current /opt/opendaylight/karaf-${ccsdk.opendaylight.version}
COPY --from=baseFirst /opt/opendaylight/current  /opt/opendaylight/current
RUN mkdir -p /opt/opendaylight/current/system/org/mariadb/jdbc/mariadb-java-client/${ccsdk.mariadb-connector-java.version}
COPY mariadb-java-client-${ccsdk.mariadb-connector-java.version}.jar /opt/opendaylight/current/system/org/mariadb/jdbc/mariadb-java-client/${ccsdk.mariadb-connector-java.version}
EXPOSE 8181
  • Copy和賦權同時執行
FROM ubuntu:16.04
# Copy APIKeys
COPY ./messageservice/ /tmp/zookeeper/gerrit  ------A 
EXPOSE 2181 2888 3888
B------> RUN useradd $ZK_USER && [ `id -u $ZK_USER` -eq 1000 ] && [ `id -g $ZK_USER` -eq 1000 ] && chown -R $ZK_USER:$ZK_USER /opt/$ZK_DIST/ /opt/zookeeper/ /var/lib/ /var/log/ /tmp/zookeeper/    
USER $ZK_USER

      問題排查如下:A處copy的檔案700MB太大,很多檔案沒用到

                               B處給/tmp/zookeeper新增屬組和屬主,該層也很大

       修改:使用 COPY –chown=1000:1000   ./messageservice/ /tmp/zookeeper/gerrit, 映象大小從1.4GB 下降到700Mb

  • 映象層的複用

      這一塊修改得當的話,得到的收益是最大的!!!最大的!!!最大的!!!

      我們知道docker映象具有層級結構,如果很多映象具有相同的層,則這些相同的層就能得到複用(把多個映象生成一個tar),docker不會儲存兩份相同放入層檔案,通過提高層得複用能顯著降低整體的映象尺寸。比如常見方法有:替換統一的基礎映象、建立出統一的基礎映象、調整層的順序等等。這裡東西沒有整理,就不上圖了,可以自行腦補,查閱資料即可

我這邊經過這一步調整後,zip產品包從11.45GB下降到6.96GB

 

最終zip包從15GB下降到7GB

    

相關文章