docker鏡像瘦身思路
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