精簡docker鏡像的建議

精簡docker鏡像的建議

作者: 張首富
時間: 2019-05-03
個人博客: www.zhangshoufu.com
QQ羣: 895291458

前提

因爲公司業務需求,需要到客戶現場部署我們代碼的離線環境,因爲各大銀行和運營商所提供的底層系統各不相同,代碼不一定能運行的起來,所以我們就採用了docker版的離線部署方式,報我們所有的應用全打成docker包,然後再到客戶現場部署.
但是這又引發了另外一個問題,因爲我們的客戶一般都是銀行和運營商,所以我們要拷貝個東西到他們的系統裏面是很費勁的,因爲全是docker包,因爲我們打包沒有精簡,導致打出來的docker非常龐大,傳輸文件到客戶服務器裏面往往需要大半天時間或者更久.
爲了提高工作效率,縮短傳輸包的時間,我們決定對docker鏡像進行精簡

精簡docker鏡像的必要性

1,我們大家都知道docker鏡像是分層存儲的,鏡像層依賴於一系列底層技術(FileSystem,copy-on-wirte,union mounts聯合掛載),而docker鏡像最多有127層,當超過127層的時候docker鏡像打包就會失敗.
2,精簡docker鏡像大小能減少我們的構建時間,只裝必須使用的包,不需要的就不裝
3,減少磁盤使用量
4,因爲包含的文件少,所以漏洞如果就少
5,傳輸速度,部署速度加快

精簡docker鏡像的建議

a, 選擇基礎鏡像

當我們編寫Dockerfile FROM的時候選擇最合適的最小的基礎鏡像,我們在這個基礎上安裝我們必須的安裝包.
常用的 Linux 系統鏡像一般有 Ubuntu、CentOs、Alpine,其中 Alpine 更推薦使用。大小對比如下:

Alpine 是一個高度精簡又包含了基本工具的輕量級 Linux 發行版,基礎鏡像只有 4.41M,各開發語言和框架都有基於 Alpine 製作的基礎鏡像,強烈推薦使用它。

查看上面的鏡像尺寸對比結果,你會發現最小的鏡像也有 4.41M,那麼有辦法構建更小的鏡像嗎?答案是肯定的,例如 gcr.io/google_containers/pause-amd64:3.1 鏡像僅有 742KB。爲什麼這個鏡像能這麼小?在爲大家解密之前,再推薦兩個基礎鏡像:

1) scratch 鏡像

scratch 是一個空鏡像,只能用於構建其他鏡像,比如你要運行一個包含所有依賴的二進制文件,如centos 7.5鏡像,他就是基於scratch來構建的,他的Dockerfile文件來構建的

FROM scratch
ADD centos-7-docker.tar.xz /

LABEL org.label-schema.schema-version = "1.0" \
    org.label-schema.name="CentOS Base Image" \
    org.label-schema.vendor="CentOS" \
    org.label-schema.license="GPLv2" \
    org.label-schema.build-date="20180531"

CMD ["/bin/bash"]

centos鏡像使用了scratch 作爲基礎鏡像,這個鏡像本身是不佔空間的,使用它構建的鏡像大小几乎和二進制文件本身一樣大,所以鏡像非常小。

2) busybox 鏡像

scratch 是個空鏡像,如果希望鏡像裏可以包含一些常用的 Linux 工具,busybox 鏡像是個不錯選擇,鏡像本身只有 1.16M,非常便於構建小鏡像。

b, 串聯 DOckerfile 指令

大家在定義 Dockerfile 時,如果太多的使用 RUN 指令,經常會導致鏡像有特別多的層,鏡像很臃腫,而且甚至會碰到超出最大層數(127層)限制的問題,遵循 Dockerfile 最佳實踐,我們應該把多個命令串聯合併爲一個 RUN(通過運算符&&和/ 來實現),每一個 RUN 要精心設計,確保安裝構建最後進行清理,這樣纔可以降低鏡像體積,以及最大化的利用構建緩存。
下面是一個優化前 Dockerfile:
下面的例子只是做個測試,正常來講沒有人會這樣構建docker鏡像
docker鏡像打包比對

FROM centos:7.5.1804
COPY ./*.repo /etc/yum.repos.d/
RUN yum -y install nginx 
RUN yum -y install mariadb*
CMD nginx
FROM centos:7.5.1804
COPY ./*.repo /etc/yum.repos.d/
RUN yum -y install nginx  mariadb*
CMD nginx
FROM centos:7.5.1804
COPY ./*.repo /etc/yum.repos.d/
RUN yum -y install nginx  mariadb* && \
    yum clean all
CMD nginx
REPOSITORY                                           TAG                 IMAGE ID            CREATED             SIZE
test                                                 V3.0                4ce16d6e1859        6 seconds ago       586MB
test                                                 V2.0                6cb5da7d6afc        26 minutes ago      685MB
test                                                 V1.0                49738c7042d6        31 minutes ago      805MB

通過上面的實驗,我們可以看出,將yum命令分成兩個RUN來寫遠遠比卸載一個RUN裏面節省空間大小的多。
兩個鏡像所安裝的軟件全是一模一樣,但是一個RUN和兩個RUN有本質的區別,因爲每多一個RUN鏡像就會多一層

c,使用多階段構建

Dockerfile 中每個指令都會爲鏡像增加一個鏡像層,並且你需要在移動到下一個鏡像層之前清理不需要的組件,實際上,有一個Dockerfile用於開發,(其中
包含構建應用程序所需的所有內容)以及一個用於生產的瘦客戶端,它只包含您的應用程序以及運行它所需的內容,“這被稱爲建造者模式”。Dockerfile 17.05.0-ce 版本
以後支持多階段構建,使用多階段構建,你可以在Dockerfile中使用多個FROM 語句,每條 FROM 指令可以使用不同的基礎鏡像,這樣可以選擇性的將服務組件從一個階段
COPY到另一個階段,最終只保留鏡像中需要的內容。

d, 構建業務鏡像的技巧

1,把依賴的庫和代碼分成COPY,因爲docker鏡像打包的時候回去中心倉庫(server端)對比有沒有相同的層,有相同的層直接拿來使用,所以我們儘量把不會改變成東西
放在一層,這樣我們打包速度就會很快了
2,使用代碼本身的啓動,不要安裝一些無所謂的東西來輔助啓動,因爲我發現有好多開發會把代碼使用Supervisor的方式去啓動他的代碼,這種方式是違法了docker本身
的理念的,因爲這種可能造成docker啓動沒問題,但是裏面的服務不正常

e,其他優化方法

1,使用yum 或者apt安裝完軟件之後刪除緩存的安裝數據
2, apt-get install 可以添加 --no-install-recommends參數來不安裝非必須的依賴
3,能用一條命令RUN完的就不要寫兩條

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章