Перейти к основному содержимому

Как установить Gitlab Runner в Docker Swarm

·893 слов·5 минут
Гайды
Юрий Семеньков
Автор
Юрий Семеньков
DevOps, tech, geek, mentor
Оглавление
This post is also available in English.

У меня в проекте есть кластер Docker Swarm, в котором динамически запускаются Jenkins Agents, на которых выполняются все джобы из Jenkins. Почему не в Kubernetes? Потому что держать Кубер-кластер только для джобов - неоптимально, Swarm сильно проще в поддержке. Вот даже есть пост “ Не усложняй”.

Недавно разворачивал Self-Hosted Gitlab, но не нашел официальной инструкции, чтобы запустить gitlab runner в swarm-кластере, чтобы еще autoscaling работал — то есть чтобы runner сам поднимал дополнительные контейнеры на swarm-нодах. Пришлось собирать по крупицам информацию. Вот, делюсь способом.

Инструкция состоит из трех этапов:

  • Получить токен для регистрации
  • Разложить конфигурации раннеров на машины
  • Задеплоить раннеры

Получить Runner Authentication Token
#

Раньше для регистрации раннеров использовался runner registration token, но он перешел в статус Deprecated. Gitlab начал использовать Runner Authentication Token для подключения раннеров.

Идем в настройки проекта, группы или всего инстанса, чтобы зарегистрировать новый Runner: Admin Settings -> CI/CD -> Runners -> New instance runner:

new instance runner

Указываем Tags. В последствие мы будем указывать тэги в наших gitlab-ci пайплайнах, чтобы они запускались на определенных раннерах. Например, у меня это тэг swarm.

На следующей странице копируем токен и сохраняем где-нибудь:

runner authentication token

Теперь Gitlab будет ждать, что какой-нибудь раннер зарегистрируется с этим токеном.

Конфигурация раннеров
#

Мы можем запустить контейнер с gitlab runner, зайти в него и выполнить указанную команду register. Gitlab Runner при регистрации сохранит токен и минимальные настройки в файл /etc/gitlab/config.toml внутри контейнера. Но чтобы не ходить на каждой машине в контейнер и не делать все руками, давай сделаем шаблон конфигурации и разложим его на swarm-ноды.

Готовим конфигурационный файл:

concurrent = 5 # Concurrent containers per node
check_interval = 0

[[runners]]
  name = "docker-swarm-runner"
  url = "https://<YOUR-GITLAB-INSTANCE>/"
  token = "<GITLAB AUTHENTICATION TOKEN>"
  executor = "docker"
  [runners.custom_build_dir]
  [runners.docker]
    tls_verify = false
    image = "alpine:latest"  # Default image for jobs
    privileged = true  # If we need Docker-in-Docker
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    allowed_pull_policies = ["always", "if-not-present", "never"]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]

Меняем token на тот, который получили в прошлом этапе. Так же указываем адрес нашего Gitlab-инстанса.

Теперь на каждой swarm-ноде нужно создать директорию для конфигурации и положить туда этот файл. Как это сделать — решайте сами, я использую Ansible.

Главное, помните, что хранить токен в git-репозитории небезопасно. Это плохая практика. В случае Ansible вы можете воспользоваться Ansible Vault или сторонними решениями, типа Hashicorp Vault или Insfisical.

Копируем конфигурационный файл на ноды
#

Вот пример Ansible-кода для копирования конфигурационного файла:

templates/config.toml.j2:

concurrent = 5
check_interval = 0

[[runners]]
  name = "docker-swarm-runner"
  url = "{{ gitlab_instance_url }}"
  token = "{{ gitlab_runner_swarm_auth_token.value }}"
  executor = "docker"
  [runners.custom_build_dir]
  [runners.docker]
    tls_verify = false
    image = "alpine:latest"  # Default image for jobs, can be overridden in .gitlab-ci.yml
    privileged = true  # Enable if you need to run Docker-in-Docker or privileged containers
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    allowed_pull_policies = ["always", "if-not-present", "never"]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]

tasks/main.yml:

- name: Create directories
  ansible.builtin.file:
    path: /etc/gitlab-runner/config
    state: directory
    recurse: true

