【DevOps工具篇】Gitlab Runner设置(使用Docker Executor作为Runner)

2020-12-18T13:26:09+08:00 | 8分钟阅读 | 更新于 2020-12-18T13:26:09+08:00

Macro Zhao

【DevOps工具篇】Gitlab Runner设置(使用Docker Executor作为Runner)

@TOC

推荐超级课程:

强烈建议学习本文之前,先阅读学习此篇:


在本篇文章中,我们将在GitLab runner服务内注册docker executor,以便构建、测试和部署我们的容器化项目。

准备docker-compose文件

在注册docker executor之前,我们需要在docker-compose.yml文件中进行少量更新,将宿主机上的docker.sock文件挂载到GitLab runner容器中。 更新后的docker-compose.yml文件应如下所示:

version: '3.8'  
services:  
  
  gitlab-server:  
    image: 'gitlab/gitlab-ce:latest'  
    container_name: gitlab-server  
    environment:  
      GITLAB_ROOT_EMAIL: "admin@example.com"  
      GITLAB_ROOT_PASSWORD: "Abcd@0123456789"  
      GITLAB_OMNIBUS_CONFIG: |  
        external_url 'http://localhost:8000'  
        nginx['listen_port'] = 8000  
    ports:  
      - '8000:8000'  
    volumes:  
      - ./gitlab/config:/etc/gitlab  
      - ./gitlab/data:/var/opt/gitlab  
  
  
  gitlab-runner:  
    image: gitlab/gitlab-runner:alpine  
    container_name: gitlab-runner  
    network_mode: 'host'  
      
    # 新增挂载docker.sock从宿主机到容器的更改  
    volumes:  
      - /var/run/docker.sock:/var/run/docker.sock

为什么需要将docker.sock挂载到GitLab Runner中?

当你在机器上安装docker时,会安装两个不同的程序:

  1. Docker服务器
  2. Docker客户端

Docker服务器通过套接字(通过网络或通过文件)接收命令。 Docker客户端通过网络发送消息给Docker服务器,以创建容器、启动容器、停止容器等。

当docker客户端和服务器在同一台计算机上运行时,它们可以通过一个特殊的文件(套接字)进行连接。而且由于Docker可以高效地在宿主机和容器之间共享文件,这意味着你可以在Docker内部运行客户端。 Docker守护进程可以通过三种不同类型的套接字监听Docker Engine API请求:unixtcpfd。默认情况下,当你安装Docker时,会在/var/run/docker.sock创建一个unix域套接字(或IPC套接字)。 我们需要将宿主机上的docker.sock挂载到GitLab Runner容器中。当我们想要使用docker执行任务时,GitLab Runner可以使用这个docker.sock文件在宿主机上创建容器,运行任务,然后任务完成后终止。 如果您的docker服务器和客户端位于不同的机器上,您可以通过TCP进行通信,但由于我们的服务器和客户端都在同一台宿主机上,所以我们通过套接字文件(即docker.sock)进行通信。 更新docker-compose.yml后,按CTRL+C停止正在运行的容器,然后运行以下命令: docker compose up --build --force-recreate

注册部分

前往您的项目运行器页面,路径为: 仓库 → 设置 → CI/CD → 运行器 URL为 http://localhost:8000/root/build-with-lal/-/settings/ci_cd URL中的build-with-lal是我之前创建的仓库名称。

现有的运行器是我们上篇文章中创建的Shell执行器。 点击新建项目运行器按钮 填写运行器详细信息。确保添加tags,这样我们可以通过指定特定的运行器来运行不同的任务。

点击创建运行器按钮,这将重定向您到以下页面

复制步骤1中的gitlab-runner register …命令。 使用docker登录到您的GitLab运行器容器:

docker compose exec -it gitlab-runner /bin/bash

登录到GitLab运行器容器后,运行上述步骤1中的命令。确保在gitlab-runner register …命令的末尾添加以下标志:

gitlab-runner register   
              --url http://localhost:8000     
              --token glrt-AMG2ra8WJDPkbx-HDAzc   
              --docker-volumes /var/run/docker.sock:/var/run/docker.sock   
              --docker-network-mode 'host'

