Какво научих, тестввайки 200 000 реда инфраструктурен код

Какво научих, тестввайки 200 000 реда инфраструктурен код

Подход IaC (Infrastructure as Code) се състои не само от код, който се съхранява в репозитория, но и от хора и процеси, които обграждат този код. Може ли да се преопотребят подходите от софтуерната разработка в управлението и описанието на инфраструктурата? Няма да е излишно да държите тази идея в ума си, докато четете статията.

Английска версия

Това е разшифровка на моя на презентацията на DevopsConf 2019-05-28.

Слайдове и видеа

Инфраструктура като история на bash

Какво научих, тестввайки 200 000 реда инфраструктурен код

Да предположим, че идвате на нов проект, а ви казват: «имаме Инфраструктура като код«. В реалността се оказва, Инфраструктура като история на bash или например Документация като история на bash. Това е напълно реална ситуация, например, подобен случай е описал Денис Лисенко в своето изказване Как да заменим цялата инфраструктура и да започнем да спим спокойно, той разказа как от историята на bash получиха стройна инфраструктура в проекта.

Със сигурно желание може да се каже, че Инфраструктура като история на bash е като код:

  1. възпроизводимост: можете да вземете историята на bash, да изпълните командите оттам, вероятно, между другото, ще получите работеща конфигурация на изхода.
  2. версиониране: знаете кой е влизал и какво е правил, пак не е факт, че това ще ви доведе до работеща конфигурация на изхода.
  3. история: история за това кой и какво е направил. само че няма да можете да я ползвате, ако загубите сървъра.

Какво да правим?

Инфраструктура като код

Какво научих, тестввайки 200 000 реда инфраструктурен код

Дори такъв странен случай като Инфраструктура като история на bash може да бъде притеглен за уши към Инфраструктура като код, но когато искаме да направим нещо по-сложно от стария добър LAMP сървър, ще стигнем до това, че този код трябва да бъде по някакъв начин модифициран, променен, доработен. После искам да разгледам паралели между Инфраструктура като код и софтуерната разработка.

D.R.Y.

Какво научих, тестввайки 200 000 реда инфраструктурен код

На проекта за разработка на СХД, имаше подзадача периодично да настройваме SDS: издаваме нов релиз — той трябва да бъде разпределен, за по-нататъшно тестване. Задачата е изключително проста:

  • влез тук по ssh и изпълни командата.
  • копирай файла там.
  • поправи конфигурацията тук.
  • пусни услугата там
  • ПЕЧЕЛЕНЕ!

За описаната логика bash е повече от достатъчен, особено в ранните етапи на проекта, когато той едва стартира. Това не е лошо, че използвате bash, но с течение на времето се появяват искания да се разшири нещо подобно, но малко различно. Първото, което идва наум: copy-paste. И така, вече имаме два много подобни скрипта, които правят почти същото. С времето броят на скриптовете нарасна и се сблъскахме с факта, че има някаква бизнес логика за разгръщане на инсталацията, която трябва да се синхронизира между различни скриптове, което е доста сложно.

Какво научих, тестввайки 200 000 реда инфраструктурен код

Оказва се, че има такова практическо правило D.R.Y. (Не повтаряйте себе си). Идеята е да се повторно използва съществуващият код. Звучи просто, но не стигнахме до това веднага. В нашия случай това беше банална идея: да отделим конфигурациите от скриптовете. Т.е. бизнес логиката за разгръщането на инсталацията е отделно, конфигурациите са отделно.

S.O.L.I.D. за CFM

Какво научих, тестввайки 200 000 реда инфраструктурен код

С течение на времето проектът нарасна и естественото продължение стана появата на Ansible. Основната причина за появата му е наличието на експертиза в екипа и че bash не е предназначен за сложна логика. Ansible също стана да съдържа сложна логика. За да не се превърне сложната логика в хаос, в разработката на софтуер съществуват принципи за организация на кода S.O.L.I.D. Например, Григорий Петров в доклада си „Защо на IT специалиста му е нужен личен бранд“ повдигна въпроса, че човекът е устроен така, че му е по-лесно да оперира с някакви социални сущности, в разработката на софтуер това са обекти. Ако обединим тези две идеи и продължим да ги развиваме, можем да забележим, че в описанието на инфраструктурата също може да се използва S.O.L.I.D. за да бъде по-лесно в бъдеще да се поддържа и модифицира тази логика.

