共計 5311 個字符,預計需要花費 14 分鐘才能閱讀完成。
本篇內容介紹了“怎么精簡 Docker 鏡像”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓丸趣 TV 小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
介紹
前段時間網易蜂巢曾經推出蜂巢 Logo T 恤,用的正是 Docker 鏡像制作,最神奇的是,它最終的鏡像大小只有 585 字節。
$ docker images | grep hub.c.163.com/public/logo
REPOSITORY TAG IMAGE ID CREATED SIZE
hub.c.163.com/public/logo latest 6fbdd13cd204 11 days ago 585 B
點擊此處,可以了解該鏡像的制作過程,這其中就用到了不少精簡鏡像的技術,尤其是針對 C 程序的優化和精簡。但我們平常開發肯定不止用 C 語言,甚至有些鏡像都不是我們自己來打包的(比如下載公共鏡像),那是否有一些通用的精簡 Docker 鏡像的手段呢?答案是肯定的,甚至有的鏡像可以精簡 98%。精簡鏡像大小的好處不言而喻,既節省了存儲空間,又能節省帶寬,加快傳輸。那好,接下來就請跟隨我來學習怎么一步步精簡 Docker 鏡像吧。
鏡像層(Layers)
在開始制作鏡像之前,首先了解下鏡像的原理,而這其中最重要的概念就是鏡像層 (Layers)。鏡像層依賴于一系列的底層技術,比如文件系統(filesystems)、寫時復制(copy-on-write)、聯合掛載(union mounts) 等,幸運的是你可以在很多地方學習到這些技術,這里就不再贅述技術細節。
總的來說,你最需要記住這點:
在 Dockerfile 中, 每一條指令都會創建一個鏡像層,繼而會增加整體鏡像的大小。
舉例來說:
FROM busybox
RUN mkdir /tmp/foo
RUN dd if=/dev/zero of=/tmp/foo/bar bs=1048576 count=100
RUN rm /tmp/foo/bar
以上 Dockerfile 干了這幾件事:
基于一個官方的基礎鏡像 busybox(只有 1M 多)
創建一個文件夾 (/tmp/foo) 和一個文件(bar)
為該文件分配了 100M 大小
再把這個大文件刪除
事實上,它最終什么也沒做,我們把它構建成鏡像看看(構建可以參考一期):
docker build -t busybox:test .
再讓我們來對比下原生的 busybox 鏡像大小和我們生成的鏡像大小:
$ docker images | grep busybox
busybox test 896c63dbdb96 2 seconds ago 106 MB
busybox latest 2b8fd9751c4c 9 weeks ago 1.093 MB
出乎意料的是,卻生成了 106 MB 的鏡像。
多出了 100 M,這是為何?這點和 git 類似(都用到了 Copy-On-Write 技術),我用 git 做了如下兩次提交(添加了又刪除),請問 A_VERY_LARGE_FILE 還在 git 倉庫中嗎?
$ git add A_VERY_LARGE_FILE
$ git commit
$ git rm A_VERY_LARGE_FILE
$ git commit
答案是: 在的,并且會占用倉庫的大小。Git 會保存每一次提交的文件版本,而 Dockerfile 中每一條指令都可能增加整體鏡像的大小,即使它最終什么事情都沒做。
精簡步驟
了解了鏡像層知識,有助于我們接下來制作精簡鏡像。這里開始,以最常用的開源緩存軟件 Redis 為例,從一步步試驗,來介紹如何制作更精簡的 Docker 鏡像。
步驟 1:初始化構建 Redis 鏡像
直接上 Dockerfile:
FROM ubuntu:trusty
ENV VER 3.0.0
ENV TARBALL http://download.redis.io/releases/redis-$VER.tar.gz
# == Install curl and helper tools...
RUN apt-get update
RUN apt-get install -y curl make gcc
# == Download, compile, and install...
RUN curl -L $TARBALL | tar zxv
WORKDIR redis-$VER
RUN make
RUN make install
# == Clean up...
WORKDIR /
RUN apt-get remove -y --auto-remove curl make gcc
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /redis-$VER
CMD [redis-server]
結合注釋,讀起來并不困難,用到的都是常規的幾個命令,簡要介紹如下:
FROM:頂頭寫,指定一個基礎鏡像,此處基于 ubuntu:trusty
ENV:設置環境變量,這里設置了 VER 和 TARBALL 兩個環境變量
RUN:最常用的 Dockerfile 指令,用于運行各種命令,這里調用了 8 次 RUN 指令
WORKDIR:指定工作目錄,相當于指令 cd
CMD:指定鏡像默認執行的命令,此處默認執行 redis-server 命令來啟動 redis
執行構建:
$ docker build -t redis:lab-1 .
注:國內網絡,更新下載可能會較慢
查看大小:
| Lab | iamge | Base | Lang | .red[*] | Size (MB) | nbsp; nbsp; Memo |
|:---:|:--------|:-----------|:-----:|:---:|---------------:|:--------------------------------|
| 1 | redis | `ubuntu` | C | dyn | 347.3 | nbsp; nbsp; base ubuntu |
動輒就有 300 多 M 的大小,不能忍,下面我們開始一步步優化。
步驟 2: 優化基礎鏡像
方法:選用更小的基礎鏡像。
常用的 Linux 系統鏡像一般有 ubuntu、centos、debian,其中 debian 更輕量,而且夠用,對比如下:
REPOSITORY TAG IMAGE ID VIRTUAL SIZE
--------------- ------ ------------ ------------
centos 7 214a4932132a 215.7 MB
centos 6 f6808a3e4d9e 202.6 MB
ubuntu trusty d0955f21bf24 188.3 MB
ubuntu precise 9c5e4be642b7 131.9 MB
debian jessie 65688f7c61c4 122.8 MB
debian wheezy 1265e16d0c28 84.96 MB
替換 debian:jessie 作為我們的基礎鏡像。
優化 Dockerfile:
FROM debian:jessie
#...
執行構建:
$ docker build -t redis:lab-2 .
查看大小:
| Lab | image | Base | Lang | .red[*] | Size (MB) | nbsp; nbsp; Memo |
|:---:|:--------|:-----------|:-----:|:---:|---------------:|:--------------------------------|
| 01 | redis | `ubuntu` | C | dyn | 347.3 | nbsp; nbsp; base ubuntu |
| 02 | redis | `debian` | C | dyn | 305.7 | nbsp; nbsp; base debian |
減少了 42M,稍有成效,但并不明顯。細心的同學應該發現,只有 122 MB 的 debian 基礎鏡像,構建后增加到了 305 MB,看來這里面肯定有優化的空間,如何優化就要用到我們開頭說到的 Image Layer 知識了。
步驟 3:串聯 Dockerfile 指令
方法:串聯你的 Dockerfile 指令(一般是 RUN 指令)。
Dockerfile 中的 RUN 指令通過 和 / 支持將命令串聯在一起,有時能達到意想不到的精簡效果。
優化 Dockerfile:
FROM debian:jessie
ENV VER 3.0.0
ENV TARBALL http://download.redis.io/releases/redis-$VER.tar.gz
RUN echo == Install curl and helper tools... \
apt-get update \
apt-get install -y curl make gcc \
\
echo == Download, compile, and install... \
curl -L $TARBALL | tar zxv \
cd redis-$VER \
make \
make install \
...
echo == Clean up... \
apt-get remove -y --auto-remove curl make gcc \
apt-get clean \
rm -rf /var/lib/apt/lists/* /redis-$VER
CMD [redis-server]
構建:
$ docker build -t redis:lab-3 .
查看大小:
| Lab | Image | Base | Lang | .red[*] | Size (MB) | nbsp; nbsp; Memo |
|:---:|:--------|:-----------|:-----:|:---:|---------------:|:--------------------------------|
| 01 | redis | `ubuntu` | C | dyn | 347.3 | nbsp; nbsp; base ubuntu |
| 02 | redis | `debian` | C | dyn | 305.7 | nbsp; nbsp; base debian |
| 03 | redis | `debian` | C | dyn | 151.4 | nbsp; nbsp; cmd chaining |
哇!一下子減少了 50%,效果明顯啊!這是最常用的一個精簡手段了。
步驟 4:壓縮你的鏡像
方法:試著用命令或工具壓縮你的鏡像。
docker 自帶的一些命令還能協助壓縮鏡像,比如 export 和 import
$ docker run -d redis:lab-3
$ docker export 71b1c0ad0a2b | docker import - redis:lab-4
但麻煩的是需要先將容器運行起來,而且這個過程中你會丟失鏡像原有的一些信息,比如:導出端口,環境變量,默認指令。
所以一般通過命令行來精簡鏡像都是實驗性的,那么這里再推薦一個小工具:docker-squash。用起來更簡單方便,并且不會丟失原有鏡像的自帶信息。
下載安裝:
壓縮操作:
$ docker save redis:lab-3 \
| sudo docker-squash -verbose -t redis:lab-4 \
| docker load
注:該工具在 Mac 下并不好使,請在 Linux 下使用
對比大小:
| Lab | Image | Base | PL | .red[*] | Size (MB) | nbsp; nbsp; Memo |
|:---:|:--------|:-----------|:-----:|:---:|---------------:|:--------------------------------|
| 01 | redis | `ubuntu` | C | dyn | 347.3 | nbsp; nbsp; base ubuntu |
| 02 | redis | `debian` | C | dyn | 305.7 | nbsp; nbsp; base debian |
| 03 | redis | `debian` | C | dyn | 151.4 | nbsp; nbsp; cmd chaining |
| 04 | redis | `debian` | C | dyn | 151.4 | nbsp; nbsp; docker-squash |
“怎么精簡 Docker 鏡像”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注丸趣 TV 網站,丸趣 TV 小編將為大家輸出更多高質量的實用文章!