构建镜像优化经验
构建镜像已经简单到docker build 或 buildkit build了,但优化镜像成了下一个问题。
体积优化
Layer层数据是叠加的
容器镜像由多个Layer层数据组装而成,每一条命令结果都会以一个层存储并逐渐叠加。
缓存数据
以Python
镜像安装诸多包为例。
# py-pip1.dockerfile
FROM python
# 安装每个包都以RUN命令独立实现
RUN pip3 install flask -i https://mirrors.aliyun.com/pypi/simple
....
RUN pip3 cache purge
# py-pip2.dockerfile
FROM python
RUN <<EOF
# 安装每个包以EOF合并语法实现,即一条RUN
pip3 install flask -i https://mirrors.aliyun.com/pypi/simple
...
pip3 cache purge
EOF
# py-pip3.dockerfile
FROM python
COPY <<EOF /opt/requirement.txt
# 以EOF语法,由COPY命令将依赖包名写入到requirement.txt
flask
...
EOF
RUN <<EOF
pip3 install -r /opt/requirement.txt -i https://mirrors.aliyun.com/pypi/simple
pip3 cache purge
EOF
三个命令构建镜像结果如下:
可以见到第一个镜像体积比后者大。
这是因为容器镜像Layer层数据是叠加的,上层会遮蔽下层的数据,但不会减少数据。
建议:执行命令若有产生缓存的,则可以追加命令删除缓存释放空间。
pip -> pip cache purge
yum/dnf -> yum/dnf clean all && rm -rf /var/cache/yum
apt -> apt install --no-install-recommends pkg && apt-get clean
npm -> npm cache clean -f
冗余的改权操作
构建镜像时会遇到某些文件需要改变权限,那么就Run chmod +x file
,但是这样是有问题的。
# chmod-1.dockerfile
FROM python
COPY bisheng-jdk-8u402-linux-x64.tar.gz /opt
# chmod-2.dockerfile
FROM python
COPY bisheng-jdk-8u402-linux-x64.tar.gz /opt
RUN chmod 777 /opt/bisheng-jdk-8u402-linux-x64.tar.gz
# chmod-3.dockerfile
FROM python
COPY --chmod=777 bisheng-jdk-8u402-linux-x64.tar.gz /opt
bisheng-jdk包体积为112M。
分别构建镜像得到以下结果。
可见到chomod-2.dockerfile
的执行结果会增长0.1G数据,正是执行变权的步骤导致。
所以当需要变权的文件体积越大镜像就会越大。
建议:采取COPY/ADD --chmod --chown
一步解决,或者导入前在本地环境已经将包改权完毕。
多阶段构建
在前文更注重的优化冗余编译步骤或编译结果,而多阶段编译也可以实现。
# go-normal.dockerfile
FROM golang
COPY jscli /opt
WORKDIR /opt
RUN <<EOF
go env -w GOPROXY=https://goproxy.cn,direct
go build -o js-cli
EOF
# go-more.dockerfile
FROM golang
COPY jscli /opt
WORKDIR /opt
RUN <<EOF
go env -w GOPROXY=https://goproxy.cn,direct
go build -o js-cli
EOF
FROM golang
COPY --link --from=0 /opt/js-cli /opt
分别构建得到镜像结果如上图,通过多阶段编译指定获取前置步骤的结果文件即可忽略之前考虑的缓存问题,当然如果你在后置步骤中又引入了缓存那还是要自己解决的。