Принципът на единствената отговорност

Какво научих, тестввайки 200 000 реда инфраструктурен код

Всеки клас изпълнява само една задача.

Не трябва да смесвате кода и да правите монолитни божествени паста чудовища. Инфраструктурата трябва да се състои от прости тухли. Оказва се, че ако раздробите Ansible playbook на малки парчета, прочетете Ansible роли, те са по-лесни за поддръжка.

Принципът на откритост/затвореност.

Какво научих, тестввайки 200 000 реда инфраструктурен код

Открити за разширение: означава, че поведението на съществото може да бъде разширено чрез създаване на нови типове същества.

  • Затворени за промяна: в резултат на разширение на поведението на съществото, не трябва да се внасят промени в кода, който използва тези същества.
  • Закрыты для изменения: в результате расширения поведения сущности, не должны вноситься изменения в код, который эти сущности использует.

Първоначално развивахме тестова инфраструктура на виртуални машини, но поради факта, че бизнес логиката на развиването беше отделена от реализацията, без проблем добавихме инсталация на baremetall.

Принципът на подмяната на Лисков

Какво научих, тестввайки 200 000 реда инфраструктурен код

Принцип на подмяната на Барбара Лисков. Обектите в програмата трябва да могат да бъдат заменяни с инстанции на техните подтипове без да се променя коректността на изпълнението на програмата.

Ако погледнем по-широко, няма особеност на конкретен проект, а това може да се приложи. S.O.L.I.D., това всъщност е свързано с CFM, например, в друг проект е необходимо да развиваме опаковано Java приложение върху различни Java, сървъри за приложения, бази данни, операционни системи и т.н. На този пример ще разглеждам нататъшните принципи. S.O.L.I.D.

В нашия случай в рамките на инфраструктурния екип има споразумение, че ако сме инсталирали роля imbjava или oraclejava, то разполагаме с бинарен изпълняем файл java. Това е необходимо, тъй като надстоящите роли зависят от това поведение, те очакват наличието на java. В същото време това ни позволява да заменяме една реализация/версия на java с друга, без да променяме логиката на разгърнатото приложение.

Проблемът тук е, че в Ansible не може да се реализира такова, поради което в рамките на екипа възникват определени споразумения.

Принципът на разделение на интерфейса

Какво научих, тестввайки 200 000 реда инфраструктурен код

Принцип на разделение на интерфейса. 'Много интерфейси, специално проектирани за клиенти, са по-добри, отколкото един интерфейс с общо предназначение.'

Първоначално пробвахме да съберем всяка възможност за разгърнато приложение в един Ansible playbook, но това беше трудно за поддържане. Вместо това подходът, при който имаме специфициран интерфейс навън (клиентът очаква 443 порт), позволява да композираме инфраструктурата от отделни блокчета за конкретната реализация.

Принципът на инверсия на зависимостите

Какво научих, тестввайки 200 000 реда инфраструктурен код

Принцип на инверсция на зависимостите. Модулите на горните нива не трябва да зависят от модулите на долните нива. И двата типа модули трябва да зависят от абстракции. Абстракциите не трябва да зависят от детайлите. Детайлите трябва да зависят от абстракциите.

Тук примерът ще бъде основан на антипатерн.

  1. При един от клиентите имаше частно облако.
  2. В рамките на облака поръчвахме виртуални машини.
  3. Но поради особеностите на облака, разгърнатото приложение беше зависимо от хипервизора, на който попадна ВМ.

Т.е. високото ниво на логика за разгръщане на приложението с зависимостите преминава на по-ниските нива на хипервизора, което означава проблеми при повторното използване на тази логика. Не е нужно така.

Взаимодействие

Какво научих, тестввайки 200 000 реда инфраструктурен код