--docker-volumes /var/run/docker.sock:/var/run/docker.sock 添加--docker-volumes /var/run/docker.sock:/var/run/docker.sock会将GitLab运行器容器中的docker套接字文件挂载到执行器容器中,这样当我们需要运行docker CLI命令时,docker CLI将通过docker.sock文件访问宿主机上的docker引擎。 --docker-network-mode 'host' 添加--docker-network-mode 'host'会将执行器容器置于宿主网络,这样在克隆仓库时,执行器可以通过localhost访问它。

我们在两个不同的地方将容器网络置于宿主网络(PC网络)。

  1. 第一个是在docker-compose.yml文件中,我们将GitLab运行器容器的网络置于我们的宿主机网络(PC网络),这样GitLab服务器可以通过localhost与GitLab运行器通信,以管理流水线。
  2. 第二个是在注册我们的docker执行器时,我们将容器网络置于宿主网络(PC网络)。当流水线使用docker执行器运行时,这个网络很有用,任务会拉取docker镜像,然后尝试在执行器容器内部克隆项目仓库。此时,docker执行器会尝试通过localhost访问仓库,因此执行器容器需要与GitLab服务器位于同一个网络,即localhost。

  • 当询问GitLab实例URL时,除非您的GitLab服务器和运行器位于不同的机器上,否则按回车键保持默认。
  • 输入您喜欢的运行器名称。
  • 由于我们要注册一个docker执行器,当询问执行器选项时,输入docker
  • 选择docker执行器时,您还需要设置一个默认的docker镜像,以防在我们的项目流水线gitlab-ci.yml文件中遗漏。我将默认docker镜像设置为python:3.10-alpine,您可以在gitlab-ci.yml文件中覆盖它。

填写完上述所有详细信息后,您的docker运行器应该已经注册,运行器页面应如下所示。

如果您回到 仓库 → 设置 → CI/CD → 运行器 页面,您应该会看到一个新的运行器与我们在上一篇文章中创建的Shell运行器并列。

使用 Shell 和 Docker 执行器测试流水线

让我们尝试添加一个包含3个不同任务的流水线

  1. Shell 执行器
  2. 使用默认docker镜像的 Docker 执行器,即 python:3.10-alpine
  3. 将docker镜像覆盖为 docker:24.0.5 的 Docker 执行器
build with shell executor:  
  stage: build  
  tags:  
    - shell  
  script:  
    - date # print current date  
    - cat /etc/os-release # print os version for Linux  
  
build with docker executor:  
  stage: build  
  tags:  
    - docker  
  image: docker:24.0.5  
  script:  
    - docker info  
  
build with docker executor default image:  
  stage: build  
  tags:  
    - docker  
  script:  
    - python --version

您的流水线编辑器在 构建 → 流水线编辑器 下应该看起来像这样:

通过为每个任务添加 tags,可以确保为这个任务选择正确的运行器。因此,我们在第一个任务中添加了 tags: shell,因为我们希望这个任务由我们的Shell执行器运行。而剩下的2个任务应该由docker执行器执行,所以我们添加了 tags: docker 在第二个任务中使用 image: docker:24.0.5,您可以使用docker CLI来构建您的项目并使用docker将您的docker镜像推送到某个容器注册中心。 提交这些更改,然后切换到 构建 → 任务 下的任务。您应该看到所有任务正在运行或者已经通过。

点击每个任务的详细信息,您会注意到每个任务都是由相关的运行器挑选并执行的

任务由Shell执行器执行,打印当前日期和操作系统详细信息。

任务由Docker运行器执行,使用默认的docker镜像,即 python:3.10-alpine

任务由Docker运行器执行,通过将默认docker镜像覆盖为 docker:24.0.5 来利用docker CLI。 如果您通过 docker info 命令检查所有这些详细信息,docker服务器详细信息来自我的主机机器,我在那里安装了实际的docker引擎。我们之所以在 gitlab-ci.yml 文件中使用docker镜像,是为了让docker CLI可用。您提供给docker CLI的任何指令都将通过使用我们挂载的套接字文件 /var/run/docker.sock 传递给主机机器上的docker引擎。 当任务由docker执行器执行时,您可以在机器上监控容器,并且应该会看到一些新的容器与您现有的容器并列。这些新容器来自docker执行器,并且一旦任务完成就会终止。

这些运行器容器是您的GitLab运行器容器的同级容器,而不是GitLab运行器容器的子容器,因为我们从主机机器上挂载了 docker.sock 文件,所以所有容器都由主机机器的docker引擎管理。 即使我们在流水线任务中尝试构建和创建容器,容器实际上也会在我们的主机docker引擎上创建,因为我们是在docker执行器及其任务中使用相同的docker.sock。 让我们通过在任务中创建一些容器来更新我们的流水线。

