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