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 的知识了。
结果仍是分了分章节,哎呀德性了