在 GitLab CI Docker 工作流程中应该在哪里编译 c++ 应用程序?

Posted

技术标签:

【中文标题】在 GitLab CI Docker 工作流程中应该在哪里编译 c++ 应用程序?【英文标题】:Where should c++ application be compiled in GitLab CI Docker workflow? 【发布时间】:2020-04-18 19:22:31 【问题描述】:

我希望了解如何正确构建我的 .gitlab-ci.yml 和 Dockerfile,以便我可以将 C++ 应用程序构建到 Docker 容器中。

我正在为 C++ 应用程序的实际编译和链接应该在 CI 工作流程中的哪个位置进行而苦恼。

我做了什么:

我目前的方法是在 Docker 中使用带有私有 gitlab docker 注册表的 Docker。 我的 gitlab-ci.yml 使用我基于 docker:19.03.1-dind 映像创建的 dind docker 映像服务,但包含我的证书以安全地与我的私人 gitlab docker 注册表通信。 我还有一个基于 docker:19.03.1 的 gitlab-ci.yml 引用的自定义基础镜像,其中包括我构建所需的内容,例如 cmake、build-base mariadb-dev 等。 将我的构建脚本添加到 gitlab-ci.yml 以构建应用程序 cmake ... && cmake --build 。 然后,dockerfile 会复制在我的构建步骤中生成的最终二进制文件。

完成所有这些后,我觉得不太对劲,我想知道我是否错过了意图。我试图在网上找到一个 C++ 示例作为示例,但没有成功。

我没有完全理解的是每个参与者在 docker-in-docker 设置中的角色:docker 镜像、dind 镜像,最后是我正在生产的容器……

我想知道的……

谁应该执行构建并包含构建环境、我的 .gitlab-ci.yml 或我的 Dockerfile 中指定的基础镜像? 如果我使用 dockerfile 构建,如何将源代码的内容放入 docker 容器中?我要复制 /builds 目录吗?我应该安装它吗? 在哪里划分谁执行工作,gitlab-ci.yml 或 Docker 文件? 参考使用 Docker-in-Docker Gitlab CI 构建的 C++ docker 应用程序的工作示例。

.gitlab-ci.yml

image: $CI_REGISTRY/building-blocks/dev-mysql-cpp:latest
#image: docker:19.03.1

services:
  - name: $CI_REGISTRY/building-blocks/my-dind:latest
    alias: docker

stages:
  - build
  - release

variables:
  # Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
  DOCKER_TLS_CERTDIR: "/certs"
  CONTAINER_TEST_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
  CONTAINER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:latest

before_script:
        - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY

build:
  stage: build
  script:
    - mkdir build

【问题讨论】:

【参考方案1】:

这两种方法同样有效。如果您查看其他 SO 问题,您可能会注意到一件事是 Java/Docker 映像几乎普遍在其主机上构建一个 jar 文件,然后将 COPY 生成一个映像,但 Go/Docker 映像倾向于使用多-stage Dockerfile 从源代码开始。

如果您已经有一个相当成熟的构建系统并且您的开发人员已经有一个非常一致的设置,那么在 CI 环境中做更多的工作是有意义的(在您的 .gitlab.yml 文件中)。以与您相同的方式构建您的应用程序,然后将COPY 构建为最小的 Docker 映像。如果您需要同时发布 Docker 和非 Docker 工件,这种方法也很有帮助。如果你有一个make dist 风格的 tar 文件并想从中获取一个 Docker 镜像,你可以使用一个非常简单的 Dockerfile,比如

FROM ubuntu
RUN apt-get update && apt-get install ...
ADD dist/myapp.tar.gz /usr/local  # unpacking it
EXPOSE 12345
CMD ["myapp"]                     # /usr/local/bin/myapp

另一方面,如果您的开发人员拥有多种桌面环境,并且您确实在尝试将事物标准化,并且您只需要发布 Docker 映像,那么将大部分内容集中在 Dockerfile 中可能是有意义的。这样做的好处是每个开发人员都可以自己在本地运行确切的构建序列,而不是依赖 CI 系统来尝试简单的更改。围绕 GNU Autoconf 构建的东西可能看起来更像

FROM ubuntu AS build
RUN apt-get update \
 && apt-get install --no-install-recommends --assume-yes \
      build-essential \
      lib...-dev
WORKDIR /app
COPY . .
RUN ./configure --prefix=/usr/local \
 && make \
 && make install

FROM ubuntu
RUN apt-get update \
 && apt-get install --no-install-recommends --assume-yes \
      lib...
COPY --from=build /usr/local /usr/local
CMD ["myapp"]

如果您在 Dockerfile 中进行主要构建,则需要COPY 中的源代码。卷安装在序列中的此时不起作用。 CI 系统在任何情况下都应该避免将源代码绑定到容器中:您希望针对您构建的实际工件运行测试,而不是构建的 Docker 映像的混合体,而是替换其所有源代码。

【讨论】:

以上是关于在 GitLab CI Docker 工作流程中应该在哪里编译 c++ 应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

CI系统中的Docker标记策略(GitLab)

gitlab-ci.yaml:在多行 python docker 镜像中运行 python

如何将存储库中的文件复制到用于作业的 Docker 容器中,在 gitlab-ci.yml

如何使用 CI/CD 为 Gitlab 注册表推送基于 docker compose 的图像

如何在gitlab-ci.yml中将文件从存储库复制到用于作业的docker容器中

DevOps实战-基于Docker的CI/CD