CI/CD за пять минут и место GitLab в нём
Освежаем понятие CI/CD и смотрим, какую часть конвейера берёт на себя GitLab.
CI/CD — практика автоматически собирать, тестировать и доставлять код при каждом изменении, чтобы релиз был событием рутинным, а не подвигом.
Зачем вообще нужен конвейер
Представьте команду из пяти человек, которые каждый день вливают изменения в общий репозиторий. Без автоматизации кто-то должен вручную скачать новый код, собрать проект, прогнать тесты и выложить на сервер. Это медленно, скучно и ошибкоопасно: человек забудет шаг, перепутает ветку, выложит непротестированное. Непрерывная интеграция (CI) решает первую половину проблемы — на каждый push автоматически запускается сборка и тесты. Непрерывная доставка (CD) — вторую: проверенный артефакт автоматически (или по одному клику) едет в staging и production.
Главная боль ручного процесса — непостоянство: сегодня инженер прогнал все тесты, завтра спешил и прогнал половину, послезавтра забыл пересобрать фронтенд. Конвейер убирает этот человеческий фактор: правила записаны в файл, применяются ко всем одинаково и не зависят от настроения и дедлайна. Прикинуть выгоду легко: если ручная проверка одного изменения занимает пятнадцать минут, то при двадцати изменениях в день это пять человеко-часов, выкинутых на рутину, которую машина делает за секунды и никогда не устаёт.
Есть и второй эффект, более ценный в долгую — сокращение обратной связи. Чем раньше разработчик узнаёт, что его коммит сломал тест, тем дешевле починка: он ещё помнит контекст, изменение маленькое, виновный коммит очевиден. Если же баг всплывёт через неделю в куче чужих правок, на расследование уйдут часы. CI превращает «найти, кто и когда сломал» из детектива в одну красную галочку напротив коммита.
Если вы проходили наш курс по GitHub Actions, идея вам знакома: триггер → набор шагов → артефакт → деплой. GitLab CI/CD устроен на тех же принципах, но имеет важное отличие в философии, о котором — ниже.
Continuous Delivery против Continuous Deployment
Буква «D» в аббревиатуре скрывает две разные практики. Continuous Delivery (непрерывная доставка) означает, что любой зелёный коммит в любой момент готов поехать в production, но финальную кнопку нажимает человек. Continuous Deployment (непрерывное развёртывание) идёт дальше: зелёный коммит едет в production сам, без ручного подтверждения. Разница в одной строчке — when: manual на джобе деплоя превращает второе в первое. Большинство команд начинают с доставки и держат ручной гейт на production, пока не накопят доверия к своим тестам.
GitLab как единая платформа
GitHub исторически был хостингом репозиториев, а Actions добавили позже как отдельный продукт. GitLab с самого начала позиционирует себя как единая DevOps-платформа: в одном продукте живут репозиторий, issue-трекер, code review (Merge Requests), CI/CD, реестр контейнеров (Container Registry), реестр пакетов, мониторинг и сканеры безопасности. Идея в том, что весь жизненный цикл изменения — от идеи в issue до метрик в production — проходит внутри одной системы без склейки десятка сервисов.
┌─────────────────────────────────────────────┐ │ GitLab │ │ │ │ Issues → Merge Request → CI/CD Pipeline │ │ │ │ │ │ Git repo Container Registry │ │ │ │ │ │ Security scans → Environments (deploy)│ └─────────────────────────────────────────────┘
Для нас как авторов пайплайнов это означает приятную вещь: реестр образов, переменные секретов и окружения деплоя уже встроены и интегрированы. Не нужно отдельно настраивать Docker Hub, отдельный vault для секретов и отдельную систему для отслеживания, что и куда задеплоено.
У «всё в одном» есть и оборотная сторона. Связанность экосистемы — это удобство, но и зависимость: уходя с GitLab, вы уносите не только репозиторий, но и пайплайны, реестр, историю окружений. В мире GitHub те же функции часто собраны из независимых кусочков (Actions + Docker Hub + сторонний vault), которые легче заменить по отдельности. GitLab оптимизирует целостность и интеграцию, а связка вокруг GitHub — гибкость выбора; для команды, которая хочет минимум движущихся частей, монолитность GitLab скорее плюс.
GitLab vs GitHub Actions: ключевые различия
Чтобы не путаться весь курс, зафиксируем соответствие понятий двух платформ в одной таблице. Слова разные, идеи во многом совпадают.
| Идея | GitLab CI/CD | GitHub Actions |
|---|---|---|
| Файл конфигурации | .gitlab-ci.yml (один на проект) | несколько файлов в .github/workflows/ |
| Единица процесса | pipeline | workflow |
| Группировка шагов | stages → jobs | jobs → steps |
| Кто исполняет | GitLab Runner | GitHub-hosted / self-hosted runner |
| Переиспользование | встроенный реестр + include | Marketplace готовых actions |
| Ревью изменений | Merge Request | Pull Request |
Главное отличие в подходе к переиспользованию: GitHub Actions сделали ставку на маркетплейс готовых блоков, где пайплайн собирают как из кубиков, а GitLab чаще предлагает писать команды оболочки напрямую и подключать готовые куски через include. У первого подхода ниже порог входа, у второго — больше прозрачности: вы видите ровно те команды, что выполняются.
Что приводит конвейер в движение
Ядро GitLab CI/CD — файл .gitlab-ci.yml в корне репозитория. GitLab читает его при каждом событии (push, открытие Merge Request, расписание) и порождает пайплайн — набор джоб, сгруппированных по стадиям. Сами джобы выполняет GitLab Runner — отдельный агент, который берёт задачу, скачивает код и запускает ваши команды. Эту тройку — файл, пайплайн, раннер — мы будем изучать весь курс.
Стоит сразу разделить роли. Сервер GitLab — это мозг: он хранит код, читает YAML и решает, какие джобы создать и в каком порядке их выпускать. Раннер — это руки: отдельная программа, возможно на другой машине, которая физически выполняет команды. Такое разделение даёт масштабируемость — один сервер управляет десятками раннеров — и объясняет, почему пайплайн без подключённого раннера зависает: мозг отдал команду, а рук, чтобы её выполнить, нет.
Как работает под капотом
Когда вы делаете git push, GitLab-сервер получает изменение и проверяет наличие .gitlab-ci.yml. Если файл есть, сервер парсит YAML, строит граф джоб и помещает их в очередь. Свободный раннер забирает джобу, разворачивает чистое окружение (например, контейнер Docker), клонирует репозиторий нужного коммита и выполняет указанные команды. Результат — успех или провал каждой джобы — отправляется обратно на сервер и отображается в интерфейсе Merge Request.
Обратите внимание на слово «чистое окружение». Каждая джоба, как правило, стартует с нуля: свежий контейнер, чистая файловая система, никаких следов предыдущих запусков. Это намеренно — так пайплайн становится воспроизводимым: результат зависит только от кода и конфигурации, а не от того, что осталось на машине после вчерашней сборки. Платой за чистоту служит то, что между джобами ничего не передаётся само собой: если стадии сборки нужны зависимости со стадии тестов, их придётся явно сохранить через cache или artifacts. Пока важно усвоить принцип: изоляция — это фича, а не помеха.
Частые ошибки
- Думать, что GitLab CI/CD требует отдельной установки. На GitLab.com он включён сразу; в self-hosted GitLab тоже встроен, нужен лишь зарегистрированный раннер.
- Путать CI и CD. CI — про проверку каждого коммита, CD — про доставку. Можно иметь CI без автоматического деплоя.
- Ожидать, что пайплайн заработает без раннера. Файл может быть идеальным, но без подключённого раннера джобы останутся в статусе pending.
- Рассчитывать, что файлы и пакеты сами «переедут» из джобы в джобу. Окружения изолированы; обмен — только через
cacheиartifacts. - Смешивать Continuous Delivery и Continuous Deployment. Первое оставляет ручной гейт на production, второе деплоит автоматически — это сознательный выбор, а не деталь.
Итоги
- CI автоматизирует сборку и тесты на каждое изменение, CD — доставку артефакта; быстрая обратная связь удешевляет починку.
- GitLab — единая платформа: репозиторий, MR, CI/CD, реестр, секреты и сканеры в одном месте; плата за интеграцию — связанность.
- Конвейер описывается в
.gitlab-ci.yml, исполняется раннерами, отображается в Merge Request; сервер — мозг, раннер — руки. - Джобы изолированы и воспроизводимы; обмен данными между ними — явный, через cache и artifacts.