首页 > 解决方案 > docker-in-docker 上免费的在线 gitlab 运行器

问题描述

我有 dotnet 解决方案,它由控制台项目、webapi 项目和 mysql db 组成。我将它们放在单独的 docker 映像中,编写 docker-compose 来启动并在我的机器上进行测试。接下来,我使用 FluentDocker 编写了一个测试,它允许我以编程方式启动 docker-compose 并验证容器是否已启动并运行。

现在我想在 Gitlab CI 上做这个。以前我使用图像:mcr.microsoft.com/dotnet/core/sdk:3.1 并针对测试项目运行测试阶段。它工作得很好,因为没有 docker 集成。我无法在 Gitlab CI 上运行 FluentDocker 测试,因为该图像不包含 docker。于是我开始研究。

  1. 将 db 纳入 CI 工作的解决方案在这里https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service ,但我怀疑我是否可以将 docker 用作服务。

  2. 接下来是为 gitlab runner https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker-workflow-with-docker-executorhttps://tomgregory 使用 docker 集成。 com/running-docker-in-docker-on-windows/ 我不能使用它,因为我使用 Gitlab 本身的免费运行器并且无法配置它。我试图运行 docker info 命令,但它在我的脚本中失败了。

  3. 我曾想过基于包含 docker 的 dotnet sdk 构建自己的映像,但这似乎是个坏主意。我最终没有让它工作。

  4. 似乎可行的解决方案是使用 dind 并启动 docker-compose: How to run docker-compose inside docker in docker which running inside gitlab-runner 容器?https://gitlab.com/gitlab-org/gitlab-foss/-/issues/30426 但要使用它,我需要安装 dotnet-sdk 以在 before-script 部分构建和测试我的应用程序,而 sdk 不是每次下载一个小包。

  5. 我可以尝试基于 docker:dind 构建我的图像并在其中包含 dotnet sdk,将其发布在 dockerhub 上,然后在 gitlab runner 中使用它。现在在我看来,这是最后的选择。

那么,这里的正确方法是什么?

- - - - - -编辑 - - - - - - -

我做了这个工作!请参阅 Konrad Botor 使用 dockerfile 和 yml 文件提供的非常彻底的答案。我使用 sdk 和 docker 构建了自己的映像,并将其用于链接到 dind 服务的测试阶段。我的镜像托管在 dockerhub 上,所以 gitlab 下载它以供使用。

还有一些注意事项:

1 - 如何使用 dind 作为服务https://gitlab.com/gitlab-org/gitlab-runner/-/issues/25344

2 - 从哪里获取 modprobe.sh 和 docker-entrypoint.sh https://github.com/docker-library/docker (进入最新版本)。非常重要的是克隆 repo 并从那里复制文件,因为我试图复制粘贴内容但它不起作用。

3 - docker-compose repo https://github.com/tmaier/docker-compose/blob/master/Dockerfile

4 - 查找示例https://gitlab.com/gitlab-examples/docker/-/blob/master/.gitlab-ci.yml

标签: .netdockergitlab

解决方案


在 GitLab CI 中使用 docker 的规范方法显示在此处的 GitLab 示例存储库中。我认为它适用于免费跑步者,因为它是 GitLab 本身维护的官方组。

由于您的工作需要的不仅仅是 Docker,我建议您使用带有 Dotnet SDK、Docker 和 docker-compose 的自定义映像,如下所示:

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine

RUN apk add --no-cache \
        ca-certificates \
# DOCKER_HOST=ssh://... -- https://github.com/docker/cli/pull/1014
        openssh-client

# set up nsswitch.conf for Go's "netgo" implementation (which Docker explicitly uses)
# - https://github.com/docker/docker-ce/blob/v17.09.0-ce/components/engine/hack/make.sh#L149
# - https://github.com/golang/go/blob/go1.9.1/src/net/conf.go#L194-L275
# - docker run --rm debian:stretch grep '^hosts:' /etc/nsswitch.conf
RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf

ENV DOCKER_CHANNEL stable
ENV DOCKER_VERSION 19.03.12
# TODO ENV DOCKER_SHA256
# https://github.com/docker/docker-ce/blob/5b073ee2cf564edee5adca05eee574142f7627bb/components/packaging/static/hash_files !!
# (no SHA file artifacts on download.docker.com yet as of 2017-06-07 though)

RUN set -eux; \
    \
# this "case" statement is generated via "update.sh"
    apkArch="$(apk --print-arch)"; \
    case "$apkArch" in \
# amd64
        x86_64) dockerArch='x86_64' ;; \
# arm32v6
        armhf) dockerArch='armel' ;; \
# arm32v7
        armv7) dockerArch='armhf' ;; \
# arm64v8
        aarch64) dockerArch='aarch64' ;; \
        *) echo >&2 "error: unsupported architecture ($apkArch)"; exit 1 ;;\
    esac; \
    \
    if ! wget -O docker.tgz "https://download.docker.com/linux/static/${DOCKER_CHANNEL}/${dockerArch}/docker-${DOCKER_VERSION}.tgz"; then \
        echo >&2 "error: failed to download 'docker-${DOCKER_VERSION}' from '${DOCKER_CHANNEL}' for '${dockerArch}'"; \
        exit 1; \
    fi; \
    \
    tar --extract \
        --file docker.tgz \
        --strip-components 1 \
        --directory /usr/local/bin/ \
    ; \
    rm docker.tgz; \
    \
    dockerd --version; \
    docker --version

COPY modprobe.sh /usr/local/bin/modprobe
COPY docker-entrypoint.sh /usr/local/bin/

# https://github.com/docker-library/docker/pull/166
#   dockerd-entrypoint.sh uses DOCKER_TLS_CERTDIR for auto-generating TLS certificates
#   docker-entrypoint.sh uses DOCKER_TLS_CERTDIR for auto-setting DOCKER_TLS_VERIFY and DOCKER_CERT_PATH
# (For this to work, at least the "client" subdirectory of this path needs to be shared between the client and server containers via a volume, "docker cp", or other means of data sharing.)
ENV DOCKER_TLS_CERTDIR=/certs
# also, ensure the directory pre-exists and has wide enough permissions for "dockerd-entrypoint.sh" to create subdirectories, even when run in "rootless" mode
RUN mkdir /certs /certs/client && chmod 1777 /certs /certs/client
# (doing both /certs and /certs/client so that if Docker does a "copy-up" into a volume defined on /certs/client, it will "do the right thing" by default in a way that still works for rootless users)

ENV COMPOSE_VERSION 1.26.2

RUN apk add --no-cache py3-pip python3
RUN apk add --no-cache --virtual build-dependencies python3-dev libffi-dev openssl-dev gcc libc-dev make \
  && pip3 install "docker-compose${COMPOSE_VERSION:+==}${COMPOSE_VERSION}" \
  && apk del build-dependencies

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["sh"]

这是基于官方docker:latest Dockerfile以及tmaier/docker-compose:latest Dockerfile。您还需要第一个 repo 中modprobe.shdocker-entrypoint.sh脚本。

然后按如下方式运行:

image: docker:latest //whatever image you use in your pipeline most often

variables:
  DOCKER_DRIVER: overlay2

stages:
- test

test:
  stage: test
  image: dotnetsdk-compose:latest //your custom image
  services:
  - docker:dind
  script:
    - docker-compose up -d

请注意,新映像基于 Alpine 3.12 而不是 Debian 10。如果这是一个问题,您必须将上述 Dockerfile 转换为使用 Debian 上可用的命令。


推荐阅读