ansible devops кодов стил
Здравейте! Казвам се работя като инженер в департамента за автоматизация на разработкачките процеси. Всеки ден нови версии на приложения се разгръщат на стотици сървъри на компанията. В тази статия споделям опит за употребата на Ansible за тези цели.
Този наръчник предлага начин за организиране на променливите в разгръщането. Този наръчник е предназначен за тези, които вече използват роли в своите playbooks и са чели , но се сблъскват с подобни проблеми:
- Намирайки променлива в кода, не е възможно веднага да се разбере за какво отговаря тя;
- Има няколко роли и променливите трябва да бъдат свързани с едно значение, но не става;
- Имате трудности в обяснението на другите как е организирана логиката на променливите в вашите playbooks.
С тези проблеми се сблъскахме в проектите на нашата компания, което доведе до формулирането на правила за оформяне на променливите в нашите playbooks, които до известна степен разрешиха тези проблеми.

Променливи в ролите
Ролята е отделен обект на системата за разгръщане. Както всеки обект в системата, тя трябва да има интерфейс за взаимодействие с останалата част от системата. Такъв интерфейс са променливите на ролята.
Да вземем, например, ролята api, която инсталира Java приложение на сървър. Какви променливи може да има тя?

Променливите на ролята могат да се разделят на 2 вида по тип:
1. Собствености
а) независими от средата
б) зависими от средата
2. Връзки
а) слушатели
б) запитвания в системата
в) запитвания към средата
Променливи собствености — това са променливи, които определят поведението на ролята.
Променливи запитвания — това са променливи, чието значение се използва за обозначаване на външни спрямо ролята ресурси.
Променливи слушатели — това са променливи, чието значение се използва за формиране на променливи запитвания.
От друга страна, 1а, 2а, 2б — това са променливи, които не зависят от средата (железо, външни ресурси и т.н.) и могат да бъдат попълнени с подразбиращи се стойности в defaults на ролята. Обаче променливите от тип 1.б и 2.в не могат да бъдат попълнени с наистина стойности, различни от ‘example’, тъй като те ще се променят в зависимост от стенда.
Кодов стил
- Името на променливата задължително трябва да започва с името на ролята. Това ще улесни разбирането по-късно, от коя роля е променливата и за какво отговаря.
- При използване на променливи в ролите, вие задължително трябва да следвате принципа на инкапсулация и да използвате променливи, определени или в самата роля, или в ролите, от които текущата зависи.
Опитайте се да не използвате речници за променливи. Ansible не позволява удобно преопределяне на отделни стойности в речник.
Пример за лоша променлива:
myrole_user: login: admin password: adminТук login е независима променлива, а password е зависима. Но
тъй като те са обединени в речник, ще трябва да я задавате изцяло
винаги. Което е много неудобно. По-добре е така:myrole_user_login: admin myrole_user_password: admin
Променливи в деплой плейбуци
При съставяне на деплой плейбук (по-нататък плейбук), ние следваме правилото, че той трябва да бъде разположен в отделно хранилище. Както и ролите: всяка в собствено git хранилище. Това позволява осъзнаването, че ролите и плейбукът са различни независими обекти в системата за деплой, и промените в един обект не трябва да влияят на работата на друг. Това се постига чрез промени в подразбиращите се стойности на променливите.
При съставяне на плейбук, ако обобщим, съществува възможност за преопределяне на подразбиращите се стойности на променливите на ролята на две места: в променливите на плейбука и в променливите на инвентори.
mydeploy # Директория на деплоя
├── deploy.yml # Деплой плейбук
├── group_vars # Директория на променливите на плейбука
│ ├── all.yml # Файл за променливите на цялата система
│ └── myapi.yml # Файл за променливите на свойствата на група myapi
└── inventories #
└── prod # Директория на среда prod
├── prod.ini # Инвентарен файл
└── group_vars # Директория за променливите на инвентори
└── myapi #
├── vars.yml # Независими променливи на група myapi
└── vault.yml # Тайни (винаги независими) ** —
Разликата е, че променливите на плейбука се използват винаги при извикване на плейбуци, разположени на едно и също ниво. Това означава, че тези променливи са идеални за промяна на подразбиращите се стойности на променливи, независими от средата. Обратно, променливите на инвентори ще се използват само за конкретна среда, което е идеално за променливи, зависими от средата.
Важно е да се отбележи, че приоритетът на променливите няма да ви позволи да презаписвате променливите първо в променливите на плейбука, а след това отделно в едно инвентори.
Това означава, че вече на този етап трябва да се определи дали променливата е зависима от средата или не и да я поставите на подходящото място.
Например, в един проект променливата, отговорна за включването на SSL, дълго време беше зависима от средата, тъй като не можехме да включим SSL по независещи от нас причини на един от стендовете. След като решихме този проблем, тя стана независима от средата и беше преместена в променливите на плейбука.
Променливи на свойства за групи
Ще разширим нашия модел на рисунка 1, добавяйки 2 групи от сървъри с различно Java приложение, но с различни настройки.

