Пускането на нова версия на проекта в продукция изисква внимателно балансиране между темп на внедряване и надеждност на решението. В компанията Slack ценят бързите итерации, кратките цикли на обратна връзка и бързата реакция на запитванията на потребителите. Освен това, в компанията работят стотици програмисти, които се стремят към максимална производителност.
Авторите на материала, чието преведение публикуваме днес, казват, че компания, която се стреми да следва подобни ценности и в същото време расте, трябва постоянно да подобрява своята система за внедряване на проекти. Компанията трябва да инвестира усилия в прозрачността и надеждността на работните процеси, така че те да съответстват на мащабите на проекта. Тук ще говорим за работните процеси, установени в Slack, и за някои решения, които доведоха до използването на съществуващата днес система за внедряване на проекти.
Как днес работят процесите на внедряване на проекти
Всеки PR (pull request) в Slack задължително трябва да бъде подложен на кодови прегледи и да премине успешно през всички тестове. Само след изпълнението на тези условия програмистът може да слее своя код с master клона на проекта. Въпреки това, внедряването на подобен код се извършва само в работно време по северноамериканско време. В резултат на това, благодарение на наличието на нашите служители на работните места, сме напълно готови да решаваме всякакви неочаквани проблеми.
Всеки ден извършваме около 12 планирани внедрявания. По време на всяко внедряване програмистът, назначен за главен по внедряването, отговаря за пускането на новата версия в продукция. Това е многостепенен процес, който осигурява плавно прехвърляне на версията в работен режим. Благодарение на този подход можем да откриваме грешки, преди те да засегнат всичките ни потребители. Ако грешките са твърде много — внедряването може да бъде отменено. Ако обаче конкретен проблем бъде открит след пускането, лесно може да бъде издадено коригиращо решение.

Интерфейсът на системата Checkpoint, която се използва в Slack за внедряване на проекти
Процесът на пускане на нова версия в продукцията може да бъде представен в четири стъпки.
▍1. Създаване на клон на версията
Всяка версия започва с нов клон на версията, от момента в нашата Git история. Това позволява да назначаваме тагове на версията и предоставя място, където можем да направим спешни корекции на грешки, открити по време на подготовката на версията за пускане в продукция.
▍2. Разгръщане в междинна среда
Следващата стъпка е разгръщането на сборката на междинни (staging) сървъри и стартиране на автоматичен тест за общата работоспособност на проекта (smoke test). Междинната среда е производствена среда, която не получава външен трафик. В тази среда провеждаме допълнително ръчно тестване. Това ни дава допълнителна увереност, че промененият проект работи коректно. Самостоятелните автоматизирани тестове не са достатъчни, за да получим подобна увереност.
▍3. Разгръщане в dogfood и canary среди
Разгръщането в продукция започва с dogfood среда, представляваща набор от хостове, които обслужват нашите вътрешни работни пространства в Slack. Тъй като сме много активни потребители на Slack, прилагането на този подход ни помогна да открием много грешки на ранен етап от разгръщането. След като се уверим, че основната функционалност на системата не е нарушена, се извършва разгръщане на сборката в canary среда. Тя представлява системи, на които преминава около 2% от продукционния трафик.
▍4. Постепенно пускане в продукция
Ако показателите за мониторинг на новата версия са стабилни и ако след разгръщането на проекта в canary среда не сме получили оплаквания, продължаваме с постепенното преминаване на продукционните сървъри към новата версия. Процесът на разгръщане е разделен на следните етапи: 10%, 25%, 50%, 75% и 100%. В резултат на това можем бавно да прехвърлим продукционния трафик към новата версия на системата. Така имаме време да проучим ситуацията в случай на откритие на аномалии.
▍Какво да правим, ако по време на разгръщането нещо не е наред?
Внасянето на модификации в кода винаги е риск. Но ние се справяме с това благодарение на наличието на добре подготвени "главни по разгръщането", които ръководят процеса на пускане на нова версия в продукция, наблюдават показателите за мониторинг и координират работата на програмистите, които пускат кода.
В случай, че нещо наистина е сгрешило, ние се опитваме да открием проблема възможно най-рано. Изследваме проблема, намираме PR, който предизвиква грешките, откатваме го, внимателно го анализираме и създаваме нова версия. Въпреки това, понякога проблемът остава незабелязан до пускането на проекта в продукция. В такава ситуация най-важното е да възстановим работата на услугата. Ето защо, преди да започнем да проучваме проблема, незабавно откатваме до предишната работеща версия.
Строителни блокове на системата за разгръщане
Нека разгледаме технологиите, които стоят в основата на нашата система за разгръщане на проекти.
▍Бързи разгръщания
Работният процес, описан по-горе, може да изглежда, в ретроспекция, напълно очевиден. Но нашата система за разгръщане не стана такава веднага.
Когато компанията беше значително по-малка, цялото ни приложение можеше да работи на 10 инстанции на Amazon EC2. Разгръщането на проекта в такава ситуация означаваше прилагането на rsync за бърза синхронизация на всички сървъри. Преди това новият код беше отделен само с една стъпка от продукцията, представена от междинна среда. Версиите се създаваха и проверяваха в такава среда, а след това веднага отиваха в продукция. Разбирането на такава система беше много лесно, тя позволяваше на всеки програмист по всяко време да разгръща написания от него код.
Но с нарастващия брой на нашите клиенти, мащабите на инфраструктурата, необходима за функционирането на проекта, също нараснаха. Скоро, с постоянния растеж на системата, нашата модел за разгръщане, основан на изпращането на нов код на сървърите, спря да се справя със задачата си. А именно, добавянето на всеки нов сървър означаваше увеличаване на времето, необходимо за извършване на разгръщането. Дори стратегиите, основани на паралелното приложение на rsync, имат определени ограничения.
В крайна сметка решихме проблема, преминавайки към напълно паралелна система за разгръщане, изградена по различен начин от старата система. А именно, сега не изпращахме код на сървърите, използвайки скрипт за синхронизация. Всеки сървър сега самостоятелно изтегляше новото издание, научавайки, че е необходимо да го направи, благодарение на наблюдението на промените в ключа Consul. Сървърите изтегляха кода паралелно. Това ни позволи да поддържаме висока скорост на разгръщане дори в условия на постоянен растеж на системата.

