
Подход IaC (Infrastructure as Code) се състои не само от код, който се съхранява в репозитория, но и от хора и процеси, които обграждат този код. Може ли да се преопотребят подходите от софтуерната разработка в управлението и описанието на инфраструктурата? Няма да е излишно да държите тази идея в ума си, докато четете статията.
Това е разшифровка на моя на .
Слайдове и видеа
- Dry run 2019-04-24
Инфраструктура като история на bash

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

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

На проекта за разработка на СХД, имаше подзадача : издаваме нов релиз — той трябва да бъде разпределен, за по-нататъшно тестване. Задачата е изключително проста:
- влез тук по ssh и изпълни командата.
- копирай файла там.
- поправи конфигурацията тук.
- пусни услугата там
- …
- ПЕЧЕЛЕНЕ!
За описаната логика bash е повече от достатъчен, особено в ранните етапи на проекта, когато той едва стартира. Това , но с течение на времето се появяват искания да се разшири нещо подобно, но малко различно. Първото, което идва наум: copy-paste. И така, вече имаме два много подобни скрипта, които правят почти същото. С времето броят на скриптовете нарасна и се сблъскахме с факта, че има някаква бизнес логика за разгръщане на инсталацията, която трябва да се синхронизира между различни скриптове, което е доста сложно.

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

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

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

Открити за разширение: означава, че поведението на съществото може да бъде разширено чрез създаване на нови типове същества.
- Затворени за промяна: в резултат на разширение на поведението на съществото, не трябва да се внасят промени в кода, който използва тези същества.
- Закрыты для изменения: в результате расширения поведения сущности, не должны вноситься изменения в код, который эти сущности использует.
Първоначално развивахме тестова инфраструктура на виртуални машини, но поради факта, че бизнес логиката на развиването беше отделена от реализацията, без проблем добавихме инсталация на baremetall.
Принципът на подмяната на Лисков

Принцип на подмяната на Барбара Лисков. Обектите в програмата трябва да могат да бъдат заменяни с инстанции на техните подтипове без да се променя коректността на изпълнението на програмата.
Ако погледнем по-широко, няма особеност на конкретен проект, а това може да се приложи. S.O.L.I.D., това всъщност е свързано с CFM, например, в друг проект е необходимо да развиваме опаковано Java приложение върху различни Java, сървъри за приложения, бази данни, операционни системи и т.н. На този пример ще разглеждам нататъшните принципи. S.O.L.I.D.
В нашия случай в рамките на инфраструктурния екип има споразумение, че ако сме инсталирали роля imbjava или oraclejava, то разполагаме с бинарен изпълняем файл java. Това е необходимо, тъй като надстоящите роли зависят от това поведение, те очакват наличието на java. В същото време това ни позволява да заменяме една реализация/версия на java с друга, без да променяме логиката на разгърнатото приложение.
Проблемът тук е, че в Ansible не може да се реализира такова, поради което в рамките на екипа възникват определени споразумения.
Принципът на разделение на интерфейса

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

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

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

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

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

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

С времето започнаха да се появяват конфликти по време на ревюто, тъй като ревюърите имаха свой стил, а въртенето на ревюърите ги събираше с различни стилове: 2 интервала или 4, camelCase или snake_case. Внедряването на това не стана лесно.
- Първата идея беше да се препоръча използването на linter, защото инженерите все пак са умни. Но различните редактори и операционни системи не го правят удобно.
- Това еволюира в бот, който за всеки проблемен комит пишеше в Slack и прикрепяше изхода от linter. Но в повечето случаи имаше по-важни задачи и кодът оставаше непоправен.
Green Build Master

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

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

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Инструменти за статичен анализ
Проблемът от предишната стъпка можеше да бъде уловен, когато забравихме кавичките; за това в природата съществуват много средства. , всъщност има много, и най-вероятно ще можете да намерите линтер за вашата IDE, съобразен с вашия стек.
Език
Инструмент
bash
Ruby
python
ansible
IaC Тестиране: Юнит тестове

Както установихме от предишния пример, линтерите не са всемогъщи и не могат да посочат всички проблемни места. Във връзка с тестването в разработката на софтуер можем да си спомним за юнит тестовете. Със сигурност идват на ум , , , . Но какво да правим с ansible, chef, saltstack и подобни?
В самото начало говорихме за S.O.L.I.D. и за това, че нашата инфраструктура трябва да се състои от малки кирпичи. Време е за тях.
- Инфраструктурата се раздробява на малки кирпичи, например, роли на Ansible.
- Разгръща се някаква среда, било то docker или ВМ.
- На това тестово окружение прилагаме нашата роля на Ansible.
- Проверяваме дали всичко е работило както очакваме (изпълняваме тестовете).
- Решаваме дали е ок или не.
IaC Тестиране: Инструменти за юнит тестове
Въпросът е, какво представляват тестовете за CFM? Може да пуснете скрипт, а може да използвате готови решения за това:
CFM
Инструмент
Ansible
Chef
Chef
saltstack
Пример за 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 година:

IaC Тестиране фреймове
Възниква въпросът как да съберем всичко това заедно и да го стартираме? Може да при наличие на достатъчно инженери. А можете и да вземете готови решения, само че не са много:
CFM
Инструмент
Ansible
Chef
Terraform
Пример за измененията в проектите на github за 2018-2019 година:

Molecule срещу Testkitchen

Първоначално се :
- Създайте ВМ паралелно.
- Приложете Ansible роли.
- Изпълнете inspec.
За 25-35 роли това отне 40-70 минути, което беше дълго.

Следващата стъпка беше преминаването към jenkins / docker / ansible / molecule. Идеологически всичко е същото.
- Пролинтувайте плейбуците.
- Пролинтувайте ролите.
- Стартирайте контейнера.
- Приложете Ansible роли.
- Изпълнете testinfra.
- Проверете идемпотентността.

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

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

На следващото ниво на пирамидата на тестване на инфраструктурата се появяват интеграционни тестове. Те са подобни на Unit тестовете:
- Инфраструктурата се разделя на малки елементи, напр. Ansible роли.
- Разгръща се някаква среда, било то docker или ВМ.
- Тази тестова среда се прилага множество Ansible роли.
- Проверяваме дали всичко работи както очакваме (изпълняваме тестовете).
- Решаваме дали е ок или не.
Грубо казано, не проверяваме работоспособността на отделен елемент от системата, както в unit тестовете, а проверяваме как е конфигуриран сървърът като цяло.
IaC тестване: End to End тестове.

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

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

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

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

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

Infrastructure as Code е
- Код в хранилището.
- Взаимодействие между хората.
- Тестване на инфраструктурата.
линкове
- Dry run 2019-04-24
- &
Източник: habr.com
