在维护一堆开源软件,因为需要比较固定可靠的编译环境,所以之前导入了 Docker,在 Dockerfile 里拉操作系统装依赖签出源码然后编译。编译完成后 run 一秒复制出成品然后销毁。
每次开源软件更新时,重新 pull 底层操作系统镜像,重新构建编译环境,然后重新编译和打包发布。当然,新的系统发布的时候也是要为新系统编译的。
单纯使用 Dockerfile build 从零到编译完是否是最佳实践?
记得以前还看到过一个做法是 build 只准备环境,然后用 run 来编译。这种方式是不是更好的实践?
两种做法各有什么利弊吗?
接下去打算发展 Docker for Windows,因为还要编译很多 Windows 下的开源项目。大家使用过程中有踩到什么坑吗?
1
chendy 2019-08-09 12:12:04 +08:00
build 准备环境,run 跑构建,没毛病
|
2
momocraft 2019-08-09 12:21:19 +08:00
那你的 image 要包含所有 build deps?
|
3
imherer 2019-08-09 12:38:58 +08:00
buid > run > commit ?
直接 build 出来就可以了呀,为什么还要 run ? |
4
GeruzoniAnsasu 2019-08-09 12:48:19 +08:00 via Android
……怀疑 lz 没有用过 ci pipeline
|
5
gam2046 2019-08-09 12:48:59 +08:00
我的做法是 build 基础的构建环境,如 gcc、java 之类的。基础编译环境准备完毕后,通过 run 的时候,pull 代码,编译出目标文件
|
6
msg7086 OP @momocraft image 里是有 build deps 的,编译完就可以删了,要的是编译出来的软件包。
短期内多次对同一个操作系统进行编译的话,可以重用之前的文件层,我觉得还是挺方便的? @imherer build 本身能把镜像里编译好的文件复制出来么? 我现在是 build 完以后创建镜像然后把文件 cp 出来的。 (刚刚看了一下脚本,用的是 container cp,不是 run ) @GeruzoniAnsasu 没有怎么用过。能否冒昧请教一下怎么用在这个场景下? |
7
jingxyy 2019-08-09 13:43:24 +08:00
我喜欢 run 时候-v 映射一个本地目录进去 编译完的放这个目录
|
8
zjsxwc 2019-08-09 14:05:12 +08:00
build 是用来运行构建环境的,
run 是作为工具提供给别人用的, 因为并不知道别人要编译哪些文件,所以 run 更灵活,而 build 需要写死等待被编译的文件 |
10
whileFalse 2019-08-09 14:30:31 +08:00
如果不想让最终运行用镜像包含源码和 Compile-time 的话,用 Docker 的多阶段构建
https://docs.docker.com/develop/develop-images/multistage-build/ |
11
whileFalse 2019-08-09 14:31:21 +08:00 1
或者如果你只想要一个干净的编译环境以获取可以在外部运行的二进制的话,你的方式是对的。
|
12
mmtromsb456 2019-08-09 15:55:40 +08:00 1
就我个人用 docker 差不多两年的经验来理解的话,因为我自己也有在维护一份私人的 openwrt 编译环境,所以我觉得相对来说比较方便的实践是这样的.
1.使用多阶段构建,在第一阶段中使用 dockerfile 中的 RUN 指令来构建出完整的所需二进制文件(whatever) 2.在第二阶段构建中提取出所需的二进制文件到新容器(多阶段构建的本质是不同的容器)中 3.在第二阶段的构建最后使用 COMMAND/ENTRYPOINT 等运行一个文件服务器进行分发 4.docker run 这个最终容器,然后直接在别的渠道直接提取即可.当然如果不需要 remote wget/curl 的情况下.我个人认为第二阶段构建完全不需要指定 COMMAND/ENTRYPOINT.直接使用 cp 来复制也可以. 我个人在使用的自动化编译流程基本上就是这样构成的,我理解是应该放在 COMMAND/ENTRYPOINT 的,也就是楼主你说的 run 的这个部分的应该有以下的特性: 1.幂等的,无论是重建容器,还是失败后自动重启容器,都应该完成相同的工作,输出相同或者类似的结果 2.轻量的,放在 run 的这个步骤的部分不应该阻塞启动时间,因为过长的启动时间会直接导致 docker 判断他启动失败.也不便于管理操作 3.提供服务的,这个 run 基本上是面对使用者的最前面的内容,应该足够一目了然可以让使用者明白这个 run 直接的提供我需要的服务 |
13
mmtromsb456 2019-08-09 15:57:52 +08:00
或者如果准备环境以及编译同时是两个不同的步骤,完全可以首先维护一份准备环境的基底镜像,比如 sample/debian-with-gcc 这样.然后在开始编译的镜像中直接使用 FROM sample/debian-with-gcc 然后再进一步的书写需要的编译步骤.最终 docker build 完成编译.
|
14
mmtromsb456 2019-08-09 16:00:35 +08:00
这样的话,编译环境和编译操作可以达成解耦,分开维护非常方便
|
15
msg7086 OP @mmtromsb456
#12 你说的办法的话,应该和我现在用的是一样的了。也就是构建产生镜像以后,把镜像中的软件包 cp 出来。 建立文件服务器好像是有点多余了,毕竟只有我自己用。 #13 准备环境这个本来就是 dockerfile 中的一步。因为我们维护的软件就是支持现在所有的 Debian 和 Ubuntu 的,所以大概有 10 个不同的操作系统要编译。现在的 dockerfile 就是 from 拿了以后 apt 装环境,git 拉源码和依赖,然后编译打包出 deb。每个操作系统都需要更新到最新版本,所以我觉得分开维护十个基底镜像意义不大,每次还是要 pull 刷新了刷新的。 |