GitLab self-hosted для малой команды разработки: установка, CI/CD, резервирование — АйТи Фреш
· 12 мин чтения

GitLab self-hosted для малой команды разработки: установка, CI/CD и миграция с GitHub

GitLab self-hosted для малой команды разработки: установка, CI/CD и миграция с GitHub

Привет! Я Евгений Семёнов, директор ITFresh. С 2022 года мы видим, как доступ к GitHub для российских компаний превратился в настоящую головную боль. То аккаунты наших клиентов блокируются, то CI/CD падает в самый неподходящий момент, а про санкционные риски и говорить нечего. Неудивительно, что ко мне всё чаще приходят с одним и тем же вопросом: «Евгений, нам нужен свой GitLab на своём сервере!» Если у вас команда из 10-30 разработчиков, эту проблему мы решаем буквально за пару недель. Стоимость? Около 100 тысяч рублей. В этой статье я поделюсь нашим опытом: расскажу, как собрать GitLab под ключ, сколько будет стоить его дальнейшая поддержка и к каким нюансам нужно быть готовым.

Зачем свой GitLab

Три причины:

Какую редакцию выбрать

EditionЦенаФишкиДля кого
CE (Community)БесплатноGit, MR, Issues, CI/CD, Registry, PagesКоманды до 50 разработчиков
EE Premium$29/user/месSAML SSO, Merge approvals, PortfolioКоманды 50+, формальные процессы
EE Ultimate$99/user/месSAST/DAST/DEPs/Fuzzing сканеры, ComplianceEnterprise с требованиями security

Для наших клиентов из малого и среднего бизнеса (МСБ) версии GitLab CE обычно хватает с лихвой. Серьёзно, там есть всё необходимое: двухфакторная аутентификация (2FA), единый вход через OIDC/SAML (SSO), и даже approvals для мерж-реквестов, которые можно настроить прямо через Push Rules. А вот о версии Ultimate стоит задуматься, только если вам кровь из носу нужна автоматическая проверка security-уязвимостей на самом высоком, compliance-уровне.

Установка GitLab CE

GitLab предлагает несколько вариантов установки: Omnibus (это когда всё в одном пакете), стандартный docker-образ или Helm chart для Kubernetes. На практике, если у вас команда до 50 человек, мы обычно ставим Omnibus на Debian 12. Это самый простой и надёжный путь.

# Добавляем репозиторий
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash

# Устанавливаем
EXTERNAL_URL="https://git.example.ru" apt install gitlab-ce

# После установки — первый вход через reset password:
gitlab-rake "gitlab:password:reset[root]"
# Вводите новый пароль

Сертификат Let's Encrypt Omnibus настраивает сам, если в конфиге указан https URL и 80/443 порты свободны. Дальше редактируем /etc/gitlab/gitlab.rb:

# Главные настройки
external_url 'https://git.example.ru'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "mail.example.ru"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "gitlab@example.ru"
gitlab_rails['smtp_password'] = "[...]"

# Backup
gitlab_rails['backup_path'] = "/var/opt/gitlab/backups"
gitlab_rails['backup_keep_time'] = 604800  # 7 дней

# Registry для Docker-образов
registry_external_url 'https://registry.example.ru'

# Применить
gitlab-ctl reconfigure

GitLab Runner — обязательно отдельно

А вот типичная ошибка, которую многие допускают: запускать GitLab Runner прямо на одном сервере с самим GitLab. Делать так не советуем! Стоит запустить хоть один тяжёлый пайплайн, как он тут же съест всю оперативку и процессор, а ваш сервер GitLab просто «ляжет».

Как мы делаем правильно? Настраиваем runner на отдельной виртуальной машине. Вот наша стандартная конфигурация: Debian 12, 2 vCPU и 4 ГБ оперативной памяти.

# Установка
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | bash
apt install gitlab-runner

# Регистрация
gitlab-runner register \
  --url https://git.example.ru \
  --registration-token abc123def456 \
  --executor docker \
  --docker-image alpine:latest \
  --description "docker-runner-01" \
  --tag-list "docker,linux"

Для параллельных сборок — параметр concurrent = 4 в /etc/gitlab-runner/config.toml. Несколько runner-ов с разными tags:

Миграция с GitHub

Хорошая новость: GitLab умеет импортировать данные напрямую, используя GitHub Personal Access Token.

# В GitLab: Admin → Settings → General → Import and export settings
# Включить: GitHub

