· 12 мин чтения

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

Меня зовут Семёнов Евгений Сергеевич, директор АйТи Фреш. С 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

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

Установка GitLab CE

Официально поддерживается 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 — обязательно отдельно

Самая частая ошибка новичков — запускать runner на том же сервере, что и GitLab. Тяжёлые пайплайны съедают RAM/CPU и сервер GitLab перестаёт отвечать.

Настройка runner на отдельной VM (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 PM. Проекты в GitHub (12 активных + 35 архивных). Решили уйти на свой GitLab из-за нестабильности доступа к GitHub и роста стоимости Team-подписки.

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

  1. Дни 1-2: VPS 4 vCPU / 16 ГБ / 200 ГБ NVMe в Selectel. Установка GitLab CE 17 на Debian 12.
  2. Дни 3-4: Настройка SMTP (отправка уведомлений через их Postfix), Keycloak SSO, GitLab Registry на отдельный VPS.
  3. Дни 5-6: Развёртывание 3 runner-ов (docker, native, windows) на отдельных VM. Первые тесты сборок.
  4. Дни 7-9: Миграция 47 репозиториев через GitHub Import. Автоматическое сохранение всех коммитов, issues, MR. Ручная миграция 24 workflow-файлов GitHub Actions → GitLab CI.
  5. День 10: Обучение команды: коммит, MR-процесс, запуск pipelines, работа с Registry. 3 часа.
  6. День 11: Бэкапы (ежедневный + off-site на MinIO), Zabbix-мониторинг, документация для нового админа.

Результат: экономия 112 тыс руб/год (vs 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 месяцев (в зависимости от числа пользователей).