用 doker 发布程序的正确打开方式
1. 每次发布用 DockerFile 打包一份新 image
然后把 image tag latest 发布
2. 在上次打包的 image 基础上 运行 docker commit,产生一个最新 image 。
目前我用方法 1 。每个 image 都是独立的 commit,之间是没父子关系。
我的疑惑是,docker commit 这个机制是不是可以淘汰了。
1. 每次发布用 DockerFile 打包一份新 image
然后把 image tag latest 发布
2. 在上次打包的 image 基础上 运行 docker commit,产生一个最新 image 。
目前我用方法 1 。每个 image 都是独立的 commit,之间是没父子关系。
我的疑惑是,docker commit 这个机制是不是可以淘汰了。
你要想让镜像之间有父子关系的话,后面构建就 FROM 上一版本镜像,虽然不知道有什么意义
虽然直接发布 dockerfile 才是最高效的方式,不过考虑到网络情况很多人不喜欢用。
2 还应该善用多阶段构建来节省最终镜像体积,不要把工具链和中间产物留在镜像里。
我觉得主的疑问在于,既然我每次发布的时候都不从上一个版本的 docker image commit,那这个命令到底有什么用?
其实在看这个命令有什么用的时候,不应该只从自己面前遇到的这个场景来看。docker commit 的这个设计的目的是增加存储层的复用程度。如果是 docker image 的终端用户(意思是你作出的镜像不会再被别人 FROM 或者 commit 新的东西)可能并没有什么感受,但想象以下的场景:
A 制作了一个最简单最干净的 Ubuntu 镜像
– B 基于上述镜像做了一个 Python runtime 镜像,只要基于该镜像起一个容器就能直接跑 python 脚本
– – C 基于 B 制作了一个 uwsgi 镜像,只要把 wsgi 脚本放进去就能起一个服务
– – D 基于 B 制作了一个安装了一些数据分析软件包的镜像,使用者只要起一个容器就能直接在 Ipython 中进行简单的数据分析操作
这样其实 BCD 都复用了 A,CD 复用了 B 。试想如果没有这个 commit 的功能,这五个镜像就是五份完全独立的文件,由于 BCD 的改动并不多,其实相当于用 4*A 的大小,但是实际上只做了一点(真正)微小的工作。而基于 commit 机制的这些镜像在都保存在 docker registry 时,应该只占用比 A 的大小稍大一点的空间。
这种机制对于社区来说是非常有益的,因为它提供给了镜像制作者一种非常廉价的复用他人已有工作的方式,同时节省了许多存储空间。
FROM xxxxxx # 这一句每次都一样,直接复用
RUN apt-get update && apt install -y xxx # 这一句也是每次都一样,直接复用
COPY . . # 这一句开始,因为拷入的代码文件变了,所以从这一行开始后面的全部重新构建
RUN build … # 从上一句开始从新构建
所以一般来说,安装依赖之类的语句尽可能提前,这样后续打包的时候就不会重新构建了。
实际上你可以简单理解成你的 Dockerfile 里每一条语句都是一个 commit (不正确,部分语句是会合并的),相互之间就是父子关系。具体表现在你 docker pull / push 的时候显示的那个进度条的个数。你每次构建的时候,如果这条语句前面的环境都是一样的话,并且当前这一层没有任何变化的话,那么这一条语句就不会重新执行,而是直接复用之前的构建结果。这样一来你会发现,在重新 docker push 的时候,会提示你部分层已经在服务器上存在了,只会 push 变动的部分。