# Пользователь: New Project → Import → GitHub
# Вставляет PAT с правами repo + admin:org + read:user
# Выбирает проекты для импорта

Что переносится:

Что НЕ переносится:

Базовый .gitlab-ci.yml

Пример для typical Python-проекта:

stages:
  - lint
  - test
  - build
  - deploy

variables:
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache"

cache:
  paths:
    - .pip-cache/

lint:
  stage: lint
  image: python:3.12
  script:
    - pip install ruff mypy
    - ruff check .
    - mypy .
  only:
    - merge_requests
    - main

test:
  stage: test
  image: python:3.12
  services:
    - postgres:16
  variables:
    POSTGRES_DB: test
    POSTGRES_PASSWORD: testpass
  script:
    - pip install -r requirements.txt -r requirements-dev.txt
    - pytest --cov=./ --cov-report=xml
  coverage: '/TOTAL.*\s+(\d+%)$/'

build:
  stage: build
  image: docker:25
  services:
    - docker:25-dind
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  only:
    - main

deploy:
  stage: deploy
  image: alpine
  script:
    - apk add --no-cache openssh
    - ssh deploy@prod "docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA && docker-compose up -d"
  only:
    - main
  when: manual  # только по кнопке

Интеграция с Keycloak SSO

В /etc/gitlab/gitlab.rb:

gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_auto_sign_in_with_provider'] = 'openid_connect'
gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect']
gitlab_rails['omniauth_block_auto_created_users'] = false

gitlab_rails['omniauth_providers'] = [
  {
    name: 'openid_connect',
    label: 'Corp SSO',
    args: {
      name: 'openid_connect',
      scope: ['openid','profile','email'],
      response_type: 'code',
      issuer: 'https://sso.example.ru/realms/corp',
      discovery: true,
      client_auth_method: 'query',
      uid_field: 'preferred_username',
      send_scope_to_token_endpoint: 'true',
      client_options: {
        identifier: 'gitlab',
        secret: 'your-client-secret-from-keycloak',
        redirect_uri: 'https://git.example.ru/users/auth/openid_connect/callback'
      }
    }
  }
]

gitlab-ctl reconfigure

Бэкапы и восстановление

Встроенный инструмент:

# Ежедневный бэкап в cron
0 2 * * * /opt/gitlab/bin/gitlab-backup create CRON=1

# Отдельно — конфигурация
0 3 * * * tar -czf /var/opt/gitlab/config-$(date +%F).tgz /etc/gitlab

# Восстановление
systemctl stop gitlab-runner
gitlab-ctl stop unicorn
gitlab-ctl stop sidekiq
gitlab-backup restore BACKUP=1698000000_2025_12_03_17.4.0
gitlab-ctl reconfigure
gitlab-ctl start

Обязательно копия конфигов /etc/gitlab/gitlab-secrets.json и /etc/gitlab/gitlab.rb отдельно — без них восстановление невозможно.

А как быть с резервными копиями Off-site? Для их создания мы обычно используем borgbackup с хранением в MinIO S3 или syncoid для синхронизации на второй сервер.

Кейс: студия на 18 разработчиков

В ноябре 2025 к нам пришла одна веб-студия. Команда: 18 разработчиков, 4 дизайнера и 3 проджект-менеджера. Все их проекты (12 активных и 35 архивных) жили в GitHub. Причина обращения была проста и понятна: надоела нестабильность доступа к GitHub, да и стоимость Team-подписки росла, как на дрожжах. Решили, что пора переезжать на свой GitLab.

