Еволюція процесу деплоя у проекті



Денис Яковлєв (2ГІС
Мене звуть Денис, я працюю в компанії 2ГІС, близько півтора років займаюся питаннями continuous delivery для проектів веб-відділу. До цього працював у компанії Parallels і там пройшов шлях від QA інженера до team lead'а.

Про deploy. Якщо ми з вами не випускаємо коробковий продукт, а пишемо якийсь сервіс, який працює десь, як багато хто називають, в дикій природі, на серверах, куди заходять користувачі, то нам недостатньо просто розробити цей сервіс та протестувати, нам потрібно ще його в цю дику природу як-то задеплоить, тобто доставити туди код разом з усім необхідним для його роботи.

З чого це складається? Нам потрібно доставити, насамперед, код — те, над чим ми працювали велику кількість часу, тестували та інше.



Ми можемо зробити це багатьма способами, загальнодоступними і не дуже, ми можемо як-небудь заливати, можемо підключити наші серваки до системи контролю версій і просто пулиться.

Далі, дані.



Якщо у нас база даних, тобто ми використовуємо в нашому сервісі базу даних, у нас періодично виникає потреба з цими даними щось робити. Нам потрібно змінювати структуру бази даних, або міняти самі дані, тобто якщо ми постійно пишемо якусь нову функціональність, ми розвиваємося, у нас це відбувається неминуче. В основному це здійснюється з допомогою міграції. Напевно, всі вже знають цей механізм. Якщо ми в розробці використовуємо якийсь загальноприйнятий фреймворк, не нами написаний, а який існує, всі його знають, там міграції вбудовані, тобто звичайними командами ми це все виконуємо. Наприклад, yii migrate, django-admin migrate.



Мало який сервіс не вимагає конфігурації. Ми заделиверили код, дані проапдейтили, у нас якісь зміни сталися, ми повинні сконфігурувати. У нас є конфіг файли, там є якісь значення, ми їх змінюємо, і в процесі життя у нас теж в ці конфіг файли або додаються нові значення, або старі деприкейтятся, вони дропаются. Після того, як у нас все це змінилося, нам потрібно або сервіси які-небудь рестартовать, або залишити як є.



Якщо ми не обійшлися без використання стороннього програмного забезпечення, ми повинні подбати про те, що це треба на наші сервера якось поставити, сконфігурувати певним чином, який потрібен нам, і своєчасно його апгрейдити. Чи не апгрейдити, якщо раптом у новій версії софта вийшла якась бага, щоб у нас все не полягло.

Які виникають рішення «в лоб»?



У нас є один сервачок, ми йдемо і робимо все це ручками, тому що всі кроки відомі, все відомо, як робити. І у нас є, припустимо, команда розробки та команда експлуатації — адмін який-небудь сидить. Команда розробки пише документацію про те, що ось зараз такий реліз і для його успішного деплоя потрібно зробити те-то, те-то і те-то. Адмін дивиться на цю документацію, йде по SSH на сервак і це ручками і виконується. Так він раз сходив, два сходив, потім йому це набридло.



Він, природно бере, те, що загальнодоступно і під рукою. Він бере Bash, Perl і все це автоматизує, бо навіщо все це робити руками, коли можна все це автоматизувати і просто запускати Bash.

Плюси:



Це все просто, добре, швидко, ми працюємо, код деливерится, ми нічого не помічаємо, але це добре лише до певного часу, для простих проектів. У нас є, припустимо, один сервачок, на ньому база даних, на ній наш код лежить — це цілком менеджебл однією людиною, і він може цілком з цим справлятися.

Мінуси:



Але ж ми хочемо розвиватися, ми розвиваємося. Наш сервіс стає складним, у нас з'являються нові сервіси, приходить більше користувачів, ми більше не обходимося одним серваком, у нас з'являються нові складові, тобто у нас вже не один сервер з кодом, а в нас уже великий бойовий контур, що складається з декількох серверів, компонентів та інше. І у нас в зв'язку з цією зростаючою складністю, тобто з нашим розвитком, з'являються проблеми, яких раніше не було. У нас збільшується кількість документації, тобто інформації про те, як спеціально навченому людині провести реліз. Навіть якщо у цієї людини давно заготовлені скрипти, які в певних умовах добре виконували свою роботу, складність цих скриптів у нього теж зростає, їх кількість зростає, тепер потрібно не один сервер апгрейдити, а потрібно апгрейдити базу, апгрейдити код, ще щось треба робити. Складність зростає. Скрипти — це теж той софт, в якому можуть бути баги, це теж починає приносити певну головний біль.

Так як ми почали все це дуже швидко робити, поки ми не відчували особливих проблем, у нас є якась кількість ручної праці. Спочатку це не дуже помітно, а потім це наростає як сніжний ком, а ручна праця — це додаткове джерело людських помилок. Хто-то что-то не так і не туди записав, або записав туди, але не так, другий неправильно скопіпастив, і в результаті виходить така ситуація, коли дуже багато помилок, і всі вони виникають, і не зрозуміло, коли вони закінчаться і звідки беруться. У підсумку, у нас це спеціально навчена людина, який відповідав за релізи, тільки і робить, що релизит. Тобто у нього немає часу на якісь інші його завдання, немає часу навіть поїсти. Він викотив один реліз, поки його викочував, прийшов другий реліз, під час цього релізу трапилися якісь помилки, потім ще прийшов патч на цей реліз. Загалом, цей великий такий головняк, нервозність зростає, а бізнес до нас приходить і каже: «Чого ви не можете до клієнтів доставити код? Адже це просто і швидко, а в нас тут ще вагон фіч йде далі, давайте щось з цим робити!».

Певний час існує такий підхід в нашій індустрії, як «Infrastructure as a code», який говорить нам, що ми повинні підходити до опису конфігурації нашого додатка так само, як ми підходимо до розробки програмного забезпечення. Так Кейф Моріс сказав:



Це трохи більше, ніж проста автоматизація, тому що автоматизація — це ми просто беремо і все, що ми ручками робимо, заганяємо в скрипт, і він працює. У підході «Infrastructure as a code» ми використовуємо всі практики, тулзы і підходи. Ми беремо це з розробки програмного забезпечення нашого сервісу і застосовуємо до опису інфраструктури. Тобто якщо з'явився новий підхід, відповідно, для його реалізації з часом з'являються і тулзы, тобто програмне забезпечення.

Які інструменти є?



Є такий клас продуктів   Сonfiguration Management System, тобто CMS (не плутати з Content management system!). Типові представники — Ansible, Chef, SaltStack, Puppet. Вони створені для того, щоб нам, як розроблювачам або як компаніям, допомогти в управлінні інфраструктурою. І одним із завдань, одним з use case'ів застосування такого є приведення нашої системи в певний описане нами стан. Тобто якщо у нас є, нам виділили абстрактний сервак, там нічого немає чи там є якась гола вісь, то за допомогою таких інструментів ми наводимо сервак в потрібне нам стан.

Давайте подивимося на деякі з цих інструментів. Я вибрав ті, які використовуються у нас в компанії, щоб на прикладах пояснити. По-перше, Anisble.



Це досить проста для розуміння, написана на Python, модульне, досить легко встановлюється і, як ми для себе відзначили в компанії, поріг входження для використання Ansible досить низький. Тобто якщо ми беремо людину, говоримо: ось тобі Ansible, розберися і почни його використовувати, він до кінця тижня бадьоренько пише, все це розуміє.

Що нам потрібно зробити після того, як ми встановили Ansible?



Нам спочатку потрібно написати, а що у нас взагалі є, з чим нам хочеться працювати? Тобто ми простий текстовий файлик створюємо, і пишемо як на наведеному вище прикладі, що у нас є група [webservers], у нас є два экзампла   www.example1.com і www.example2.com, група [dbservers], тобто db1, db2. Це наш, грубо кажучи, бойової контур, і з ним ми хочемо працювати.

Далі, в Ansible є така сутність — playbook'і:



Playbook — це набір інструкцій, тобто ті кроки, які Ansible належить зробити, щоб наші сервера привести у той стан, яке нам потрібно. Тобто playbook'і складаються з hosts (ми вказуємо, з якими хостами ми хочемо працювати) і tasks –вказуємо ті кроки, які Ansible потрібно зробити. І є командочка — ми говоримо: «Запусти цей playbook, інформацію про хостах візьми з цього файлу.

Приклад playbook'а:



Ми вказуємо hosts (якщо хто запам'ятав — webservers). Це та група хостів, яка у нас вказана в Ansible инвенторе. Ми говоримо, що хочемо поставити nginx на ті сервери, які ми вказали там.

Завдання складаються у нас в даному випадку з двох кроків:

  1. ми спочатку оголошуємо ім'я, щоб нам потім можна було розібратися, що ми робимо, тобто ми пишемо Install nginx — цей крок відповідає у нас за установку nginx'а й пишемо в даному випадку yum — це модуль Ansible, що відповідає за установку через yum. Ми говоримо: «yum, постав нам пакет nginx останньої версії».
  2. наступний крок — ми повинні сконфігурувати nginx, тому ми модулю template говоримо: «У нас в рамках цього playbook'а є файл default.conf, поклади його, будь ласка, з цього шляху, і після того, як ти це зробив, тобто notify, перестартуй nginx».
Ми запускаємо командочку ansible-playbook з цим playbook'ом, і після виконання цього playbook'а у нас на серверах групи webservers виходить встановлений nginx, налаштований як нам треба.

Архітектура виглядає приблизно так:



Я взяв це з Інтернету, цю картинку можна вільно нагуглити. У нас є Host Inventory, Playbooks, Core Modules — це модулі, які написані самою командою Ansible, що якраз відповідає yum, apt та інше; Custom Modules — це те, що там написано ком'юніті або ще якими-небудь контрибуторами; Plugins. Запускається Ansible, йде за хостами і виконує те, що йому потрібно. Примітно те, що на тих хостах, з якими ми працюємо, нам додаткового ПО не треба, тобто у нас як наші серваки стояли-працювали, так вони і працюють. Там має бути, по-моєму, тільки Python, але Python є практично скрізь.

З цим коротко зрозуміло, давайте для порівняння подивимось Chef.



Chef — це того ж класу, але написано іншою компанією. На мою думку, воно трохи складніше, навіть може бути набагато складніше, ніж Ansible, тому що у нас, якщо людина до кінця тижня починає писати і розбирається в Ansible, і вже починає видавати якийсь код, а з Chef йому кілька тижнів розбиратися, як там працює, які фішки, щоб видавати якийсь результат.

Якими ми тут оперуємо термінами?



  • Cookbooks — це рецепти. Якщо у випадку Ansible человекочитаемо все добре, зрозуміло, то у випадку з Chef cookbooks — це у нас Ruby, тут буде потрібно якийсь час, щоб освоїти, якщо не повністю, але якийсь базовий рівень цієї мови програмування.
  • Ще у нас є Roles — способи групування Cookbooks. Припустимо, у нас є роль «вебсервер» для налаштування веб-сервера. Нам потрібно поставити nginx, сконфигурить, ще щось зробити, присідання тощо. Це у нас розбито на кілька cookbooks, і ми робимо окрему роль — «вебсервер», в якій говоримо, що ці cookbooks туди входять, і цю роль призначаємо на потрібні нам серваки. І тоді ми бачимо, що у нас є стільки-то вебсерверов, і такими способами ми наводимо їх у потрібний стан.
  • Є у нас Environment — опис нашого оточення, тобто якщо у нас є девелопмент оточення, стейжинг оточення, є продакш оточення, яке відрізняється якимись параметрами, тобто ми тут маємо можливість, по-моєму, в JSON описати, оголосити список змінних, якими відрізняються наші оточення, відповідно значення для кожного оточення прописати.
Chef існує в декількох конфігураціях, тобто як його можна встановити.

  1. Chef server.



    Ми ставимо окремий сервак де-то в нашому оточенні, в якому зберігаються всі наші cookbooks, ролі, environment, ноди з описом та інше.

    На кожній ноде нашої варто клієнтське ПО — Chef client, яке налаштоване на цей сервак. І воно ходить туди за описом цієї ноди, тобто вона приходить і
    каже: «Я така ось нода, скажи мені, будь ласка, що у мене є ролями, з яких-небудь додаткових налаштувань, за рецептами, що мені потрібно
    зробити?». Chef сервак їй відповідає: «Ось, виконуй, будь ласка, ці рецепти з такими вхідними параметрами», та утилітка все це застосовує.

    Якщо хтось звернув увагу, Ansible трохи по-іншому, тобто у випадку з Chef сервером, ми, по-перше, ставимо додаткове ПЗ на наші ноди, і ми заходимо
    на самі ноди, або віддалено повинні покликати цей Chef client. У Ansible ми говоримо Ansible playbook на нашій робочої тачці, і він йде сам по SSH
    виконує всі на наших серверах.

    Але це одна конфігурація Chef.

  2. Далі у нас є Chef zero — це лайтовый варіант Chef Server, тобто без gui, він in memory, тобто ми просто його такого легковажного підняли, завантажили туди всю нашу інформацію для тестування, перевірили все це, задеплоили, вбили Chef zero, і у нас все звільнилося — все добре.
  3. Також є Chef solo — це open source версія утилітки Chef client, яка на відміну від перших двох випадків не вимагає підключення до якогось зовнішнього серваку. Нам тут не потрібен ні Chef server, ні Chef zero, ми просто в цьому випадку говоримо Chef solo, що: «У нас є шлях, по якому лежать наші рецепти, виконай, будь ласка, звідти такі-то ось рецепти». У такій конфігурації ми отримуємо, що всі наші cookbooks, рецепти повинні знаходитися в потрібний нам час на тому ж инстансе, де у нас розташований Chef solo.
Це простий приклад, як виглядає установка nginx на Chef в рецептах.



Я хочу зазначити, що це дуже маленька частина функціональності цих всіх інструментів, які я згадав, тобто там є набагато більше можливостей, use case'ів, складових та інше. Це великі складні інструменти, вони вирішують широке коло завдань, але зараз в рамках цієї доповіді, ми говоримо тільки про одне use case'е — як нам задеплоиться.

Припустимо, ми подивилися, визначилися, вирішили, що нам підходить якийсь інструмент, і що ж нас чекає крім якихось технічних питань? Ми ж працюємо в команді. Ми можемо сказати, що з сьогоднішнього дня ми використовуємо, припустимо, Ansible. Добре, що ми далі отримуємо?

Отримуємо нові процедурні питання — це зона відповідальності, тобто я, як team leader, вирішую, що тепер ми використовуємо Ansible, але у мене стоїть питання, хто у мене повинен писати playbooks?



Розробники? Вони до мене приходять і кажуть: «Ми не будемо писати playbooks, тому що ми не знаємо бойову конфігурацію». Добре, я йду до адмінам і кажу: «Тепер ви пишете playbooks». Вони кажуть: «Ми playbooks писати, вибач, не будемо, тому що ми не знаємо додатки». Це приклад з повітря для розуміння. І цю ситуацію ми повинні якось резолвить, тому що виходить, що знання для написання playbooks, рецептів у нас розмазані. Частина знань у нас є в одній команді, частина — в іншій команді.

Наведу приклад, як таку штуку ми вирішували у себе в відділі. У нас є багато продуктів, сервісів, і вони різного ступеня складності. І один дуже складний перевантажений наш проект — це Web API. Ми зробили так: у нас адміни взяли Chef, написали всю базу. У нас 3 датацентру по 18 серверів, децентралізація тощо. І такі таски адміни взяли на себе, написали всю цю конфігурацію, раздеплоились у всі датацентри, переконалися, що все це працює. Потім в процесі життя продукту, коли змінюються ті параметри, про яких адміни не знають, як я приводив приклад — тобто у нас в кофиге щось змінилося, ми почали використовувати інші ще якісь утилітки… Це все те, що вирішується в процесі розробки продукту. Адміни прийшли, навчили розробників писати playbooks, розповіли, що таке Chef, з чим його їдять, як готувати, і потім після цього моменту команда розробки сама почала писати ці playbooks. Коли зміни у нас критичні або дуже складні, ризиковані, то команда розробки бере, і сама це пише і просто на рев'ю віддає адмінам, і вони дивляться, як це буде лягати в поточну інфраструктуру і залишає якісь коментарі.

Інші ж сервіси простіше. Вони взяли, і подивилися, що Chef для нас — це занадто складно, надмірно та інше. Вони взяли Ansible, самі написали, швиденько розібралися, самі все написали, прийшли до адмінам і сказали: «Подивіться, чи можна так?». Ті подивилися і сказали: «Так, ні, не знаю, може бути».

З зоною відповідальності виникає питання. Срібної кулі, як і практично скрізь, немає. Потрібно так резолвить, напевно, в кожному проекті, в кожному сервісі по-своєму.

І, природно, у нас змінюється workflow. У нас з'являються нові таски, інструментарії, та workflow розробки у нас змінюється.

Якщо з написанням, все зрозуміло — ми чогось подивилися, вивчили, нам надали інстанси цього Chef сервера або ще щось, ми взяли улюблений текстовий редактор, якось пристосувалися, почали писати… Але виникає наступне питання — нам же треба якось це все тестувати, тому що у нас виходить точно такий же код, як він себе веде, нам теж треба розуміти. І якщо на цьому моменті не дай бог, розробники свій сервіс деплоят собі ж на робочій тачці, то тут все погано і сумно і без віртуалізації тут не обійдешся. Тому що мені треба підняти тачку, раптом я там написав щось погане, що все зламалося, мені потрібно це все швиденько вбити, передеплоить, пофіксити, передеплоить, подивитися, як працює… Я знаю, я бачив такі команди, бачив такі компанії, які досі віртуалізацію не використовують взагалі ніяк. Може, це нормально так, допустимо, але я особисто не розумію, як можна без віртуалізації жити. Якщо ми деплоимся на своїй тачці, і віртуалізації немає, то в цьому моменті вона просто необхідна.

Vagrant — це не інструмент для тестування, але це те, що може нам допомогти швидко подивитися. Що це таке Vagrant? Це ПЗ для створення віртуального середовища. Це обгортка над багатьма провайдерами віртуалізації, як віртуал бокс, ВМ січень та інше. І плюс — у нього ще є інтеграція з вищезазначеними системами конфігурації, тобто з Chef, Ansible, з Puppet.

Щоб розгорнути мені тачку, тобто я поставив собі Vagrant і мені потрібно просто зробити vagrant init — це я вказую, дистрибутив чого мені треба.



У мене в поточній директорії з'являється vagrant файл — конфігураційний файл моєї майбутньої виртуалки. І в цій же директорії я кажу: «vagrant up» і через деякий час на моєму хості піднімається віртуальна машина, де я можу робити, що хочу, потім її грохнути і ще чого-небудь, тобто роблю з нею, що хочу.

Ось быстренький приклад, про Chef solo:



У Vagrant файлі я пишу, що у мене в provision'e Chef solo, мої cookbooks розташовуються ось там-то і, будь ласка, на цю машину додай мені рецепт, який у мене називається «apache» і відповідає за встановлення apache.

Тоді, коли я кажу «vagrant up» для цієї машини, вона піднімається, і виконується цей рецепт, який встановлює apache.

Vagrant'a самого не достатньо для тестування. Я бачив в програмі RootConf'а є окремий доповідь з приводу того, як тестувати інфраструктуру. Там розповідають саме про тестових фреймворках, що дозволяють тестувати інфраструктуру. Я знаю, що існує test kitchen, який заснований на Vagrant'e, і він дозволяє писати тести, коли у нас він піднімає віртуальну машину, і йому вказуєш: прив'яжи мене систему, віртуалізацію… Потім кажеш: у мене є набір тестів, які виглядають досить просто, нам потрібно перевірити, що у нас все поставило, що демони запустилися, потрібні нам файли лежать у певному місці. Власне, ми пишемо такого роду тести, і він їх після підняття віртуальної машини, проганяє і каже «OK» або «не ДОБРЕ».

Це все найпростіші варіанти, тобто тестування інфраструктури — це теж окрема велика тема. Ми з вами трохи прочинили дверцята в цей світ, але там ще багато питань, багато технік та інше.

Що б хотілося порекомендувати, з чого почати? Інструменти великі, інформації багато, хочеться взяти спробувати. Від себе можу сказати, що такі рекомендації — якщо у нас є який-небудь маленький простий сервіс, то беріть те, що вже відомо, т. е. поставити nginx або postgres та інше. Спробувати почати з маленького, написати рецепт, playbook, виконати прості загальновідомі дії, тоді можна буде зрозуміти, чи потрібно вам це на даному етапі, або вас досі баш-скрипти влаштовують, або ручками ви робите. Зрозуміти, чи потрібно вам це. І зрозуміти, що вам зручніше.

Я тут ссилочку привів:

У кожного інструменту існують ком'юніті, бестпрактисы, репозиторії з написаними cookbooks, тобто все відоме, яке треба встановлювати, конфигурить та інше. З приводу цього вже написані всі playbooks, вироблені бестпрактисы, і ми йдемо в ці супермаркети або в Galaxy і просто беремо, що нам потрібно — як кубики — і виконуємо, формуємо, так у нас виходить готова інфраструктура.

З приводу такого важливого аспекту, як вартість, можна сказати, що ці продукти в основному безкоштовні. Сhef почав з 12-ої версії хотіти грошей, тому багато хто сидять на 11-ій версії досі, а Ansible хочуть грошей за веб-морду, Ansible tower це, по-моєму, називається. А в інших конфігураціях все це можна взяти безкоштовно і швидко застосувати.

Контакти
» Блог компанії 2ГІС

Ця доповідь — розшифровка одного з кращих виступів на навчальній конференції розробників високонавантажених систем HighLoad++ Junior.

Також деякі з цих матеріалів використовуються нами в навчальному онлайн-курс по розробці високонавантажених систем HighLoad.Guide — це ланцюжок спеціально підібраних листів, статей, матеріалів, відео. Вже зараз у нашому підручнику понад 30 унікальних матеріалів. Підключайтеся!

Ну і головна новина — ми почали підготовку весняного фестивалю "Російські інтернет-технології", в який входить вісім конференцій, включаючи HighLoad++ Junior.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.