通过 docker 多阶段构建与装载构建和部署 C++
Building and deploying C++ through docker multistage build vs mount
我正在尝试使用 docker 构建自定义 C++ 工具,它具有许多自定义库依赖项。
共有三个库:libA、libB 和 libC。 libB 依赖于 libA,libC 依赖于 libA 和 libB。在我的家庭系统上,我通常会更新 libA 的源代码,然后安装它下游的所有内容,因为 libB 使用 CMake 查找 libA 等。
在 docker 中实现此目标的最佳方法是什么?是不是也要用make install?我不希望包含源代码的最终图像 - 只是二进制文件和库。如果我使用多阶段构建,我怎么知道我已经复制了所有必要的其他库,例如curl, protobuf 进入最后'layer'。只为构建镜像安装源代码而不为部署镜像安装源代码不是更好吗?
我发现 docker 和 C++ 的信息不多。
您通常不想为您的应用程序代码或依赖项使用卷。最佳做法是 Docker 图像是独立的。您可能 运行 跨 Docker 解释语言(尤其是 Node)的设置,这些语言大量使用卷和绑定安装,但这些实际上只是通过 运行 在主机代码上使用 运行ning Node Docker 而不是在主机上安装 Node。
对于需要编译但只需要编译工件到 运行 的东西,一种典型的方法是使用 Docker multi-stage build。这个想法是,您设置一个包含完整构建工具链的映像并编译所有内容,然后在同一个 Docker 文件中创建第二个映像,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 install
或 COPY
内容放入每个图像阶段才能显示它们。
这里的一个开放的并发症是 C 库构建通常会包含一些仅在额外的 C 库构建中需要的部分。在您的示例中,libB
依赖于 libA
,因此 libA
安装步骤将包括 C 头文件和静态库。这些可能很大(尤其是 .a
静态库)并且在 运行 时不需要。您可能希望通过在构建阶段结束时战略性地使用 RUN rm
来清除这些内容。一般来说 RUN rm
不会使图像变小,但是如果你 RUN rm
构建阶段的东西然后 COPY
编辑文件进入最后阶段,只有留下的东西复制到最终图像中。
我正在尝试使用 docker 构建自定义 C++ 工具,它具有许多自定义库依赖项。
共有三个库:libA、libB 和 libC。 libB 依赖于 libA,libC 依赖于 libA 和 libB。在我的家庭系统上,我通常会更新 libA 的源代码,然后安装它下游的所有内容,因为 libB 使用 CMake 查找 libA 等。
在 docker 中实现此目标的最佳方法是什么?是不是也要用make install?我不希望包含源代码的最终图像 - 只是二进制文件和库。如果我使用多阶段构建,我怎么知道我已经复制了所有必要的其他库,例如curl, protobuf 进入最后'layer'。只为构建镜像安装源代码而不为部署镜像安装源代码不是更好吗?
我发现 docker 和 C++ 的信息不多。
您通常不想为您的应用程序代码或依赖项使用卷。最佳做法是 Docker 图像是独立的。您可能 运行 跨 Docker 解释语言(尤其是 Node)的设置,这些语言大量使用卷和绑定安装,但这些实际上只是通过 运行 在主机代码上使用 运行ning Node Docker 而不是在主机上安装 Node。
对于需要编译但只需要编译工件到 运行 的东西,一种典型的方法是使用 Docker multi-stage build。这个想法是,您设置一个包含完整构建工具链的映像并编译所有内容,然后在同一个 Docker 文件中创建第二个映像,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 install
或 COPY
内容放入每个图像阶段才能显示它们。
这里的一个开放的并发症是 C 库构建通常会包含一些仅在额外的 C 库构建中需要的部分。在您的示例中,libB
依赖于 libA
,因此 libA
安装步骤将包括 C 头文件和静态库。这些可能很大(尤其是 .a
静态库)并且在 运行 时不需要。您可能希望通过在构建阶段结束时战略性地使用 RUN rm
来清除这些内容。一般来说 RUN rm
不会使图像变小,但是如果你 RUN rm
构建阶段的东西然后 COPY
编辑文件进入最后阶段,只有留下的东西复制到最终图像中。