特别注意:阅读该文章,需要一点Docker相关的知识。
最近一段时间,随着Docker被墙,网上出现了一大堆相关的技术文档,我们不去讨论这些问题。今天我们换个角度来说说这个问题,如何完全不依赖外部仓库,从零构建一个自己的镜像呢?
首先,互联网上有很多镜像,我给他们定义了2种分类:
1. 操作系统镜像(包括常见的Centos,Ubuntu,Debian,Alpine,Busybox等)。
Debian: Docker官方镜像使用的源。
Alpine: Docker官方也开始采用它作为源。
Busybox: 一个超小型的镜像(1.24MB),里面有不少命令,一般用于测试。
2. 业务镜像(包括常见的中间件镜像,比如JDK,Nginx,RabbitMQ,MYSQL等)。
其次,我们知道在我们写Dockerfile的时候,都需要写一个FROM镜像,那我们有没有想过一个问题,第一个镜像是从哪里来的,在第一个镜像来之前,他是如何规避这个问题的。肯定有的人会说,可以使用FROM scratch。是的,我们就是使用该方式来构建一个完全属于自己的镜像,这个镜像可以是一个操作系统,比如自己日常使用的操作系统镜像,甚至可以只包含应用程序的镜像,没有底层依赖。
官方镜像
首先我们要先分析下操作系统镜像到底是如何制作的。
[root@localhost docker]# docker history debian:11
IMAGE CREATED CREATED BY SIZE COMMENT
6f4986d78878 2 years ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:c03517c5ddbed4053… 124MB
[root@localhost docker]# docker history centos:7
IMAGE CREATED CREATED BY SIZE COMMENT
eeb6ee3f44bd 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
总结来看,就是直接把文件追加到容器里面,然后一个CMD里面加了个bash,至于这个文件里面有什么内容呢,其实就是这个操作系统一个rootfs。
其次我们可以分析那些中间件镜像是如何做的。
[root@localhost ~]# docker history nginx
IMAGE CREATED CREATED BY SIZE COMMENT
605c77e624dd 2 years ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
<missing> 2 years ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B
中间省略部分
<missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=NGINX Do… 0B
<missing> 2 years ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:09675d11695f65c55… 80.4MB
[root@localhost docker]# docker history mysql:5.7
IMAGE CREATED CREATED BY SIZE COMMENT
c20987f18b13 2 years ago /bin/sh -c #(nop) CMD ["mysqld"] 0B
<missing> 2 years ago /bin/sh -c #(nop) EXPOSE 3306 33060 0B
<missing> 2 years ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B
中间省略部分
<missing> 2 years ago /bin/sh -c groupadd -r mysql && useradd -r -… 329kB
<missing> 2 years ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:bd5c9e0e0145fe33b… 69.3MB
总结来看,这些中间件镜像和操作系统镜像前面部分基本都是一样的,都是一个rootfs,然后添加自己的业务逻辑进去。
制作自己的镜像
如果我们要制作自己的操作系统镜像,是不是只要有了操作系统的rootfs文件就可以制作自己的操作系统镜像,而不需要依赖仓库呢?然后其他中间件镜像,是不是可以在这个操作系统镜像基础上接着做呢?
制作操作系统镜像,先找rootfs(暂时只找到这2个)
#alpine镜像,版本可以在下面的地址进行选择
https://mirror.tuna.tsinghua.edu.cn/alpine/v3.19/releases/x86_64/
#ubuntu镜像,版本可以在下面的地址进行选择
https://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/
Centos找了很久,都没找到对应的rootfs文件,我们这里以一台新的Centos 7.9 的虚拟机作为自己的rootfs的来源(这个方法其实就可以比较容易把本地的虚拟机业务容器化)。
打包操作系统根目录,找一台最精简的服务器,否则这个打包的文件会比较大,其实这个还可以精简的,这里只是简单的测试功能。
#打包操作系统根目录,找一台最精简的服务器,否则这个打包的文件会比较大,其实这个还可以精简的,这里只是简单的测试功能
touch test-dockerimages
tar -czvf centos7.9.tar.gz --exclude=/proc --exclude=/sys --exclude=/dev --exclude=/tmp --exclude=/run --exclude=/boot /
#编写Dockerfile,上面的压缩包和Dockerfile需要在同一个目录,构建和打包最好用2台不同的服务器。
FROM scratch
ADD centos7.9.tar.gz /
CMD ["bash"]
#构建容器,当然这个由于是从虚拟机打包过来的rootfs,所以比较大
[root@localhost centos7.9]# docker build -t centos:7.9diy .
[root@localhost centos7.9]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos 7.9diy 3130d67457c2 2 minutes ago 1.43GB
#运行容器,可以看到我们打包操作系统创建的空文件,已经带到容器里面了。
[root@localhost centos7.9]# docker run -it centos:7.9diy bash
[root@b97848bf03ee /]# ls -l /root/test-dockerimages
-rw-r--r--. 1 root root 0 6月 13 20:59 /root/test-dockerimages
总结:
1.如果为了镜像足够小,打包的时候需要把打包所在目录忽略掉,可以尽量减少干扰,并缩小镜像大小。
2.这个是虚拟机生成的镜像,所以和标准的Centos7.9(200M)的差距还是很大的,当然我这个操作系统里面自带的东西也比标准的镜像更多。
3.如果你能找到对应镜像的rootfs文件,那么做出来的操作系统镜像和官方的镜像就会非常接近。
制作中间件镜像
只要找到了对应的物料,也可以用同样的方法制作,但是这个物料可能不好找,参数由于Docker命令的限制也无法看到完整的,就不容易完全复刻官方的镜像,只能根据自己的实际情况来配置。