Что сделали за 11 рабочих дней:

  1. Итак, что мы делаем в первые два дня? Разворачиваем VPS в Selectel: 4 vCPU, 16 ГБ оперативной памяти и 200 ГБ NVMe-диска. Сразу же ставим GitLab CE 17 на чистый Debian 12.
  2. На третий и четвёртый день занимаемся настройками. Это включает SMTP для отправки уведомлений (обычно через Postfix клиента), подключение Keycloak SSO и разворачивание GitLab Registry, но уже на отдельном VPS.
  3. Что мы делали на пятый и шестой день? Активно разворачивали инфраструктуру: установили сразу три runner-а – Docker, нативный и Windows – каждый на отдельной виртуальной машине. А потом, конечно, приступили к первым тестам сборок. Важно было убедиться, что всё работает, как задумано.
  4. Следующие три дня, с седьмого по девятый, были посвящены большой миграции. Представьте, мы перенесли 47 репозиториев! Для этого использовали GitHub Import, что позволило автоматически сохранить абсолютно все коммиты, issues и merge-реквесты. Но ведь не всё можно сделать кнопкой. Ещё 24 workflow-файла из GitHub Actions пришлось переписывать вручную под GitLab CI. Это была настоящая ювелирная работа.
  5. На десятый день мы собрали команду. Провели трёхчасовое обучение. Ведь что толку от новой системы, если никто не знает, как ей пользоваться? Детально объяснили, как правильно делать коммиты, как устроен MR-процесс, как запускать пайплайны и эффективно работать с Registry. За три часа мы убедились, что каждый участник команды готов к работе с новыми инструментами.
  6. Одиннадцатый день — время финальных штрихов для максимальной надёжности. Мы настроили ежедневные бэкапы, а также обеспечили их off-site хранение на MinIO. Это значит, что ваши данные будут в безопасности, что бы ни произошло. Конечно, не забыли про Zabbix-мониторинг для круглосуточного контроля системы. И, что не менее важно, подготовили подробнейшую документацию – чтобы любому новому администратору было легко войти в курс дела.

Что же получила студия в итоге? Во-первых, заметную экономию: целых 112 тысяч рублей в год, если сравнивать с платной GitHub Team-подпиской на 25 пользователей. Во-вторых, полный контроль над своим кодом. И, конечно же, полную независимость от любых санкционных рисков! Сам проект обошёлся в 115 тысяч рублей плюс 14 тысяч рублей ежемесячно за VPS и runners. Вложения, кстати, окупаются меньше чем за год.

Типовые проблемы эксплуатации

Развернём GitLab для вашей команды — от 95 000 руб.

Я лично проектирую и разворачиваю self-hosted GitLab для команд разработки 5-50 человек в Москве и области. Установка, миграция с GitHub / Bitbucket, настройка CI/CD runners, интеграция с Keycloak SSO, Registry, бэкапы. Типовой проект — 1-2.5 недели. Первичный аудит текущей инфраструктуры и план миграции — бесплатно.

Телефон: +7 903 729-62-41
Telegram: @ITfresh_Boss
Семёнов Евгений Сергеевич, директор АйТи Фреш

FAQ — GitLab self-hosted

GitLab CE или EE?
CE (Community Edition) — бесплатный навсегда, покрывает 95% задач малой и средней команды: issues, merge requests, CI/CD, registry, pages. EE (Enterprise) — дополнительно DORA-метрики, Secure-сканеры, SAML SSO (есть и в CE через OIDC), audit log. Для команд до 30 разработчиков — CE достаточно.
Какое железо нужно?
Для команды 10-30 разработчиков: 4 vCPU / 16 ГБ RAM / 100 ГБ SSD для самого GitLab + 2 vCPU / 4 ГБ RAM на каждый runner. GitLab довольно прожорлив к RAM — Sidekiq, Puma, PostgreSQL, Redis, Gitaly. На 8 ГБ будет тормозить.
Нужны ли отдельные серверы для runners?
Да, всегда. Никогда не запускайте runners на том же сервере, что сам GitLab. Пайплайны могут съесть все ресурсы и положить GitLab. Минимум — отдельная VM на 2 vCPU / 4 ГБ RAM. Для частых сборок — несколько runners с tags (docker, linux, windows).
Можно ли мигрировать с GitHub?
Да. GitLab имеет встроенный импорт с GitHub — проекты, issues, pull requests (становятся MR), комментарии, релизы. Типовая миграция 10-30 репозиториев — 1-3 дня. Переменные CI/CD и секреты переносятся вручную. GitHub Actions → GitLab CI требует переписывания workflow-файлов.
Сколько стоит self-hosted GitLab под ключ?
Для команды 15-25 разработчиков: VPS для GitLab — 10-15 тыс руб/мес, 2-3 runner-а — ещё 5-8 тыс/мес, работа по установке + миграция с GitHub + настройка CI/CD + интеграция с Keycloak/AD — от 95 тыс руб разово. Окупается против GitHub Team за 6-14 месяцев (в зависимости от числа пользователей).

Подпишитесь на рассылку ITfresh

Каждую неделю мы делимся практическими гайдами, которые будут полезны и IT-руководителям, и сисадминам. Ждите советы по безопасности, работе с 1С, миграциям, настройке резервных копий и, конечно, лайфхаки, проверенные на наших реальных проектах.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.