Pull to refresh

Выкатываем в бой

Reading time6 min
Views3.7K
К бою! Внедрение конечного веб-продукта является не самой приятной процедурой для создателя и часто сопровождается жутким стрессом. Нелюбовь разработчика к релизам связана не только с чувствами ответственности и страха перед эксплуатацией новой версии, но и с ощущениями неопределенности: а что будет после того, как внедримся?

Приложения могут разрабатываться большим коллективом программистов, инженеров по качеству, графическим интерфейсам, но в конце проектного пути ответственность на себя берет последний из могикан. Недостаток теоретических знаний заставляет нервничать нашего героя, ведь опыта, приобретенного вследствие проб и ошибок, под час не достаточно для систематически успешного внедрения. Чтобы разобраться, как правильно выкатывать веб-проекты в бой, начнем, пожалуй, с основ.

План генштаба

техпроцесс разработки

Получив требования, спецификации, всевозможные рекомендации и указания, разработчик выделяет в репозитории исходного кода пространство для своих маневров. Такой областью может быть персональная ветка SVN, новый модуль в CVS или папка на файловой системе.

Нет смысла подробно рассказывать о последующих циклах «Develop – Test – Deploy»: про них и так много чего полезного написано. Отмечу лишь важные наблюдения:
  • Приложение каждого разработчика должно использовать персональные БД и файловые хранилища. Использовать общую «помойку» — зло, порождающее серьезные ошибки.
  • Разработка автотестов не всегда оправдана: их реализация не должна отнимать больше 20% рабочего времени. Разрабатывать через тестирование – крайняя степень расточительства.
  • Чем больше участников в техпроцессе, тем чаще необходимо сливаться и проверять коллективный результат. Непрерывная интеграция сможет помочь, но ее сопровождение может оказаться накладным – нужно балансировать между автоматизацией и затратами.
Итоговые результаты разработки фиксируются в релиз-кандидате (сливаются ветки, создается тег и пр.) и передаются в приемочное тестирование. Релиз-кандидат – это конечный монолитный продукт, в который нельзя вносить изменения. Если необходимо исправить ошибки, доработать функционал – необходимо начинать с начала и делать нового кандидата.

Тяжело в учении

Стоит отметить, что многие менеджеры проводят приемочное тестирование в среде разработки, что в корне не верно. Понятно, что делать отдельного кандидата для нанобагов очень лениво (и расточительно). Но отработанная однажды процедура внедрения на тестовую платформу существенно сэкономит разработчику время и нервы. Тем более никто не мешает компоновать мелкие исправления в группы и фиксировать их в одной версии продукта.

Основные хинты приемочного тестирования:
  • Сценарий внедрения кандидата должен быть максимально приближен к сценарию внедрения релиза. Если в конечном релизе планируется обновить структуру БД, мигрировать данные, добавить сторонние библиотеки – сделать все это необходимо именно в той последовательности, в которой предполагается внедрение релиза.
  • Условия тестовой платформы должны быть максимально приближены к условиям боевой. Если приложение использует кластер из 5 memcached-серверов – подготовьте >1 сервера на тестовой платформе. Если приложение использует 1 master-сервер СУБД в режиме RW и 2 slave-сервера в режиме RO – воссоздайте полную схему репликации. Сэкономить на оборудовании для тестирования распределенных систем поможет бесплатный VMWare Server (или любой другой аналог, кроме Virtuozzo). Версии системных библиотек, ядра ОС и пр. должны также совпадать с версиями соответствующих компонент боевой платформы.
  • Нагрузочное тестирование является плавающей проблемой приемочного тестирования. Полностью воссоздать условия релиза невозможно: мы не знаем, какой точно будет нагрузка, мы можем только предполагать. Да и создавать полную копию боевой платформы накладно. Для адекватного тестирования обычно выделяют в приложении узкие места, измеряют для них максимальные значения устойчивости и аппроксимируют результаты на ожидаемые нагрузки.
  • Тестирование должно быть регрессионным, но нужно балансировать между качеством и затратами. Если внесены только косметические изменения в интерфейс, нет смысла прогонять тест-план полностью.
  • Не забудьте об откате приложения, возврат к предыдущей версии должен быть тщательно отработан.
Переход от кандидата к релизу может занять определенное количество итераций «Кандидат – Тестирование – Изменение». В ходе цикла будут находиться новые баги, меняться требования и вноситься изменения. В конечном итоге, придется разорвать порочный круг и делать релиз. И крайне редко предрелизный отчет о тестировании оказывается на 100% завершенным (разработчики в таких случаях отмазываются приставкой beta).
Рулил я когда-то разработкой портала о рекламе. Команде тогда пришлось выкатить ~20 кандидатов до внедрения релиза. Релиз внедрили с 10-ого раза. Итоговый отчет о тестировании был успешен на ~70%. Не самый удачный проект в моей жизни.

К оружию

Порядок внедрения релиза должен быть следующим:
  1. Внедряем новые версии компонент платформы. Обновляем библиотеки, сервисы и пр., при этом оставляем себе инструмент для отката до старых версий.
  2. Внедряем БД и файловое хранилище. В случае если в бою работает предыдущая версия приложения, необходимо заранее подготовить старый релиз к поддержке новой структуры хранилищ. История такая:
    • добавляем предыдущему релизу поддержку новой схемы хранения
    • внедряем измененный предыдущий релиз
    • внедряем новую структуру хранения и мигрируем данные (предыдущий релиз должен работать в старой логике с новым хранилищем)
    • внедряем новый релиз
  3. Внедряем приложение.
  4. Тестируем приложение.
  5. Откатываемся (если необходимо).
В случае факапа откатываемся к предыдущей версии в обратном порядке:
  1. Откатываем приложение.
  2. Откатываем БД и файловое хранилище (если необходимо).
  3. Откатываем компоненты платформы (если необходимо).

Приложение в бой

Во-первых, приложение должно быть спроектировано таким образом, чтобы ее структура папок была отделена от файлового хранилища.
Правильно
/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
Во-вторых, необходимо контролировать версии библиотек сторонних разработчиков. Чтобы быть уверенным, что в бою используется поддерживаемая версия библиотеки Zend Framework, необходимо либо включить библиотеку в структуру папок приложения (и держать ее в svn), либо представлять релиз в виде пакета (например, deb), с помощью которого проверять зависимости.

В-третьих, многие разработчики внедряют приложение в бой обновлением из репозитория исходного кода (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
После извлечения исходного кода проект инсталлируется (настраиваются конфиги, права, стартовые данные) и тестируется рядом с работающим релизом, для чего может использоваться отдельный виртуальный хост веб-сервера (например, www-test.myproject.ru). После прогона тест-плана, предыдущий релиз подменяется новым. Известны следующие варианты замены релизов: изменение символической ссылки, mount_null, изменение конфига веб-сервера с последующим graceful restart.
Символической ссылкой мы переключаем проект с одного релиза на другой.
Таким же образом можно откатится к предыдущей версии.
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. В ходе переписки с одним из хабраюзеров сформулировалось: главным в этом информационном обращении является не навязывание своих рекомендаций, а то что я заставляю человека задуматься о проблемах, которые могут возникнуть в своей конкретной ситуации. Общие рекомендации на*^& никому не нужны. В итоге, каждый делает по-своему. И это правильно. Потому что каждый проект уникален.
Tags:
Hubs:
Total votes 84: ↑77 and ↓7+70
Comments43

Articles