build with shell executor:  
  stage: build  
  tags:  
    - shell  
  script:  
    - date # print current date  
    - cat /etc/os-release # print os version for Linux  
  
build with docker executor:  
  stage: build  
  tags:  
    - docker  
  image: docker:24.0.5  
  
  # new changes for adding dummy containers  
  script:  
    - docker run -d --rm --name nested-container1-in-pipelinejob alpine sleep 20  
    - docker run -d --rm --name nested-container2-in-pipelinejob alpine sleep 20  
  
build with docker executor default image: # default python image  
  stage: build  
  tags:  
    - docker  
  script:  
    - python --version  
    - sleep 10

一旦您提交了上述更改并且流水线运行,您可以通过运行以下命令在主机机器上监控您的docker容器:

docker ps

输出应该看起来像这样。

您可以看到,我们的执行器容器和我们在任务中创建的容器都是在主机docker引擎上创建的。

Docker套接字绑定的已知问题

关于docker套接字绑定和管理所有容器使用单个docker引擎的一些已知问题,GitLab文档在这里有所强调链接

  • 如果流水线任务运行了 docker rm -f $(docker ps -a -q),它将删除GitLab服务器和运行器容器,可能还会删除其他关键容器。
  • 如果您的测试创建了具有特定名称的容器,它们可能会相互冲突。

从源代码仓库共享文件和目录到容器可能不会按预期工作。卷挂载是在主机机器的上下文中完成的,而不是构建容器。 套接字绑定不是使用GitLab运行器的docker执行器的唯一方式。还有一种称为 Docker in Docker(简称 dind)的方式,我们将在下一篇文章中讨论。

使用Docker执行器构建和部署您的项目

现在您可以在您的仓库中添加一个 Dockerfile 并尝试使用docker构建您的项目。 Dockerfile

FROM python:3.10-alpine  
  
RUN python --version

更新 gitlab-ci.yml 以使用docker构建项目

构建输出

我们尝试使用 docker build . 构建我们的项目。 同样的方式,您可以使用 docker login 登录到容器注册中心,然后使用 docker push 将您的docker构建镜像推送到注册中心 正如我们之前讨论的,使用 /var/run/docker.sock 在主机docker引擎上创建子容器可能会存在一些潜在问题。为了避免在CI任务中使用 /var/run/docker.sock,还有一种称为 Docker-In-Docker 的方式,任务的容器将作为另一个服务容器(Docker-in-Docker)的子容器创建,而不是直接在主机docker引擎上创建。

© 2011 - 2025 Macro Zhao的分享站

关于我

如遇到加载502错误,请尝试刷新😄

Hi,欢迎访问 Macro Zhao 的博客。Macro Zhao(或 Macro)是我在互联网上经常使用的名字。

我是一个热衷于技术探索和分享的IT工程师,在这里我会记录分享一些关于技术、工作和生活上的事情。

我的CSDN博客:
https://macro-zhao.blog.csdn.net/

欢迎你通过评论或者邮件与我交流。
Mail Me

推荐好玩(You'll Like)
  • AI 动·画
    • 这是一款有趣·免费的能让您画的画中的角色动起来的AI工具。
    • 支持几十种动作生成。
我的项目(My Projects)
  • 爱学习网

  • 小乙日语App

    • 这是一个帮助日语学习者学习日语的App。
      (当然初衷也是为了自用😄)
    • 界面干净,简洁,漂亮!
    • 其中包含 N1 + N2 的全部单词和语法。
    • 不需注册,更不需要订阅!完全免费!
  • 小乙日文阅读器

    • 词汇不够?照样能读日语名著!
    • 越读积累越多,积跬步致千里!
    • 哪里不会点哪里!妈妈再也不担心我读不了原版读物了!
赞助我(Sponsor Me)

如果你喜欢我的作品或者发现它们对你有所帮助,可以考虑给我买一杯咖啡 ☕️。这将激励我在未来创作和分享更多的项目和技术。🦾

👉 请我喝一杯咖啡

If you like my works or find them helpful, please consider buying me a cup of coffee ☕️. It inspires me to create and share more projects in the future. 🦾

👉 Buy me a coffee