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