Инфраструктурата като код не е само за код, а и за отношенията между кода и хората, за взаимодействията между разработчиците на инфраструктура.

Bus factor

Какво научих, тестввайки 200 000 реда инфраструктурен код

Да предположим, че на проекта имате Васил. Васил знае всичко за вашата инфраструктура. Какво ще стане, ако изведнъж Васил изчезне? Това е абсолютно реална ситуация, тъй като той може да бъде удрян от автобус. Понякога това се случва. Ако такова нещо се случи и знанието за кода, неговата структура, как работи, тайните имена и пароли не са разпределени в екипа, могат да възникнат редица неприятни ситуации. За да минимизирате тези рискове и да разпределите знанието в рамките на екипа, можете да използвате различни подходи.

Парно DevOps

Какво научих, тестввайки 200 000 реда инфраструктурен код

Това не е като в шега, в която администраторите пият бира, сменят пароли, а аналогът на парното програмиране е, че двама инженери седят на един компютър, една клавиатура и започват заедно да настройват вашата инфраструктура: настройват сървър, пишат роля за Ansible и т.н. Звучи красиво, но при нас не сработи. Въпреки това определени случаи на тази практика работиха. Появи се нов служител, неговият наставник заедно с него взимат реална задача, работят — предават знание.

Друг случай е инцидентният разговор. По време на проблем се събира група дежурни и заинтересовани, определя се един водещ, който споделя своя екран и озвучава мисленето си. Другите участници следват мисълта на водещия, наблюдават трикове от конзолата, проверяват дали не е пропуснал ред в логовете, научават нещо ново за системата. Този подход по-скоро работеше, отколкото не.

Преглед на кода

Какво научих, тестввайки 200 000 реда инфраструктурен код

Субективно, разпространението на знания за инфраструктурата и как тя е устроена беше по-ефективно чрез преглед на кода:

  • Инфраструктурата е описана в код в репозитория.
  • Промените се извършват в отделен клон.
  • При искането за обединение можете да видите делтата на промените в инфраструктурата.

Интересното тук беше, че рецензентите бяха избирани на случаен принцип по график, т.е. с известна вероятност вие ще се занимавате с нова част от инфраструктурата.

Стил на кода

Какво научих, тестввайки 200 000 реда инфраструктурен код

С времето започнаха да се появяват конфликти по време на ревюто, тъй като ревюърите имаха свой стил, а въртенето на ревюърите ги събираше с различни стилове: 2 интервала или 4, camelCase или snake_case. Внедряването на това не стана лесно.

  • Първата идея беше да се препоръча използването на linter, защото инженерите все пак са умни. Но различните редактори и операционни системи не го правят удобно.
  • Това еволюира в бот, който за всеки проблемен комит пишеше в Slack и прикрепяше изхода от linter. Но в повечето случаи имаше по-важни задачи и кодът оставаше непоправен.

Green Build Master

Какво научих, тестввайки 200 000 реда инфраструктурен код

Времето минава, и стигнахме до заключението, че не можем да пускаме комити в мастер, които не преминават тестовете. Вуаля! Изобретихме Green Build Master, който отдавна се практикува в разработката на софтуер:

  • Разработката се извършва в отделна клонка.
  • По този клон се изпълняват тестове.
  • Ако тестовете не преминат, кодът няма да попадне в мастер.

Приемането на това решение беше болезнено, тъй като предизвика много спорове, но то беше оправдано, тъй като на ревю пристигнаха заявки за сливания без разногласия по стил и с времето броят на проблемните места започна да намалява.

IaC Testing

Какво научих, тестввайки 200 000 реда инфраструктурен код

Освен проверка на стила, може да се използват и други неща, например, да се провери дали вашата инфраструктура наистина може да бъде разгръщана. Или да се провери, че промените в инфраструктурата няма да доведат до загуба на пари. Защо би било необходимо? Въпросът е сложен и философски; по-добре е да отговорим с история, че веднъж имаше auto-scaler на PowerShell, който не проверяваше гранични условия => създаваше повече ВМ, отколкото е необходимо => клиентът похарчи повече пари, отколкото беше планувал. Не е приятно, но тази грешка можеше да бъде уловена на по-ранните етапи.

