.net - 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。于是我开始研究。
将 db 纳入 CI 工作的解决方案在这里https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service ,但我怀疑我是否可以将 docker 用作服务。
接下来是为 gitlab runner https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker-workflow-with-docker-executor 或https://tomgregory 使用 docker 集成。 com/running-docker-in-docker-on-windows/ 我不能使用它,因为我使用 Gitlab 本身的免费运行器并且无法配置它。我试图运行 docker info 命令,但它在我的脚本中失败了。
我曾想过基于包含 docker 的 dotnet sdk 构建自己的映像,但这似乎是个坏主意。我最终没有让它工作。
似乎可行的解决方案是使用 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 不是每次下载一个小包。
我可以尝试基于 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
解决方案
在 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.sh
的docker-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 上可用的命令。
推荐阅读
- javascript - 在 Chrome Kiosk 模式下禁用/自定义与触摸相关的输入 UI
- python - python kill python的子进程
- django - 如何在同一台服务器(Digitalocean 或 aws)上部署 react 作为前端和 drf(django rest 框架)
- sql - 自动创建总差比较行
- animation - FFmpeg,动画类型:如何沿着大图像移动视频屏幕?
- php - 如何重设密码,盐
- jax-rs - 如何将专有的 Apache CXF 功能添加到 Open Liberty
- node.js - 将 JSON 对象从 Express 服务器发送到 React 时未定义对象?
- amazon-web-services - 在具有不同端口的单个 EC2 上运行两个不同的 Web 应用程序
- android - 如何从资源 XML (Android) 中获取视图 ID 的 IntArray