Был ли опыт работы с CI/CD в GitLab?

Ответ

Да, у меня есть опыт настройки и поддержки CI/CD пайплайнов в GitLab для проектов, включая ML-сервисы и бэкенд-приложения. Основная цель — автоматизация сборки, тестирования, анализа кода и развертывания.

Ключевые задачи, которые решал:

  • Автоматизация тестирования: Запуск юнит- и интеграционных тестов при каждом пуше в merge request (MR).
  • Статический анализ кода: Интеграция с pylint, black, mypy для Python-проектов.
  • Сборка и публикация Docker-образов: Автоматическая сборка образа при мерже в основную ветку и его отправка в GitLab Container Registry или сторонний реестр.
  • Развертывание: Настройка деплоя в staging/production среды (вручную через manual jobs или автоматически).
  • Кеширование зависимостей: Использование кеша для pip/poetry и Docker-слоев для ускорения сборки.

Пример .gitlab-ci.yml для Python/ML проекта:

stages:
  - lint
  - test
  - build
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

# 1. Проверка кода
lint:
  stage: lint
  image: python:3.10-slim
  script:
    - pip install black pylint mypy
    - black --check --diff .
    - pylint --fail-under=7.0 src/
    - mypy src/
  only:
    - merge_requests

# 2. Запуск тестов
test:
  stage: test
  image: python:3.10-slim
  script:
    - pip install -r requirements.txt
    - pytest tests/ --cov=src --cov-report=xml
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml
  only:
    - merge_requests
    - main

# 3. Сборка Docker-образа
build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE
  only:
    - main

# 4. Деплой (ручной запуск)
deploy_staging:
  stage: deploy
  image: alpine:latest
  script:
    - echo "Deploying $DOCKER_IMAGE to staging..."
    # Здесь команды для деплоя (kubectl, ansible, ssh)
    - kubectl set image deployment/ml-service app=$DOCKER_IMAGE -n staging
  when: manual
  only:
    - main

Использованные возможности GitLab CI: артефакты, кеши, environments, manual jobs для контроля деплоя, правила (only/except), секретные переменные (CI/CD Variables).

Ответ 18+ 🔞

А, ну это про ту самую магию, когда ты в репу что-то закинул, а дальше оно само собирается, тестируется и, если не сломалось, даже куда-то выкатывается. Да, занимался этим делом, и не раз. Цель простая — чтобы всё летало на автомате, а не приходилось каждый раз вручную, как обезьяна, команды в консоли тыкать.

Что конкретно делал, чтобы жизнь мёдом не казалась:

  • Автоматические тесты: Настроил так, что как только ты создаёшь мерж-реквест — сразу начинается цирк. Юниты, интеграционные проверки — всё прогоняется, и если что-то сломал, тебе сразу же красненьким подсветят. Волнение ебать, но зато работает.
  • Проверка кода на вшивость: Интегрировал разные линтеры и форматтеры (pylint, black, mypy). Чтобы код был не только рабочим, но и хотя бы отдалённо похожим на человеческий, а не на поток сознания после пятницы. Доверия ебать ноль к коллегам, которые пишут как бог на душу положит.
  • Сборка Docker-образов: Сделал так, что когда код попадает в основную ветку (main), автоматически собирается свежий Docker-образ и заливается в реестр (GitLab Registry или куда надо). Больше никаких «ой, а я забыл собрать».
  • Выкатка на стенды и в прод: Настроил деплой. На тестовый стенд можно выкатить вручную, кнопочку нажать — это manual job. А в прод уже построже, с дополнительными проверками. Чтобы не получилось «ой, а я случайно продакшен снёс».
  • Ускорение всего этого безобразия: Использовал кеширование для пиповских зависимостей и слоёв Docker, чтобы каждый раз не ждать овердохуища времени, пока всё заново скачается.

Вот пример конфига .gitlab-ci.yml, который я для одного ML-сервиса на Python пилил:

stages:
  - lint
  - test
  - build
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

# 1. Стадия "Причесать код"
lint:
  stage: lint
  image: python:3.10-slim
  script:
    - pip install black pylint mypy
    - black --check --diff .  # Проверяем, отформатирован ли код
    - pylint --fail-under=7.0 src/  # Если качество кода ниже 7 — падаем
    - mypy src/  # Проверяем типы
  only:
    - merge_requests  # Запускаем только для MR, чтобы не грузить основную ветку

# 2. Стадия "Проверить, не сломал ли чего"
test:
  stage: test
  image: python:3.10-slim
  script:
    - pip install -r requirements.txt
    - pytest tests/ --cov=src --cov-report=xml  # Запускаем тесты и считаем покрытие
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml  # Сохраняем отчёт, чтобы GitLab его красиво показал
  only:
    - merge_requests
    - main

# 3. Стадия "Упаковать в контейнер"
build:
  stage: build
  image: docker:latest
  services:
    - docker:dind  # Нужно для сборки Docker внутри Docker
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE  # Пушим образ в реестр
  only:
    - main  # Собираем только с основной ветки

# 4. Стадия "Выкатить на тестовый стенд"
deploy_staging:
  stage: deploy
  image: alpine:latest
  script:
    - echo "Deploying $DOCKER_IMAGE to staging..."
    # А вот тут уже магия деплоя: kubectl, ansible или просто ssh
    - kubectl set image deployment/ml-service app=$DOCKER_IMAGE -n staging
  when: manual  # Ручной запуск! Самый ответственный момент
  only:
    - main

Что из фишек GitLab CI использовал: Артефакты (чтобы тестовые отчёты сохранялись), кеши (чтобы не ждать вечность), environments (для разделения стендов), эти самые manual jobs (чтобы случайно не наделать дел), правила only/except (чтобы пайплайн бегал где надо), и, конечно, секретные переменные (CI/CD Variables), чтобы пароли и токены не светить в коде. В общем, стандартный набор, чтобы не изобретать велосипед, а работать.