Нека видим как ще изглежда плейбукът в този случай:
- hosts: myapi
roles:
- api
- hosts: bbauth
roles:
- auth
- hosts: ghauth
roles:
- authИмаме три групи в плейбука, затова веднага е препоръчително да създадете толкова файла за групи в group_vars на променливите на инвентори и променливите на плейбука. Един файл за група в този случай е описание на една компонента на приложението в плейбука. Когато отворите файла за група в променливите на плейбука, веднага виждате всички различия от подразбиращото се поведение на ролите, установени на групата. В променливите на инвентори: отличията в поведението на групата от стенд на стенд.
Стил на кода
- Стремете се изобщо да не използвате променливите на host_vars, тъй като те не описват системата, а само индивидуален случай, което в перспектива ще доведе до въпроси: "Защо този хост се различава от другите?", отговорът на който не винаги е лесно да се намери.
Променливи на връзки
Въпреки това, това е свързано с променливите на свойства, но как да бъде с променливите на връзки?
Тяхната разлика е, че те трябва да имат една и съща стойност в различни групи.
Поначало имаше да се използва огромна конструкция от вида:
hostvars[groups['bbauth'][0]]['auth_bind_port'], но веднага се отказахме от нея
тъй като тя има недостатъци. Първо, обемност. Второ, зависимост от определен хост в групата. Трето, необходимо е преди започването на деплоя да съберем факти от всички хостове, ако не искаме да получим грешка за неопределена променлива.
В крайна сметка беше решено да се използват променливи за свързване.
Променливи на връзки — това са променливи, които принадлежат на плейбука и са необходими за свързването на обектите в системата.
Променливите за свързване се запълват в общите променливи на системата. group_vars/all/vars и се формират чрез извеждане на всички променливи на слушателите от всяка група и добавяне в началото на променливата на името на групата, от която е изнесен слушателят.
По този начин се осигурява еднотипност и непересичане на имена.
Нека опитаме да свържем променливите от примера по-горе:

