Внедрение конечного веб-продукта является не самой приятной процедурой для создателя и часто сопровождается жутким стрессом. Нелюбовь разработчика к релизам связана не только с чувствами ответственности и страха перед эксплуатацией новой версии, но и с ощущениями неопределенности: а что будет после того, как внедримся?
Приложения могут разрабатываться большим коллективом программистов, инженеров по качеству, графическим интерфейсам, но в конце проектного пути ответственность на себя берет последний из могикан. Недостаток теоретических знаний заставляет нервничать нашего героя, ведь опыта, приобретенного вследствие проб и ошибок, под час не достаточно для систематически успешного внедрения. Чтобы разобраться, как правильно выкатывать веб-проекты в бой, начнем, пожалуй, с основ.
Получив требования, спецификации, всевозможные рекомендации и указания, разработчик выделяет в репозитории исходного кода пространство для своих маневров. Такой областью может быть персональная ветка SVN, новый модуль в CVS или папка на файловой системе.
Нет смысла подробно рассказывать о последующих циклах «Develop – Test – Deploy»: про них и так много чего полезного написано. Отмечу лишь важные наблюдения:
Основные хинты приемочного тестирования:
Во-вторых, необходимо контролировать версии библиотек сторонних разработчиков. Чтобы быть уверенным, что в бою используется поддерживаемая версия библиотеки Zend Framework, необходимо либо включить библиотеку в структуру папок приложения (и держать ее в svn), либо представлять релиз в виде пакета (например, deb), с помощью которого проверять зависимости.
В-третьих, многие разработчики внедряют приложение в бой обновлением из репозитория исходного кода (svn up). Сравнить такой подход можно разве что с rm –rf /. Релиз необходимо полностью извлекать из репозитория и размещать в отдельном от предыдущего релиза месте.
После извлечения исходного кода проект инсталлируется (настраиваются конфиги, права, стартовые данные) и тестируется рядом с работающим релизом, для чего может использоваться отдельный виртуальный хост веб-сервера (например, www-test.myproject.ru). После прогона тест-плана, предыдущий релиз подменяется новым. Известны следующие варианты замены релизов: изменение символической ссылки, mount_null, изменение конфига веб-сервера с последующим graceful restart.
Если приложение распределенное:
Приложения могут разрабатываться большим коллективом программистов, инженеров по качеству, графическим интерфейсам, но в конце проектного пути ответственность на себя берет последний из могикан. Недостаток теоретических знаний заставляет нервничать нашего героя, ведь опыта, приобретенного вследствие проб и ошибок, под час не достаточно для систематически успешного внедрения. Чтобы разобраться, как правильно выкатывать веб-проекты в бой, начнем, пожалуй, с основ.
План генштаба
Получив требования, спецификации, всевозможные рекомендации и указания, разработчик выделяет в репозитории исходного кода пространство для своих маневров. Такой областью может быть персональная ветка SVN, новый модуль в CVS или папка на файловой системе.
Нет смысла подробно рассказывать о последующих циклах «Develop – Test – Deploy»: про них и так много чего полезного написано. Отмечу лишь важные наблюдения:
- Приложение каждого разработчика должно использовать персональные БД и файловые хранилища. Использовать общую «помойку» — зло, порождающее серьезные ошибки.
- Разработка автотестов не всегда оправдана: их реализация не должна отнимать больше 20% рабочего времени. Разрабатывать через тестирование – крайняя степень расточительства.
- Чем больше участников в техпроцессе, тем чаще необходимо сливаться и проверять коллективный результат. Непрерывная интеграция сможет помочь, но ее сопровождение может оказаться накладным – нужно балансировать между автоматизацией и затратами.
Тяжело в учении
Стоит отметить, что многие менеджеры проводят приемочное тестирование в среде разработки, что в корне не верно. Понятно, что делать отдельного кандидата для нанобагов очень лениво (и расточительно). Но отработанная однажды процедура внедрения на тестовую платформу существенно сэкономит разработчику время и нервы. Тем более никто не мешает компоновать мелкие исправления в группы и фиксировать их в одной версии продукта.Основные хинты приемочного тестирования:
- Сценарий внедрения кандидата должен быть максимально приближен к сценарию внедрения релиза. Если в конечном релизе планируется обновить структуру БД, мигрировать данные, добавить сторонние библиотеки – сделать все это необходимо именно в той последовательности, в которой предполагается внедрение релиза.
- Условия тестовой платформы должны быть максимально приближены к условиям боевой. Если приложение использует кластер из 5 memcached-серверов – подготовьте >1 сервера на тестовой платформе. Если приложение использует 1 master-сервер СУБД в режиме RW и 2 slave-сервера в режиме RO – воссоздайте полную схему репликации. Сэкономить на оборудовании для тестирования распределенных систем поможет бесплатный VMWare Server (или любой другой аналог, кроме Virtuozzo). Версии системных библиотек, ядра ОС и пр. должны также совпадать с версиями соответствующих компонент боевой платформы.
- Нагрузочное тестирование является плавающей проблемой приемочного тестирования. Полностью воссоздать условия релиза невозможно: мы не знаем, какой точно будет нагрузка, мы можем только предполагать. Да и создавать полную копию боевой платформы накладно. Для адекватного тестирования обычно выделяют в приложении узкие места, измеряют для них максимальные значения устойчивости и аппроксимируют результаты на ожидаемые нагрузки.
- Тестирование должно быть регрессионным, но нужно балансировать между качеством и затратами. Если внесены только косметические изменения в интерфейс, нет смысла прогонять тест-план полностью.
- Не забудьте об откате приложения, возврат к предыдущей версии должен быть тщательно отработан.
Рулил я когда-то разработкой портала о рекламе. Команде тогда пришлось выкатить ~20 кандидатов до внедрения релиза. Релиз внедрили с 10-ого раза. Итоговый отчет о тестировании был успешен на ~70%. Не самый удачный проект в моей жизни.
К оружию
Порядок внедрения релиза должен быть следующим:- Внедряем новые версии компонент платформы. Обновляем библиотеки, сервисы и пр., при этом оставляем себе инструмент для отката до старых версий.
- Внедряем БД и файловое хранилище. В случае если в бою работает предыдущая версия приложения, необходимо заранее подготовить старый релиз к поддержке новой структуры хранилищ. История такая:
- добавляем предыдущему релизу поддержку новой схемы хранения
- внедряем измененный предыдущий релиз
- внедряем новую структуру хранения и мигрируем данные (предыдущий релиз должен работать в старой логике с новым хранилищем)
- внедряем новый релиз
- Внедряем приложение.
- Тестируем приложение.
- Откатываемся (если необходимо).
- Откатываем приложение.
- Откатываем БД и файловое хранилище (если необходимо).
- Откатываем компоненты платформы (если необходимо).
Приложение в бой
Во-первых, приложение должно быть спроектировано таким образом, чтобы ее структура папок была отделена от файлового хранилища.Правильно/var/www/myproject/ /etc/ /lib/ /classes/ /images/ /templates/ index.php /var/www/userdata/ /images/ /video/ |
Не правильно/var/www/myproject/ /etc/ /lib/ /classes/ /images/ /templates/ /userdata/ /images/ /video/ index.php |
В-третьих, многие разработчики внедряют приложение в бой обновлением из репозитория исходного кода (svn up). Сравнить такой подход можно разве что с rm –rf /. Релиз необходимо полностью извлекать из репозитория и размещать в отдельном от предыдущего релиза месте.
Релизы размещаются в отдельных папках на боевой платформеuser@stable:~/apps/myproject$ ls -la drwxr-xr-x 12 user www-data 4096 Окт 29 11:38 . drwxr-xr-x 5 user www-data 4096 Май 13 23:22 .. drwxr-xr-x 8 user www-data 4096 Окт 22 17:11 rel_0.5.1 drwxr-xr-x 8 user www-data 4096 Окт 27 13:17 rel_0.5.1.1 drwxr-xr-x 8 user www-data 4096 Окт 28 02:07 rel_0.5.1.2 drwxr-xr-x 8 user www-data 4096 Окт 29 11:38 rel_0.5.2 user@stable:~/apps/myproject$ svn co svn+ssh://user@svn.myproject.ru/myproject/tags/rel_0.5.2.1 ... user@stable:~/apps/myproject$ ls -la drwxr-xr-x 12 user www-data 4096 Окт 29 11:38 . drwxr-xr-x 5 user www-data 4096 Май 13 23:22 .. drwxr-xr-x 8 user www-data 4096 Окт 22 17:11 rel_0.5.1 drwxr-xr-x 8 user www-data 4096 Окт 27 13:17 rel_0.5.1.1 drwxr-xr-x 8 user www-data 4096 Окт 28 02:07 rel_0.5.1.2 drwxr-xr-x 8 user www-data 4096 Окт 29 11:38 rel_0.5.2 drwxr-xr-x 8 user www-data 4096 Окт 29 12:31 rel_0.5.2.1 |
Символической ссылкой мы переключаем проект с одного релиза на другой. Таким же образом можно откатится к предыдущей версии. user@stable:~/httpdocs/ $ ls –la drwxr-xr-x 3 user www-data 4096 Окт 29 11:40 . drwxr-xr-x 9 user www-data 4096 Окт 28 21:25 .. lrwxrwxrwx 1 user www-data 27 Окт 29 11:40 pro -> ../apps/myproject/rel_0.5.2 user@stable:~/httpdocs/ $ rm pro && ln –s ../apps/myproject/rel_0.5.2.1 pro user@stable:~/httpdocs/ $ ls –la drwxr-xr-x 3 user www-data 4096 Окт 29 11:40 . drwxr-xr-x 9 user www-data 4096 Окт 28 21:25 .. lrwxrwxrwx 1 user www-data 27 Окт 30 17:12 pro -> ../apps/myproject/rel_0.5.2.1 |
- отключаем часть бэкендов, перенаправив весь трафик с фронтов на оставшиеся рабочие
- На отключенных бэкендах проводим локальные внедрения и тесты
- переключаем трафик на свежие бэкенды
- повторяем процедуру для освободившихся бэкендов
- В результате поблочного внедрения фронтенды переключаем в нормальное состояние и распределяем нагрузку по всем бэкендам.
P.S. Если хватит сил закончить повествование, ждите вторую часть о прелестях LiquiBase, подводных камнях rsync и миграции файловых хранилищ.
P.P.S. В ходе переписки с одним из хабраюзеров сформулировалось: главным в этом информационном обращении является не навязывание своих рекомендаций, а то что я заставляю человека задуматься о проблемах, которые могут возникнуть в своей конкретной ситуации. Общие рекомендации на*^& никому не нужны. В итоге, каждый делает по-своему. И это правильно. Потому что каждый проект уникален.