CI/CD с Gitea для HomeLab

опубликовано: ⏰ 8

Очень редко встречал Gitea в качестве DVCS + CI/CD решения, обычно все используют GitLab. Собственно, и сам первым делом попытался использовать GitLab, но практически сразу появились проблемы. Основная его проблема – это аппетиты к ресурсам, которые были ограничены. Поэтому пришлось искать альтернативы, и Gitea оказалась одной из них.

Введение

Зачем это всё нужно?

Во-первых, так или иначе, но для нормальной работы (SDLC) требуется хоть какой-то выстроенный процесс автоматизации сборки, тестирования и поставки приложений. Заниматься этим вручную, мягко говоря, не эффективно и не масштабируемо.

Во-вторых, не всегда есть возможность использовать публичные сервера, например, GitHub или GitLab. Там хотя и есть приватные репозитории, но всегда есть риск, что код утечёт. Либо сам сервис будет заблокирован, и придётся всё восстанавливать из резервных копий, повезёт, если делались достаточно часто.

В-третьих, иногда хочется иметь полный контроль над своими данными и процессами.

Поэтому и начал искать DVCS-сервер + CI/CD к нему, когда возникла потребность развернуть базовое окружение для разработки.

Варианты

В большинстве проектов обычно требовался довольно ограниченный функционал:

  • Хранение кода.
  • CI/CD.
  • MR/PR.
  • Иногда трекер задач.

По этой причине к DVCS-серверу каких-то особых требований не было. Из известных бесплатных решений, которые можно развернуть локально, было несколько вариантов:

РешениеCI/CDСложность
настройки
Язык
разработки
Лицензия
GitLabвстроенныйВысокаяRubyApache 2
Giteaвстроенный, Drone, Woodpecker, TektonНизкаяGoMIT
Forgejo (форк Gitea)WoodpeckerНизкаяGoGPLv3
GitBucket + JenkinsJenkinsСредняяScalaApache 2 / MIT

Скажу честно, дальше Gitea я не пробовал, так как он полностью подошёл. Да и судя по скриншотам, у них примерно похожее всё.

GitLab и Gitea

В чём собственно была проблема с GitLab? По функционалу всё понятно, много где используется, много всего умеет и поддерживает. Но вот скорость старта и потребляемые ресурсы неприятно удивили. Ниже, как пример, пустые сервера с несколькими проектами и парой пользователей.

Процессы и потребление памяти у GitLab – ~7.5 GiB, время старта 2-3 минуты:

Время старта пара минут (до доступа к UI) и довольно сильно нагружает при этом CPU при запуске всех сервисов. Вроде бы можно отключить (Puma) кластеризацию у GitLab, что снизит потребление памяти, но ценой потери параллелизма.

Процессы и потребление памяти у Gitea – ~200-300 MiB, время старта 2-5 секунд:

Настройка раннеров для CI/CD у Gitea и Git примерно одинаковая и простая. Раннеры у обоих могут разворачиваться в Docker или на хосте. Запускаем, регистрируем и можно собирать проекты:

Дальше начинаются отличия: пайплайны у них разные:

  • В GitLab используется собственный формат описания CI/CD pipelines.
  • В Gitea используется форк nektos/act, это реализация GitHub Actions для локального запуска.

Сложно сказать, что лучше или хуже. По ощущениям, из коробки GitLab более функционален, а Gitea более понятный. При этом в Gitea есть возможность делать свои действия, которые потом можно использовать в пайплайнах. Ну, и получаем возможность использовать существующие GitHub Actions, все нужные были в наличии.

Пример пайплайна в Gitea, на котором тестировалось:

YAML
name: Build

on:
  pull_request:
    branches:
      - main
      - develop
  push:
    branches:
      - main
      - develop

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Maven
        uses: stCarolas/setup-maven@v5
        with:
          maven-version: '3.9.9'

      - name: Cache local Maven repository
        uses: actions/cache@v4
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-maven-

      - name: Cache Node.js modules
        uses: actions/cache@v4
        with:
          path: ~/.npm # Or ./node_modules if you prefer caching locally
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: Set up JDK (21)
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '21'

      - name: Set up Node.js (24)
        uses: actions/setup-node@v4
        with:
          node-version: 24

      - name: Setup settings.xml
        uses: s4u/maven-settings-action@v3.1.0
        with:
          mirrors: |
            [{
              "id": "nexus.public",
              "name": "public",
              "mirrorOf": "*",
              "url": "http://${{ vars.NEXUS_HOST }}/repository/maven-public/"
            }]
          servers: |
            [{
                "id": "nexus.private",
                "username": "${{ secrets.NEXUS_USER }}",
                "password": "${{ secrets.NEXUS_PASS }}"
            }]

      - name: Build and test
        run: mvn --batch-mode clean deploy -Dnexus.host=${{ vars.NEXUS_HOST }}

      - name: Generate JaCoCo coverage and Sonar reports
        run: mvn --batch-mode jacoco:report sonar:sonar -Dsonar.token=${{ secrets.SONAR_TOKEN }} -Dsonar.host.url=${{ vars.SONAR_HOST }} -P sonar