Да предположим, че имаме променливи, които зависят една от друга:
# roles/api/defaults:
# Переменная запроса
api_auth1_address: "http://example.com:80"
api_auth2_address: "http://example2.com:80"
# roles/auth/defaults:
# Переменная слушатель
auth_bind_port: "20000"Да изнесем в общите променливи group_vars/all/vars всички слушатели и да добавим в названието името на групата:
# group_vars/all/vars
bbauth_auth_bind_port: "20000"
ghauth_auth_bind_port: "30000"
# group_vars/bbauth/vars
auth_bind_port: "{{ bbauth_auth_bind_port }}"
# group_vars/ghauth/vars
auth_bind_port: "{{ ghauth_auth_bind_port }}"
# group_vars/myapi/vars
api_auth1_address: "http://{{ bbauth_auth_service_name }}:{{ bbauth_auth_bind_port }}"
api_auth2_address: "http://{{ ghauth_auth_service_name }}:{{ ghauth_auth_bind_port }}"Сега, променяйки стойността на коннектора, ще бъдем сигурни, че заявката ще се отнася там, където се намира портът.
Стил на кода
- Тъй като ролите и групите са различни обекти в системата, е необходимо те да имат различни наименования, тогава променливите за свързване точно ще показват, че принадлежат на конкретна група сървъри, а не на роля в системата.
Среднозависими файлове
В ролите могат да се използват файлове, които се различават от среда до среда.
Пример за такива файлове могат да бъдат SSL сертификатите. Да ги съхраняваме в текстов вид
в променлива не е много удобно. Но е удобно да съхраняваме пътя до тях вътре в променлива.
Например, използваме променливата api_ssl_key_file: "/path/to/file".
Тъй като очевидно е, че сертификатът на ключа ще се променя от среда на среда, то тази среднозависима променлива трябва да се намира в файла
group_vars/myapi/vars инвенторни променливи и да съдържа стойността ‘за пример’.
Най-удобно в този случай е да поставим файла с ключа в репозитория на плейбука по пътя
files/prod/certs/myapi.key, тогава стойността на променливата ще бъде:
api_ssl_key_file: "prod/certs/myapi.key"Удобството е, че хората, отговорни за разгръщането на системата на конкретен стенд, имат свое собствено място в репозитория за съхранение на файловете си. В същото време остава възможността да се посочи абсолютен път до сертификата на сървъра, в случай че сертификатите се предоставят от друга система.
Няколко стенда в една среда
Често възниква нужда от разгръщането на няколко практически идентични стенда в една среда с минимални разлики. В този случай разделяме средозависимите променливи на такива, които не се променят в рамките на тази среда и такива, които се променят. И извеждаме последните директно в самите инвентори файлове. След тази манипулация става възможно да създадем още един инвентори направо в каталога на околната среда.
Той ще преизползва инвентори group_vars и ще има възможност да презапише някои променливи директно за себе си.
Окончателната структура на директориите за проекта по разгръщане:
mydeploy # Директория на внедряване
├── deploy.yml # Плейбук за внедряване
├── files # Директория за файлове на внедряването
│ ├── prod # Директория за файлове, зависещи от средата, на stand prod
│ │ └── certs #
│ │ └── myapi.key #
│ └── test1 # Директория за файлове, зависещи от средата, на stand test1
├── group_vars # Директория за променливи на плейбука
│ ├── all.yml # Файл за променливи, свързващи цялата система
│ ├── myapi.yml # Файл с променливи за групата myapi
│ ├── bbauth.yml #
│ └── ghauth.yml #
└── inventories #
├── prod # Директория за среда prod
│ ├── group_vars # Директория за променливи на инвентори
│ │ ├── myapi #
│ │ │ ├── vars.yml # Променливи, зависещи от средата, за групата myapi
│ │ │ └── vault.yml # Тайни (винаги зависещи от средата)
│ │ ├── bbauth #
│ │ │ ├── vars.yml #
│ │ │ └── vault.yml #
│ │ └── ghauth #
│ │ ├── vars.yml #
│ │ └── vault.yml #
│ └── prod.ini # Инвентори за stand prod
└── test # Директория за среда test
├── group_vars #
│ ├── myapi #
│ │ ├── vars.yml #
│ │ └── vault.yml #
│ ├── bbauth #
│ │ ├── vars.yml #
│ │ └── vault.yml #
│ └── ghauth #
│ ├── vars.yml #
│ └── vault.yml #
├── test1.ini # Инвентори за stand test1 в среда test
└── test2.ini # Инвентори за stand test2 в среда testОбобщение
След организирането на променливите съгласно статията: всеки файл с променливи отговаря за конкретна задача. И тъй като файлът има определени задачи, става възможно да се назначи отговорно лице за правилността на всеки файл. Например, за правилността на попълването на променливите на плейбука отговорен става разработчикът на внедряването на системата, докато администратора, чиято среда е описана в инвентори, отговаря за попълването на променливите в инвентори.
Ролите станаха самостоятелна единица в разработката с собствен интерфейс, което позволи на разработчика на ролята да разработва възможности, а не да пригодява ролята към системата. Особено този проблем касаеше общите роли за всички системи в компанията.
На системните администратори вече не им се налага да разбират от кода за деплой. Всичко, което им трябва за успешен деплой, е да попълнят файловете с променливи, зависещи от средата.
Литература
Автор
Калюжни Денис Александрович
Източник: habr.com
