Казалось бы, 2025 год, а CI/CD до сих пор есть не везде, где релизы — регулярная рутина. А там, где есть, оно порой работает так, что лучше бы не работало.
🤔 Для начала разберёмся с терминами
Есть путаница. CD — это не просто “нажал кнопку — код задеплоился”. Это подход к разработке, в котором каждое изменение потенциально готово к релизу (см. Фаулера — он пишет сложно, но полезно).
Но когда говорят “CI/CD”, чаще всего имеют в виду: “я запушил код, и он магически оказался на серверах”. Ну, магия магией, но работать это должно стабильно.
🤔 Как это устроено
Есть две модели доставки кода:
- Push — код выталкивается в среду (Jenkins, GitLab CI).
- Pull — среда сама забирает нужное из репозитория (ArgoCD, Flux).
Если триггернуться на слово "ArgoCD" — можно развести холивар про gitops-подходы, в этой заметке хотелось бы этого избежать. Поэтому сосредоточимся на GitLab CI — удобной системе, где CI/CD строится на простых скриптах.
Pipeline в GitLab CI — это просто последовательность команд. Например:
stages:
- update_code
- restart_service
update_code:
stage: update_code
script:
- git pull origin main
restart_service:
stage: restart_service
script:
- systemctl restart myservice
Этот pipeline обновляет код и перезапускает сервис. Всё просто? Нет.
🤔 Проблема с git pull
Наивная схема с git pull кажется рабочей, но тут две проблемы:
1. Изменения не атомарные!
Когда идёт git pull — файлы подменяются прямо на работающем сервисе. Если код обновился не весь (например, разорвался посреди обновления), приложение скорее всего разнесёт на куски.
2. Неуправляемое состояние.
Файлы на сервере могли быть случайно (или не случайно) изменёны вручную. Где гарантия, что git pull не выдаст конфликт? А если обновление потребует миграции БД?
Не получится сделать просто git pull && restart. Должен быть механизм откатов, контроль за зависимостями, тестирование перед выкладкой.
Ой, что-то сложно, давайте не делать? Можно сделать сначала "наивный" вариант, а по мере того, как будет отстреливать и придётся решать конфликты руками — обкладываться костылями вокруг. Эволюционный подход.
Ну или – сделать доставку атомарной сразу. Например, с помощью Docker?
🤔 Почему Docker не спасает
Окей, допустим, вместо git pull мы собираем и выкатываем контейнеры:
script:
- docker build -t my-app .
- docker run -d my-app
Но тут свои нюансы, которые иногда могут отстрелить нам ноги:
- Сборка образа не случится мгновенно. Если тянуть зависимости, сборка может идти долго.
- Чистка старых образов. Хранилище контейнеров растёт в размере, и если не следить, место на диске тупо кончится.
- Проблема зависимостей. Если код требует новую версию PostgreSQL, просто пересборка образа не поможет.
То есть Docker решает часть проблем, но не все (и создаёт новые 😳)
🤔 Почему у вас до сих пор нет CI/CD
1. Возможно вы не знаете bash? Не беда, у вас есть ChatGPT. Например, спросите его, как написать скрипт, который проверяет, запущен ли сервис, и если нет — перезапускает.
2. Возможно у вас нет времени? CI/CD как раз освобождает время. Задумайтесь, сколько часов в неделю уходит на ручные сборки, регрессы, конфликты при мерже. Выявите это и автоматизируйте.
3. Вас кидает с проекта на проект? Если нет времени на наведение порядка, может, пора сменить работу?
🤔 С чего начать
Начните с простого — автоматизируйте любую рутинную задачу. Например, вместо ручного git pull && restart сделайте скрипт:
#!/bin/bash
git pull origin main && systemctl restart myservice
И хотя бы проверьте, что он сработает, а не развалит всё к чертям.
CI/CD — это не про сложные пайплайны, а про здравый смысл. Чем раньше начнёте, тем меньше будете тратить время на рутину.