【docker】大小仅3GB的Oracle21c的docker镜像,含apex和oml4py

前言

之前在【ORACLE】从安装ORACLE LINUX 8开始构建一个ORACLE21C的docker镜像这篇文章中,最后构建出来的docker镜像有15GB,上传阿里云压缩后也有9GB,我怎么算都不对劲,系统100M,数据库也就几个GB,加上APEX,怎么也应该也不会超过10GB,有没有办法把大小压一压呢?

问题分析

于是我运行了一下

image history imageid

image.png

发现有些层的数据大小出现了重复,有个3GB大小的额外出现了2次,所以导致整个镜像很大。于是我又仔细看了下Tim Hall的dockefile,发现写得很整齐规范,根据执行内容的不同,把代码分成了很多个阶段,并标有注释。

但是,对于dockerfile来说,每执行一条指令,它就会构建一个新的层。如果某条指令有修改现有的文件,那么它就会把数据都复制出一个新的层,这样大小就翻倍了。就算在本层把无用大文件删掉,上一层的大小还是不会变,因为上一层还有这个大文件。

所以,有时候会发现,常见的dockerfile都是用"&&\"把代码合并成一条来执行的,但本次的dockerfile代码量有点多,全合成一行不方便查看和修改,所以此时就要引入多阶段构建的概念。

Docker Engine 17.05 中引入了多阶段构建语法。
docker官方关于多阶段构建的说明https://docs.docker.com/develop/develop-images/multistage-build/

关于这个多阶段构建,我看了不少国内的文章介绍,但是大部分都是复制了一次官方的例子,或者稍做修改,完全没有找到我想要的用法。绝大部分能搜到的例子都是使用前一阶段的构建作为后一阶段构建的部分文件,而我需要的是只保留最后一个指令执行后的数据,前面不管有多少层都不要了。

于是我开始在github上搜“dockerfile”,看别人是怎么写的,果然绝大多数都是把指令都用"&&\"合并成了一条,然后我继续找,直到看到zabix的一个dockerfile,瞬间得到了启发,
https://github.com/zabbix/zabbix-docker/blob/5.4/Dockerfiles/server-pgsql/ol/Dockerfilez

COPY --from=builder ["/tmp/zabbix-${ZBX_VERSION}/src/zabbix_server/zabbix_server", "/usr/sbin/zabbix_server"]

因为我搜到的其他例子大多都是这么写的

COPY --from=builder /go/src/github.com/helloworld/app .
COPY --from=builder /build/server /

搜不到一例复制所有文件的,所以不清楚这个语法应该是 “/ /” 还是 “. .”,是复制文件夹还是复制文件夹中的所有文件?但是有了zabix的这个例子,它是使用了一个包含两个元素的list,前面和后面都是一个文件夹,且末尾没有"/",类型是一样的,那么理论上,它是支持同名文件夹直接覆盖的。

解决方案

所以,我的想法是,无论一个dockerfile前面执行了多少条指令,我只要在最后,再执行一次构建,构建的源镜像和第一阶段的源镜像保持一致(理论上,空镜像也行?),然后把第一阶段最终构建的所有文件都复制到第二阶段构建中去,那么第二阶段的镜像就只有一层了,而且这种方法是通用的。

就像这样:

FROM oraclelinux:8 as builder
...
#一堆命令
...

FROM oraclelinux:8
COPY --from=builder ["/", "/"]

于是开始实测,首先我把第二次构建加在了CMD命令的后面,发现以这个镜像创建容器并启动后,它并不会执行CMD中的内容,于是我就把第二次构建向上移动一条,结果又发现,构建的环境变量不会被继承,于是我又把第一阶段声明的环境变量在第二阶段又复制粘贴了一次。最终果然成功了。
原始版本结构是这个样子

FROM oraclelinux:8 
ENV ORACLE_BASE=/u01/app/oracle 

...
#一堆命令
...

CMD exec ${SCRIPTS_DIR}/start.sh

改之后结构为这个样子

FROM oraclelinux:8 as builder
ENV ORACLE_BASE=/u01/app/oracle 

...
#一堆命令
...

FROM oraclelinux:8
COPY --from=builder ["/", "/"]
ENV ORACLE_BASE=/u01/app/oracle 
CMD exec ${SCRIPTS_DIR}/start.sh

可以看到并不用修改多少代码,即可把所有无用的层都干掉,每个文件只留一份数据。

成品

按这个方案构建后,最终的镜像大小只有9GB了
image.png

然后上传阿里云
image.png

阿里云压缩后只有3G了
image.png

项目地址:https://github.com/Dark-Athena/dockerfile/tree/main/ol8_21_oml4py

docker pull及run:

docker pull registry.cn-shanghai.aliyuncs.com/darkathena/ol8_21_oml4py:2.0
docker run -dit --name ol8_21_con -p 1521:1521 -p 5500:5500 --shm-size="1G"  registry.cn-shanghai.aliyuncs.com/darkathena/ol8_21_oml4py:2.0

补充

其实Tim Hall也说了,这是他用来玩的,有些地方写得不是很好,不过我倒是通过这次亲自尝试,对docker又多了一点经验,要是一开始他的dockerfile构建的镜像很小,我又怎么会想到要去优化它呢?
https://github.com/oraclebase/dockerfiles

Just some Dockerfiles I’m playing around with. Some will be simple and stupid. Others might be a bit more useful to look at if you are learning about Docker.
Feel free to copy or fork this stuff. It’s unlikely I’ll accept pull requests as it’s just my playground.

 

posted on 2021-11-16 15:03  DarkAthena  阅读(152)  评论(0编辑  收藏  举报

导航