- name: Copy config file
  ansible.builtin.template:
    src: config.toml.j2
    dest: /etc/gitlab-runner/config/config.toml

Конфигурационный файл должен быть на всех нодах swarm-кластера.

Деплой Gitlab Runner в Swarm
#

Swarm работает с привычными docker-compose файлами, поэтому создаем такой. Для копирования я так же пользуюсь Ansible, поэтому вот пример jinja-шаблона:

services:
  gitlab-runner:
    image: gitlab/gitlab-runner:{{ gitlab_runner_image_version }}
    deploy:
      mode: global
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/gitlab-runner/config:/etc/gitlab-runner
    networks:
      - gitlab-net

networks:
  gitlab-net:
    external: false

Обратите внимание:

  • мы указываем deploy mode: global, чтобы контейнер запустился на всех нодах кластера. Это как DaemonSet в Kubernetes.
  • мы подключаем директорию с config.toml файлом
  • дополнительно мы монтируем docker socket, чтобы gitlab runner мог управлять нашим docker engine и создавать новые контейнеры (это нужно для работы autoscaling)
  • указываем версию gitlab-runner контейнера, посмотреть доступные можно в Docker Hub.

Я копирую этот файл с помощью Ansible:

- name: Copy compose file
  ansible.builtin.template:
    src: docker-compose.yml.j2
    dest: /etc/gitlab-runner/docker-compose.yml

Запускать swarm stack нужно с менеджер-ноды (главной ноды кластера), но сам файл будет лежать на всех нодах. Избыточно, но мне так проще, чтобы не добавлять условия в Ansible.

Идем на менеджер-ноду и выполняем:

docker stack deploy -c docker-compose.yml gitlab-runner

Через минутку проверяем:

root@swarm-node01:/home/ysemyenkov# docker stack ps gitlab-runner
ID             NAME                                                    IMAGE                                 NODE           DESIRED STATE   CURRENT STATE        ERROR     PORTS
pnkxq7yf3wm3   gitlab-runner.1tlong-name   gitlab/gitlab-runner:ubuntu-v17.3.0   swarm-node01   Running         Running 2 days ago
ih4822qch9ew   gitlab-runner.3tlong-name   gitlab/gitlab-runner:ubuntu-v17.3.0   swarm-node03   Running         Running 2 days ago
xzj5yt1cv5ae   gitlab-runner.2tlong-name   gitlab/gitlab-runner:ubuntu-v17.3.0   swarm-node02   Running         Running 2 days ago

Если все нормально, то в Gitlab мы увидем зарегистрированный Runner:

registered swarm gitlab runners

Проверяем работу
#

Можем создать тестовый пайплайн, который запустит десяток джобов одновременно:

stages:
  - test

parallel-jobs:
  stage: test
  tags:
    - swarm
  script:
    - echo "Starting sleep for 600 seconds"
    - sleep 600
  parallel:
    matrix:
      - JOB_NAME: "job1"
      - JOB_NAME: "job2"
      - JOB_NAME: "job3"
      - JOB_NAME: "job4"
      - JOB_NAME: "job5"
      - JOB_NAME: "job6"
      - JOB_NAME: "job7"
      - JOB_NAME: "job8"
      - JOB_NAME: "job9"
      - JOB_NAME: "job10"

Запускаем пайплайн и видим, что контейнеры запустились в нужном количестве и на разных нодах. Посмотреть можно как через docker ps на нодах, так и через средства мониторинга. Например я смотрю метрики cAdvisor в Grafana:

containers in grafana from cadvisor metrics

Видим, что три верхних контейнера — это основные процессы gitlab-runner, которые получают задания и создают динамические контейнеры под джобы. А ниже, наши контейнеры с sleep джобами запущенны параллельно на разных нодах.

Вот и всё.


🙋‍♂️С комментариями можно смело приходить в наш телеграм-чат.

🌀Так же рекомендую подписаться на телеграм-канал, чтобы не пропускать классные посты и анонсы новых статей.

🎬 А видео выходят на Youtube, канал @etogeek.

Related

Как закоммитить только часть файла?
·203 слов·1 минута
Git Гайды
Как создать свой блог на Hugo
·1781 слово·9 минут
Гайды
Бест-практисы Ansible
·1052 слов·5 минут
Гайды