Може да се попита защо да направим сложната инфраструктура още по-сложна? Тестовете за инфраструктурата, също както и тестовете за кода, не са насочени към опростяване, а към познаване как трябва да работи вашата инфраструктура.

IaC Testing Pyramid

Какво научих, тестввайки 200 000 реда инфраструктурен код

IaC Testing: Static Analysis

Ако веднага разгръщате цялата инфраструктура и проверявате дали работи, може да се окаже, че това отнема ужасно много време и изисква много усилия. Затова основата трябва да бъде нещо бързо работещо, с много компоненти, което покрива множество примитивни места.

Bash е заядлив

Нека разгледаме един банален пример. Изберете всички файлове в текущата директория и ги копирайте на друго място. Първото, което идва на ум:

for i in * ; do 
    cp $i /some/path/$i.bak
done

А какво, ако в името на файла има интервал? Ами добре, ние сме умни, умеем да използваме кавички:

for i in * ; do cp "$i" "/some/path/$i.bak" ; done

Млади ли сме? Не! Какво ако в директорията няма нищо, т.е. глобингът не сработи.

find . -type f -exec mv -v {} dst/{}.bak ;

А сега как сме млади? Не… Забравихме, че в името на файла може да има n.

touch x
mv x  "$(printf "foonbar")"
find . -type f -print0 | xargs -0 mv -t /path/to/target-dir

Инструменти за статичен анализ

Проблемът от предишната стъпка можеше да бъде уловен, когато забравихме кавичките; за това в природата съществуват много средства. Shellcheck, всъщност има много, и най-вероятно ще можете да намерите линтер за вашата IDE, съобразен с вашия стек.

Език
Инструмент

bash
Shellcheck

Ruby
RuboCop

python
Pylint

ansible
Ansible Lint

IaC Тестиране: Юнит тестове

Какво научих, тестввайки 200 000 реда инфраструктурен код

Както установихме от предишния пример, линтерите не са всемогъщи и не могат да посочат всички проблемни места. Във връзка с тестването в разработката на софтуер можем да си спомним за юнит тестовете. Със сигурност идват на ум shunit, junit, rspec, pytest. Но какво да правим с ansible, chef, saltstack и подобни?

В самото начало говорихме за S.O.L.I.D. и за това, че нашата инфраструктура трябва да се състои от малки кирпичи. Време е за тях.

  1. Инфраструктурата се раздробява на малки кирпичи, например, роли на Ansible.
  2. Разгръща се някаква среда, било то docker или ВМ.
  3. На това тестово окружение прилагаме нашата роля на Ansible.
  4. Проверяваме дали всичко е работило както очакваме (изпълняваме тестовете).
  5. Решаваме дали е ок или не.

IaC Тестиране: Инструменти за юнит тестове

Въпросът е, какво представляват тестовете за CFM? Може да пуснете скрипт, а може да използвате готови решения за това:

CFM
Инструмент

Ansible
Testinfra

Chef
Inspec

Chef
Serverspec

saltstack
Goss

Пример за testinfra, проверяваме дали потребителите test1, test2 съществуват и са в групата sshusers:

def test_default_users(host):
    users = ['test1', 'test2' ]
    for login in users:
        assert host.user(login).exists
        assert 'sshusers' in host.user(login).groups

Какво да изберем? Въпросът е сложен и нееднозначен, ето пример за измененията в проектите на github за 2018-2019 година:

Какво научих, тестввайки 200 000 реда инфраструктурен код

IaC Тестиране фреймове

Възниква въпросът как да съберем всичко това заедно и да го стартираме? Може да вземете и направите всичко сами при наличие на достатъчно инженери. А можете и да вземете готови решения, само че не са много:

CFM
Инструмент

Ansible
Molecule

Chef
Test Kitchen

Terraform
Terratest

Пример за измененията в проектите на github за 2018-2019 година:

Какво научих, тестввайки 200 000 реда инфраструктурен код

Molecule срещу Testkitchen

Какво научих, тестввайки 200 000 реда инфраструктурен код