В этом скрипте выполняются следующие шаги:

  1. Получение кода.
  2. Настройка кеширования Maven/NPM.
  3. Установка Maven.
  4. Установка NPM.
  5. Установка JDK.
  6. Сборка проекта и деплой артефактов в репозиторий.
  7. Генерация отчётов по тестам.
  8. Запуск Sonar.

По скорости получается довольно быстро, учитывая, что средний по размеру проект (65 модулей, ~41к строк) с:

  • Генераторы protobuf, antlr4.
  • Backend (Spring Boot).
  • Frontend (NodeJS).
  • SAST, тесты, отчёты и прочее.

И пару скриншотов интерфейса, очень похож на GitHub.

Возможность доработок

Учитывая, что после смены GitLab на Gitea получилось сэкономить почти 8 GiB оперативной памяти, то решил в качестве эксперимента попробовал добавить сборку в RAM (tmpfs). Как бонус, ещё снизить IOPS и износ SSD дисков. По умолчанию, в раннере (Docker) нельзя смонтировать рабочую директорию как tmpfs. Все тома монтируются на локальную файловую систему внутри временного контейнера задачи. Единственный вариант – это запуск на хосте, без докера. Либо поднять VM и сделать там всё, но не очень всё это нравилось.

В целом ничего сложного, но для этого пришлось форкнуть два проекта:

Проблема только была с зависимостями и обновлением модуля Docker до версии с поддержкой опций для tmpfs. По умолчанию, выставляется флаг noexec и перестаёт работать protobuf-компилятор при сборке проекта. По итогу всё заработало и настраивается парой параметров через конфигурацию раннера.

YAML
container:
  workdir_mount_as_tempfs: true
  workdir_tempfs_options: [ [ exec ] ]

Сервер

Почему пытаюсь сэкономить ресурсы? Всё окружение пока решил развернуть на отдельной железке без виртуалок. Т.е. это минимально необходимый набор из:

  • DVCS (GitLab -> Gitea).
  • CI/CD (GitLab -> Gitea)
  • Репозитории артефактов Maven, NPM, Docker Registry (Nexus).
  • Общая RDBMS (PostgreSQL).
  • SAST (SonarQube).
  • NFS (Samba).
  • Трекер задач (YoutTrack -> Gitea).
  • Почтовый сервер (poste.io).
  • Агенты LLM и сами проекты.

Всё на Docker Compose, но возможно стоило Proxmox/ESXi использовать для развертывания отдельных VM. Но опять же вопрос, как их потом нарезать с минимальными накладными издержками.

Ещё вылезла проблема с низкой скоростью WiFi. Возможно, роутер не справляется, которому уже лет 11 или эфир забит (смена каналов не помогает). Больше 8 MiB/s не получалось увидеть при передаче файлов. В итоге, купил коммутатор с 2.5G портами и завёл всё на него. Пришлось вспомнить старые времена с обжимкой патч-кордов, но к счастью без прокладки коробов. Руки ещё помнят :).

Вообще думал, что будут проблемы со старым кабелем категории 5e и нужной скорости не получу. Да и и бухта с кабелем, тоже лет 11 пролежала без дела. Но нет, скорость между устройствами на теоретическом максимуме для 2.5G.

Shell
Accepted connection from fe80::ccce:ac20:594c:7b73, port 58386
[  5] local fe80::ecdf:64b9:2ebd:1c port 5201 connected to fe80::ccce:ac20:594c:7b73 port 49018
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   277 MBytes  2.32 Gbits/sec
[  5]   1.00-2.00   sec   277 MBytes  2.32 Gbits/sec
[  5]   2.00-3.00   sec   277 MBytes  2.32 Gbits/sec
[  5]   3.00-4.00   sec   277 MBytes  2.32 Gbits/sec
[  5]   4.00-5.00   sec   277 MBytes  2.32 Gbits/sec
[  5]   5.00-6.00   sec   277 MBytes  2.32 Gbits/sec
[  5]   6.00-7.00   sec   277 MBytes  2.32 Gbits/sec
[  5]   7.00-8.00   sec   277 MBytes  2.32 Gbits/sec
[  5]   8.00-9.00   sec   277 MBytes  2.32 Gbits/sec
[  5]   9.00-10.00  sec   277 MBytes  2.32 Gbits/sec
[  5]   9.00-10.00  sec   277 MBytes  2.32 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  2.82 GBytes  2.42 Gbits/sec                  receiver

Вот такая штука ExeGate EXE-725C-45 тоже оказалась полезной. Стоит недорого и нужна для ноута без RJ45 порта. Скорость как раз через неё в таблице выше.

Порты SFP+ в будущем можно для NAS использовать, если всё-таки соберу.

Заключение

Что сказать, теперь с Gitea. Нужно больше времени на тестирование, пока нравится больше GitLab и интерфейс кажется более удобным.

По потреблению ресурсов точно был смысл переходить. Если смотреть на возможности масштабирования, то на публичном хосте Gitea десятки тысяч проектов и пользователей, похоже масштабируется.

Gitea Gitlab Ci-Cd Homelab