1. Производствени сървъри наблюдават ключа Consul. 2. Ключът се променя, което уведомява сървърите, че трябва да започнат да изтеглят нов код. 3. Сървърите изтеглят tarball файлове с кода на приложението.
▍Атомарни разгръщания
Друго решение, което ни помогна да достигнем до многостепенна система за разгръщане, беше атомарното разгръщане.
Преди да започнем да използваме атомарни разгръщания, всяко разгръщане можеше да доведе до появата на множество съобщения за грешки. Факт е, че процедурата за копиране на нови файлове на производствени сървъри не беше атомарна. Това водеше до съществуването на кратък времеви интервал, в който кодът, в който бяха извиквани нови функции, стана достъпен преди самите функции да станат налични. Когато такъв код беше извикван, това водеше до връщане на вътрешни грешки. Това се проявяваше в неуспешни API заявки и „разчупени“ уеб страници.
Екипът, който се зае с този проблем, го реши, въвеждайки понятието „горещи“ (hot) и „студени“ (cold) директории. Кодът в „горещата“ директория отговаря за обработката на производствения трафик. А в „студените“ директории кодът, по време на работа на системата, просто се подготвя за използване. В процеса на разгръщането новият код се копира в неизползваната „студена“ директория. След това, когато на сървъра няма активни процеси, се извършва мигновено превключване на директориите.

1. Разопаковане на кода на приложението в „студената“ директория. 2. Превключване на системата на „студената“ директория, която става „гореща“ (атомарна операция)
Резюме: фокусиране върху надеждността
През 2018 година проектът достигна такива мащаби, че бързото разгръщане започна да вреди на стабилността на продукта. Имахме доста напреднала система за разгръщане, в която вложихме много усилия и време. Нужно беше само да преработим и усъвършенстваме процесите на организацията на разгръщането. Станахме достатъчно голяма компания, чиито разработки се използваха в цял свят за осигуряване на непрекъсната свързаност и решаване на важни задачи. Затова надеждността се оказа в центъра на нашето внимание.
Трябваше да направим процеса на разгръщане на новите версии на Slack по-безопасен. Тази необходимост ни доведе до усъвършенстване на нашата система за разгръщане. Всъщност, по-горе обсъдихме тази усъвършенствана система. В недрата на системата продължаваме да използваме технологии за бързо и атомарно разгръщане. Промени се начинът, по който се извършва разгръщането. Нашата нова система е предназначена за постепенно разгръщане на нов код на различни нива, в различни среди. Сега използваме по-съвременни, отколкото преди, помощни инструменти и средства за мониторинг на системата. Това ни дава възможност да улавяме и отстраняваме грешки рано, преди те да имат шанс да достигнат до крайния потребител.
Но ние не планираме да спрем дотук. Постоянно усъвършенстваме тази система, прилагане на по-съвременни помощни инструменти и средства за автоматизация на работата.
Уважаеми читатели! Как е устроен процесът на разгръщане на нови версии на проектите, където работите вие?
Източник: habr.com
