【问题标题】:Building and deploying C++ through docker multistage build vs mount通过 docker multistage build vs mount 构建和部署 C++
【发布时间】:2021-09-01 09:47:10
【问题描述】:

我正在尝试使用具有许多自定义库依赖项的 docker 构建自定义 C++ 工具。

共有三个库:libA、libB 和 libC。 libB 依赖于 libA,而 libC 依赖于 libA 和 libB。在我的家庭系统上,我通常会更新 libA 的源代码,然后从其下游安装所有内容,因为 libB 使用 CMake 来查找 libA 等。

在 docker 中实现这一目标的最佳方法是什么?是否也使用make install?我不希望有源代码的最终图像 - 只是二进制文件和库。如果我使用多阶段构建,我怎么知道我已经复制了所有必要的其他库,例如curl,protobuf 进入最后的“层”。只为构建映像挂载源而不为部署映像挂载不是更好吗?

我发现关于 docker 和 C++ 的信息并不多。

【问题讨论】:

    标签: c++ docker deployment build


    【解决方案1】:

    您通常不希望为您的应用程序代码或依赖项使用卷。最好的做法是让 Docker 映像自包含。您可能会在 Docker 设置中运行大量使用卷和绑定挂载的解释语言(尤其是 Node),但这些实际上只是归结为通过 Docker 在主机代码上运行 Node,而不是在主机上安装 Node。

    对于需要编译但只需要运行已编译的工件的东西的典型方法是使用 Docker multi-stage build。这个想法是,您设置一个包含完整构建工具链的映像并编译所有内容,然后在同一 Dockerfile 中创建第二个映像,COPY --from 第一个映像仅编译了工件。

    我可能会尝试在这里使用标准的 /usr/local 目录树,原因有两个:它通常是 Autoconf 等工具的默认安装前缀,并且在标准 Linux 分发版 Docker 映像中它是空的。

    # The first stage only builds things.  We'll COPY files out of it
    # later.
    FROM ubuntu:20.04 AS builder
    
    # Install any dependencies we need here, like the C toolchain.
    RUN apt-get update \
     && DEBIAN_FRONTEND=noninteractive \
        apt-get install --assume-yes --no-install-recommends \
          build-essential \
          libbar-dev \
          libfoo-dev \
          libquux-dev
    
    # Build library A and install it into /usr/local.
    WORKDIR /usr/src/libA
    COPY libA ./
    RUN ./configure \
     && make \
     && make install
    
    # Similarly with library B
    WORKDIR /usr/src/libB
    COPY libB ./
    RUN ./configure \
     && make \
     && make install
    
    # ...and library C, and the application proper
    ...
    
    # The final FROM line is the actual runtime image.  Anything before
    # this will be built, and will show up in `docker images`, but isn't
    # "the output" of the build.
    
    FROM ubuntu:20.04
    
    # Get the installed libraries and applications from the earlier stage.
    COPY --from=builder /usr/local/ /usr/local/
    
    # Regenerate the shared-library cache.
    RUN ldconfig
    
    # Set ordinary metadata to run a Docker container.  (The binary is
    # probably in /usr/local/bin which is on the default PATH.)
    EXPOSE 80
    CMD ["myapp"]
    

    如果不同的库具有非常不同的构建时依赖项,则可以扩展此方法以具有更多构建阶段。请记住,每条FROM 行都是重新开始的,您需要将RUN apt-get installCOPY 东西放入每个图像阶段以使它们出现。

    这里的一个复杂问题是 C 库构建通常会包含一些仅在其他 C 库构建时才需要的部分。在您的示例中,libB 依赖于libA,因此libA 安装步骤将包括 C 头文件并且通常是静态库。这些可能很大(尤其是.a 静态库)并且在运行时不需要。您可能想要清除这些,可能在构建阶段结束时战略性地使用RUN rm。通常RUN rm 不会使图像变小,但是如果您在构建阶段RUN rm 某些东西然后COPY 编辑文件进入最后阶段,则只有留下的东西会被复制到最终图像中.

    【讨论】:

    • 这非常有用 - 谢谢。编译 libB 和 libA 等的初始映像我假设 /usr/src 是通过绑定安装到本地机器?
    • 此设置中根本没有绑定挂载。它将WORKDIR 设置为(构建)映像内的路径,然后将COPYs 设置为来自主机的源树。
    猜你喜欢
    • 2019-08-23
    • 2018-06-27
    • 1970-01-01
    • 2011-12-23
    • 2021-07-03
    • 1970-01-01
    • 1970-01-01
    • 2020-12-10
    • 2019-07-05
    相关资源
    最近更新 更多