Dockerfile Idiomshtml
分發更小的容器,是一種應該被推薦的行爲。java
更小的容器,啓動會更快,分發會更快,重用會更快,……。對於生命來講,快是一種態度,表明你的時間被消費的更有價值:節約時間老是正確的。node
幾年前,其實我就想寫有關容器縮減的內容,不過那時候 alpine 還不被重視,它本身也很難用,因此咱們更多地是在 ubuntu 這樣的大塊頭上研究怎麼削減最終尺寸。python
值得欣慰的是,那些曾經用到的原則一直都是對的,儘管這個世界、這些生態在變,但準則沒有變。linux
如今,關於容器尺寸削減的問題,文章多得很,問答也不少。git
但我仍是打算寫一篇。寫者嘛,老是以爲本身寫的內容對一點,邏輯對一點,用詞對一點,覆蓋面對一點,限定語對一點。等等。github
不過,此次準備隨便寫,不打算整構邏輯了。golang
削減容器的最終尺寸,首先考慮以下的 Checklist:docker
採用更小的基準包shell
選取最恰當的基準包。
alpine:latest
是最佳選擇
golang:alpine
可能纔是對的node:8-alpine
使用包安裝命令時,記住清除包安裝過程所下載的索引、安裝包
後面我會在慣用法中更多介紹這一點。
去掉內存交換機制,去掉交換分區
不要安裝帶有 ncurse 依賴的工具,例如 mc
不要安裝帶有調試工具或者調試工具性質的工具,例如 vim,curl。必定要用,使用 nano 和 wget 替代它們
調整命令順序,合併相同命令,使得產生更少的層
使用記憶功能以便去掉打包過程當中纔會使用的包,從而縮減最終容器尺寸
這個記憶功能,主要是指 alpine apk --virtual
功能;對於 apt 則有一個 apt-mark 工具。
對於 apt 使用 apt install --no-install-recommends -y
方式
使用多遍構建過程,將打包和中間內容排除在最終容器以外,以縮減其尺寸
下面都是基於 voxr vdeps-base 來介紹。
較典型的作法是這樣子:
RUN fetchDeps=" \ ca-certificates \ bash less nano iputils bind-tools busybox-extras \ wget lsof unzip \ "; \ apk update \ && apk --update add ${fetchDeps} \ && apk info -vv | sort \ && apk -v cache clean && rm /var/cache/apk/* # 摘自 https://github.com/hedzr/docker-basics/blob/master/alpine-base/Dockerfile 複製代碼
apk -v cache clean
和 rm /var/cache/apk/*
二者選一就能夠了,這裏只是爲了示例。
比上例更嚴格精確、也更節省空間的辦法是:
RUN build-deps="gcc
freetype-dev \
musl-dev \
"; \
apl add --update --no-cache bash less nano unzip && \
apk add --no-cache --virtual .build-deps ${buildDeps} && \
pip install --no-cache-dir requests && \
apk del .build-deps && \
rm /var/cache/apk/*
複製代碼
採用國內鏡像服務器加速,更溫馨的結構:
# 改編自 hedzr/docker-basics/golang-builder RUN fetchDeps=" \ ca-certificates \ "; \ buildDeps=" tig "; \ cp /etc/apk/repositories /etc/apk/repositories.bak; \ echo "http://mirrors.aliyun.com/alpine/v3.10/main/" > /etc/apk/repositories; \ apk update \ && apk add --virtual .build-deps ${buildDeps} \ && apk add ${fetchDeps} \ && echo && echo "Put your building scripts HERE" \ && apk del .build-deps \ && rm /var/cache/apk/* \ 複製代碼
RUN fetchDeps=" \ ca-certificates \ wget nano vim.tiny net-tools iputils-ping lsof \ dnsutils inetutils-telnet locales \ "; \ TZ=Etc/UTC; LOCALE=en_US.UTF-8; \ apt update \ && DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends ${fetchDeps} \ && locale-gen $LOCALE \ && cat /etc/default/locale && echo "Original TimeZone is: $(locale -a)" && date +'%z' \ && ln -s /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ | tee /etc/timezone \ && echo "Current TimeZone updated: $(locale -a)" && date +'%z' \ # && apt-get purge -y --auto-remove ${fetchDeps} \ && rm -rf /var/lib/apt/lists/* # 時鐘時區部分能夠去掉 # 摘自 https://github.com/hedzr/docker-basics/blob/master/ubuntu-mod/Dockerfile 複製代碼
對於用到 python pip 的場景還能夠這樣:
RUN buildDeps="curl python-pip" && \ apt-get update && \ apt-get install -y --no-install-recommends $buildDeps && \ pip install requests && \ apt-get purge -y --auto-remove $buildDeps && \ rm -rf /var/lib/apt/lists/* 複製代碼
用到 build-essential 或者 gcc 系的也能夠相似地處理:
RUN buildDeps="curl wget build-essentials flex bison make cmake autoconf automake git libtool" && \ fetchDeps="nano wget curl" apt-get update && \ apt-get install -y --no-install-recommends $fetchDeps && \ AUTO_ADDED_PACKAGES=`apt-mark showauto` && \ apt-get install -y --no-install-recommends $buildDeps && \ mkdir build && cd build && cmake .. && make && make install && \ apt-get purge -y --auto-remove $buildDeps $AUTO_ADDED_PACKAGES && \ rm -rf /var/lib/apt/lists/* 複製代碼
注意到咱們採用了 AUTO_ADDED_PACKAGES
機制,這是一種 Debian 包管理系的記憶功能,能夠被用來很好地削減尺寸。
相似 apt,再也不贅述了
儘管包管理的記憶功能可以完美地削減容器尺寸,但它並不是是沒有缺點的:
你必須在單句 RUN
中寫出記憶以及消除記憶的所有腳本,若是分割到多句指令,那麼容器中的 OS的佔地面積依然能被收縮,但容器的尺寸可能並不能被削減。
若是你在單句 RUN
指令中完成了你的整個容器構建腳本的話,構建的開發過程將會很是痛苦,由於冗長的指令序列不能被緩存到多層中,因此每一次微小的變化都會致使 docker build
去完整地重建你的這個容器。
因此縮減容器尺寸,應該是當你的容器構建過程已經開發完成以後纔去作的事情。
好的,記憶功能有點點不完美,可是多遍構建可以很好地平衡這一切問題。
以 golang 應用的容器化爲例,下面是一個多遍構建的例子:
FROM golang:1.7.3 AS builder WORKDIR /go/src/github.com/alexellis/href-counter/ RUN go get -d -v golang.org/x/net/html COPY app.go . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /go/src/github.com/alexellis/href-counter/app . CMD ["./app"] # 摘自 https://github.com/alexellis/href-counter 複製代碼
好吧,我本身的寫的複雜得多,但暫時還不能展現,此外,複雜的版本也不利於闡述骨架結構。
寫到這裏,暫時告一段落了。
關於縮減尺寸以及 Dockerfile 的慣用寫法,也就先說這麼多了。再要釋出點什麼也不是不能夠,但可能涉及到的就不是僅僅 Docker 的知識了。
結果仍是分了分章節,哎呀德性了