Първоначално се опитвахме да използваме testkitchen:

  1. Създайте ВМ паралелно.
  2. Приложете Ansible роли.
  3. Изпълнете inspec.

За 25-35 роли това отне 40-70 минути, което беше дълго.

Какво научих, тестввайки 200 000 реда инфраструктурен код

Следващата стъпка беше преминаването към jenkins / docker / ansible / molecule. Идеологически всичко е същото.

  1. Пролинтувайте плейбуците.
  2. Пролинтувайте ролите.
  3. Стартирайте контейнера.
  4. Приложете Ansible роли.
  5. Изпълнете testinfra.
  6. Проверете идемпотентността.

Какво научих, тестввайки 200 000 реда инфраструктурен код

Линтовката за 40 роли и тестовете за десетина отнеха около 15 минути.

Какво научих, тестввайки 200 000 реда инфраструктурен код

Какво да изберете зависи от многобройни фактори, като използвания стек, експертизата в екипа и т.н. Всеки сам решава как да се справи с въпроса за Unit тестването.

IaC тестване: Интеграционни тестове.

Какво научих, тестввайки 200 000 реда инфраструктурен код

На следващото ниво на пирамидата на тестване на инфраструктурата се появяват интеграционни тестове. Те са подобни на Unit тестовете:

  1. Инфраструктурата се разделя на малки елементи, напр. Ansible роли.
  2. Разгръща се някаква среда, било то docker или ВМ.
  3. Тази тестова среда се прилага множество Ansible роли.
  4. Проверяваме дали всичко работи както очакваме (изпълняваме тестовете).
  5. Решаваме дали е ок или не.

Грубо казано, не проверяваме работоспособността на отделен елемент от системата, както в unit тестовете, а проверяваме как е конфигуриран сървърът като цяло.

IaC тестване: End to End тестове.

Какво научих, тестввайки 200 000 реда инфраструктурен код

На върха на пирамидата ни посрещат End to End тестове. Т.е. не проверяваме работоспособността на отделен сървър, отделен скрипт или отделен елемент от нашата инфраструктура. Проверяваме, че множество сървъри, обединени заедно, работят така, както очакваме. За съжаление, не съм виждал готови решения, вероятно защото инфраструктурата е често уникална и е трудно да се шаблонизира и да се създаде фреймуърк за тестването ѝ. В крайна сметка всеки създава собствено решение. Търсене има, но отговори няма. Затова ще споделя какво имам, за да вдъхновя другите за здравомислие или да ме насочат, че всичко вече е изобретено.

Какво научих, тестввайки 200 000 реда инфраструктурен код

Проект с дълга история. Използва се в големи организации и вероятно всеки от вас е бил косвено свързан. Приложението поддържа множество бази данни, интеграции и т.н. Знанието за това как може да изглежда инфраструктурата е множество docker-compose файлове, а знанието за това кои тестове да се изпълняват в коя среда е jenkins.

Какво научих, тестввайки 200 000 реда инфраструктурен код

Тази схема работеше доста дълго, докато в рамките на от изследване не опитахме да я пренесем в Openshift. Контейнерите останаха същите, но средата на изпълнение се промени (привет D.R.Y. отново).

Какво научих, тестввайки 200 000 реда инфраструктурен код

Идеята на изследването тръгна по-далеч и в openshift се намери нещо като APB (Ansible Playbook Bundle), което позволява да се опакова знание в контейнер за това как да се развие инфраструктура. Т.е. съществува възпроизводима, тествана точка на знание как да се развие инфраструктура.

Какво научих, тестввайки 200 000 реда инфраструктурен код

Всичко това звучеше добре, докато не се сблъскахме с хетерогенна инфраструктура: за тестовете ни е необходим Windows. В крайна сметка знанието за това как, къде и как да се развие и тестваме, седи в jenkins.

Заключение

Какво научих, тестввайки 200 000 реда инфраструктурен код

Infrastructure as Code е

  • Код в хранилището.
  • Взаимодействие между хората.
  • Тестване на инфраструктурата.

линкове

Източник: habr.com

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster