27.04.2017
Как мы делали CI и что из этого вышло
Непрерывная интеграция (CI, англ. Continuous Integration) — практика разработки программного обеспечения, которая заключается в выполнении частых автоматизированных сборок проекта для скорейшего выявления и решения интеграционных проблем.
Все начиналось в далеком 2011-м. Для своих проектов мы начали использовать VCS (контроль версий). Реальной необходимости на тот момент не было, а подобные системы еще не были популярными.
Но мы поняли, что рано или поздно придется вводить эти инструменты в работу и решили попробовать.
В самом начале мы использовали SVN (не к ночи будет помянут). Чуть позднее внедрили в работу Git.
По мере роста количества проектов и репозиториев (равно как и количества сотрудников) на меня, как тимлида, стало обрушиваться огромное количество просьб от сотрудников (типа, “Спули в песок”). Поскольку временные затраты на подобные операции росли, мы написали первую версию собственного веб-инструмента для работы с удаленным репозиторием.
Основной задачей инструмента было выполнять команду git pull.
Разработка этого решения позволила значительно упростить процесс, избавиться от необходимости входа в консоль, а также дать возможность разработчикам выполнять все операции полностью самостоятельно без привлечения тимлида.
Стоит заметить, что для 2012 года, когда мы внедрили решение, это полностью уникальное решение для работы с VCS и огромный шаг к автоматизации, особенно учитывая, что помимо выполнения git-команд, сразу после внедрения в работу мы также добавили в нее возможность делать дампы баз данных и упаковывать медиафайлы, которые игнорируются в Git.
По самым скромным оценкам этот инструмент экономит тимлиду около 15-20 часов в месяц, в связи с чем повышает производительность труда, не отвлекая на рутинные операции.
Спустя некоторое время у нас появилась необходимость ветвления кода для ведения параллельных работ по конкретным функциям в отдельных ветках, а также потребность в создании архивов с изменениями.
Для того, чтобы избавиться от необходимости любого ручного вмешательства, а также избежать возможных ошибок, происходящих из-за человеческого фактора, мы разработали новую версию инструмента для автоматизации.
В новую версию мы добавили авторизацию, списки контроля доступа (ACL), переключение веток, создание патчей (архивов) с изменениями.
В интерфейс вынесли все основные операции по работе с репозиторием:
А также создали отдельную вкладку для работы с Git и упаковкой изменений в текущей выбранной ветке.
На этом этапе архив с изменениями загружался на рабочий компьютер тимлида, распаковывался и по FTP|SSH заливался на основной сайт с заменой старых частей кода.
Все эти решения экономили огромное количество времени, но никоим образом не решали вопроса автоматического запуска кода на production-сервер (он же PROD).
Для реализации деплоя в бой и десятка различных утилитарных задач, вроде проверки кода через php_codesniffer и т.п., были необходимы десятки скриптов.
Изначальная мысль разработать свою утилиту для выполнения этих задач была отброшена, и мы взяли на вооружение Jenkins.
Тем не менее, даже такой уровень автоматизации имеет свои сложности. Jenkins - это инструмент для организации выполнения ряда процедур в единую задачу. В нем нет единственной волшебной кнопки, которая выполнит задачу автоматически, на что когда-то были надежды. Для его использования необходимо точное и конкретное понимание того, какие процедуры вы будете выполнять, в какой очередности, соответственно схема будущего деплоя сначала должна быть строго формализована.
Например, вот так будет выглядеть схема двухсерверной конфигурации деплоя.
А вот так будет выглядеть трехсерверная конфигурация.
И в таком решении есть огромный плюс. Такой подход позволяет нам масштабировать деплой на 4,5 и большее количество серверов без лишних проблем и практически с нулевыми трудозатратами.
Используя нашу систему решения для автоматического деплоя мы и создавая задачу в Jenkins, мы запускаем следующую последовательность:
Задача Jenkins ведет мониторинг определенной ветку в Git репозитории. При появлении изменений она автоматически заливает изменения из этой ветки на указанный сервер.
Кроме того, мы используем Jenkins для следующих задач:
- Копирование базы данных и медиафайлой с PROD-сервера и их загрузка на DEV-сервер.
- Загрузка базы данных и медиафайлов с DEV на компьютер разработчика
Сам релиз на PROD выглядит следующим образом:
- На песке используется ветка DEV
- Функционал тестируется и полностью подготавливается к релизу
- Тимлид мержит DEV в MASTER и проводит PUSH в репозиторий
- Дальше запускается Jenkins, который опрашивает репозиторий раз в 30 минут и при наличии изменений заливает их в бой. Перед запуском код тестируется. После окончания деплоя программно очищается кэш и проводится еще десяток мелких процедур.
Мы используем замечательный Jenkins-плагин “Publish Over (SSH|FTP|etc.)”. Он не решает абсолютно всех задач по релизу на PROD, либо выкатывает вообще весь репозиторий.
(Хотя с помощью этого же плагина можно выполнять команды на удаленном сервере.)
Поскольку выкладывание всего репозитория на PROD никак не вписывается в понимание выкатывания релиза, мы разработали специальный скрипт, который вызывается из Ant в начале сборки релиза и подготавливает все файлы, необходимые для релиза.
Внедрение такой технически сложной системы подарило нам огромное количество возможностей:
- Выкатывание релиза происходит в полностью автоматизированном режиме, больше не требует часов скурпулезной работы и занимает считанные минуты.
- Решение позволило полностью синхронизировать PROD и DEV. Благодаря этому вероятность появления ошибок и багов на релизном продукте практически равны нулю.
- Чем больше сотрудников-программистов одновременно работает над проектом - тем больше выгода от внедрения CI. Благодаря созданию отдельных веток под отдельные задачи не произойдет никаких серьезных ошибок и пересечения разных задач. А вероятность ошибок от человеческого фактора при сборке практически сведена к нулю.