首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
msg7086
V2EX  ›  程序员

用 Docker 编译软件,是用 build 好还是用 build+run 好?

  •  
  •   msg7086 · 173 天前 · 1634 次点击
    这是一个创建于 173 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    在维护一堆开源软件,因为需要比较固定可靠的编译环境,所以之前导入了 Docker,在 Dockerfile 里拉操作系统装依赖签出源码然后编译。编译完成后 run 一秒复制出成品然后销毁。

    每次开源软件更新时,重新 pull 底层操作系统镜像,重新构建编译环境,然后重新编译和打包发布。当然,新的系统发布的时候也是要为新系统编译的。

    问题

    单纯使用 Dockerfile build 从零到编译完是否是最佳实践?

    记得以前还看到过一个做法是 build 只准备环境,然后用 run 来编译。这种方式是不是更好的实践?

    两种做法各有什么利弊吗?

    延伸

    接下去打算发展 Docker for Windows,因为还要编译很多 Windows 下的开源项目。大家使用过程中有踩到什么坑吗?

    15 回复  |  直到 2019-08-09 16:12:47 +08:00
    chendy
        1
    chendy   173 天前
    build 准备环境,run 跑构建,没毛病
    momocraft
        2
    momocraft   173 天前
    那你的 image 要包含所有 build deps?
    imherer
        3
    imherer   173 天前
    buid > run > commit ?
    直接 build 出来就可以了呀,为什么还要 run ?
    GeruzoniAnsasu
        4
    GeruzoniAnsasu   173 天前 via Android
    ……怀疑 lz 没有用过 ci pipeline
    gam2046
        5
    gam2046   173 天前
    我的做法是 build 基础的构建环境,如 gcc、java 之类的。基础编译环境准备完毕后,通过 run 的时候,pull 代码,编译出目标文件
    msg7086
        6
    msg7086   173 天前
    @momocraft image 里是有 build deps 的,编译完就可以删了,要的是编译出来的软件包。
    短期内多次对同一个操作系统进行编译的话,可以重用之前的文件层,我觉得还是挺方便的?

    @imherer
    build 本身能把镜像里编译好的文件复制出来么?
    我现在是 build 完以后创建镜像然后把文件 cp 出来的。
    (刚刚看了一下脚本,用的是 container cp,不是 run )

    @GeruzoniAnsasu 没有怎么用过。能否冒昧请教一下怎么用在这个场景下?
    jingxyy
        7
    jingxyy   173 天前
    我喜欢 run 时候-v 映射一个本地目录进去 编译完的放这个目录
    zjsxwc
        8
    zjsxwc   173 天前
    build 是用来运行构建环境的,
    run 是作为工具提供给别人用的,
    因为并不知道别人要编译哪些文件,所以 run 更灵活,而 build 需要写死等待被编译的文件
    msg7086
        9
    msg7086   173 天前
    @zjsxwc 我这边只是自己用,编译也只编译特定的大型项目,不考虑其他人使用,也不考虑编译其他软件的。
    whileFalse
        10
    whileFalse   173 天前
    如果不想让最终运行用镜像包含源码和 Compile-time 的话,用 Docker 的多阶段构建

    https://docs.docker.com/develop/develop-images/multistage-build/
    whileFalse
        11
    whileFalse   173 天前   ♥ 1
    或者如果你只想要一个干净的编译环境以获取可以在外部运行的二进制的话,你的方式是对的。
    mmtromsb456
        12
    mmtromsb456   173 天前
    就我个人用 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 直接的提供我需要的服务
    mmtromsb456
        13
    mmtromsb456   173 天前
    或者如果准备环境以及编译同时是两个不同的步骤,完全可以首先维护一份准备环境的基底镜像,比如 sample/debian-with-gcc 这样.然后在开始编译的镜像中直接使用 FROM sample/debian-with-gcc 然后再进一步的书写需要的编译步骤.最终 docker build 完成编译.
    mmtromsb456
        14
    mmtromsb456   173 天前
    这样的话,编译环境和编译操作可以达成解耦,分开维护非常方便
    msg7086
        15
    msg7086   173 天前
    @mmtromsb456
    #12 你说的办法的话,应该和我现在用的是一样的了。也就是构建产生镜像以后,把镜像中的软件包 cp 出来。
    建立文件服务器好像是有点多余了,毕竟只有我自己用。

    #13 准备环境这个本来就是 dockerfile 中的一步。因为我们维护的软件就是支持现在所有的 Debian 和 Ubuntu 的,所以大概有 10 个不同的操作系统要编译。现在的 dockerfile 就是 from 拿了以后 apt 装环境,git 拉源码和依赖,然后编译打包出 deb。每个操作系统都需要更新到最新版本,所以我觉得分开维护十个基底镜像意义不大,每次还是要 pull 刷新了刷新的。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   821 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 25ms · UTC 20:23 · PVG 04:23 · LAX 12:23 · JFK 15:23
    ♥ Do have faith in what you're doing.