Ове године, главна европска Кубернетес конференција - КубеЦон + ЦлоудНативеЦон Еуропе 2020 - била је виртуелна. Међутим, таква промена формата нас није спречила да предамо наш дуго планирани извештај „Идемо? Басх! Упознајте Схелл-оператора“ посвећеног нашем пројекту отвореног кода .
Овај чланак, инспирисан разговором, представља приступ поједностављивању процеса креирања оператора за Кубернетес и показује како можете да направите сопствени уз минималан напор користећи схелл-оператор.

Представљамо (~23 минута на енглеском, приметно информативнији од чланка) и главни извод из њега у текстуалном облику. Иди!
У Фланту стално све оптимизујемо и аутоматизујемо. Данас ћемо причати о још једном узбудљивом концепту. Сусрет: скриптовање љуске у изворном облаку!
Међутим, почнимо са контекстом у коме се све ово дешава: Кубернетес.
Кубернетес АПИ и контролери
АПИ у Кубернетесу може бити представљен као нека врста сервера датотека са директоријумима за сваки тип објекта. Објекти (ресурси) на овом серверу су представљени ИАМЛ датотекама. Поред тога, сервер има основни АПИ који вам омогућава да урадите три ствари:
- да прими ресурс по својој врсти и називу;
- промена ресурс (у овом случају сервер чува само „исправне“ објекте - сви погрешно формирани или намењени другим директоријумима се одбацују);
- пратити за ресурс (у овом случају корисник одмах добија његову тренутну/ажурирану верзију).
Дакле, Кубернетес делује као нека врста сервера датотека (за ИАМЛ манифесте) са три основна метода (да, заправо постоје и други, али ћемо их за сада изоставити).

Проблем је у томе што сервер може да чува само информације. Да би то функционисало потребно вам је контролор - други најважнији и фундаментални концепт у свету Кубернетеса.
Постоје две главне врсте контролера. Први узима информације из Кубернетеса, обрађује их према угнежђеној логици и враћа их К8с. Други преузима информације из Кубернетеса, али, за разлику од првог типа, мења стање неких екстерних ресурса.
Хајде да детаљније погледамо процес креирања примене у Кубернетес-у:
- Контролор примене (укључен у
kube-controller-manager) прима информације о имплементацији и креира РеплицаСет. - РеплицаСет креира две реплике (два модула) на основу ових информација, али ти модули још увек нису заказани.
- Планер распоређује подове и додаје информације о чворовима њиховим ИАМЛ-овима.
- Кубелетс прави промене на спољном ресурсу (рецимо Доцкер).
Затим се цео овај низ понавља обрнутим редоследом: кубелет проверава контејнере, израчунава статус модула и шаље га назад. РеплицаСет контролер прима статус и ажурира стање скупа реплика. Иста ствар се дешава са контролором имплементације и корисник коначно добија ажурирани (тренутни) статус.

Схелл-оператор
Испоставило се да је Кубернетес заснован на заједничком раду различитих контролора (Кубернетес оператери су такође контролори). Поставља се питање, како направити свог оператера уз минималан напор? И овде у помоћ долази онај који смо развили . Омогућава администраторима система да креирају сопствене изјаве користећи познате методе.
Једноставан пример: копирање тајни
Погледајмо једноставан пример.
Рецимо да имамо Кубернетес кластер. Има именски простор default са неком Тајном mysecret. Поред тога, у кластеру постоје и други именски простори. Неки од њих имају посебну етикету. Наш циљ је да копирамо Сецрет у просторе имена са ознаком.
Задатак је компликован чињеницом да се у кластеру могу појавити нови простори имена, а неки од њих могу имати ову ознаку. С друге стране, када се ознака обрише, треба избрисати и Сецрет. Поред овога, сама тајна се такође може променити: у овом случају, нова тајна мора бити копирана у све просторе имена са ознакама. Ако се Сецрет случајно избрише у било ком именском простору, наш оператер треба да га одмах врати.
Сада када је задатак формулисан, време је да почнемо да га имплементирамо користећи схелл-оператор. Али прво вреди рећи неколико речи о самом схелл-оператору.
Како ради схелл-оператор
Као и друга радна оптерећења у Кубернетесу, схелл-оператор се покреће у сопственом под-у. У овој подлози у директоријуму /hooks извршне датотеке се чувају. То могу бити скрипте у Басх, Питхон, Руби итд. Такве извршне датотеке називамо кукицама (куке).

Схелл-оператор се претплаћује на Кубернетес догађаје и покреће ове куке као одговор на оне догађаје који су нам потребни.

Како схелл-оператер зна коју удицу да покрене и када? Поента је да свака удица има две фазе. Током покретања, схелл-оператор покреће све куке са аргументом --config Ово је фаза конфигурације. А након тога, куке се покрећу на нормалан начин - као одговор на догађаје за које су везане. У последњем случају, кука прима контекст везивања (обавезујући контекст) - подаци у ЈСОН формату, о чему ћемо детаљније говорити у наставку.
Прављење оператора у Басху
Сада смо спремни за имплементацију. Да бисмо то урадили, морамо да напишемо две функције (успут, препоручујемо библиотека , што увелико поједностављује писање кукица у Басху):
- први је потребан за фазу конфигурације - приказује контекст везивања;
- други садржи главну логику куке.
#!/bin/bash
source /shell_lib.sh
function __config__() {
cat << EOF
configVersion: v1
# BINDING CONFIGURATION
EOF
}
function __main__() {
# THE LOGIC
}
hook::run "$@"
Следећи корак је да одлучимо који су нам објекти потребни. У нашем случају, морамо да пратимо:
- тајна извора за промене;
- сви простори имена у кластеру, тако да знате који имају прикачену ознаку;
- циљне тајне како би се осигурало да су све синхронизоване са изворном тајном.
Претплатите се на тајни извор
Конфигурација везивања за то је прилично једноставна. Називом означавамо да смо заинтересовани за Сецрет mysecret у именском простору default:

function __config__() {
cat << EOF
configVersion: v1
kubernetes:
- name: src_secret
apiVersion: v1
kind: Secret
nameSelector:
matchNames:
- mysecret
namespace:
nameSelector:
matchNames: ["default"]
group: main
EOF
Као резултат тога, кука ће се покренути када се промени изворна тајна (src_secret) и примите следећи обавезујући контекст:

Као што видите, садржи име и цео објекат.
Праћење именских простора
Сада морате да се претплатите на именске просторе. Да бисмо то урадили, наводимо следећу конфигурацију везивања:
- name: namespaces
group: main
apiVersion: v1
kind: Namespace
jqFilter: |
{
namespace: .metadata.name,
hasLabel: (
.metadata.labels // {} |
contains({"secret": "yes"})
)
}
group: main
keepFullObjectsInMemory: false
Као што видите, у конфигурацији се појавило ново поље са именом јкФилтер. Као што му име говори, jqFilter филтрира све непотребне информације и креира нови ЈСОН објекат са пољима која нас занимају. Хоок са сличном конфигурацијом ће добити следећи контекст везивања:

Садржи низ filterResults за сваки именски простор у кластеру. Боолеан променљива hasLabel означава да ли је ознака придружена датом именском простору. Селектор keepFullObjectsInMemory: false указује да нема потребе да се комплетни објекти чувају у меморији.
Праћење тајни мета
Претплаћујемо се на све Тајне које имају наведену напомену managed-secret: "yes" (ово су наша мета dst_secrets):
- name: dst_secrets
apiVersion: v1
kind: Secret
labelSelector:
matchLabels:
managed-secret: "yes"
jqFilter: |
{
"namespace":
.metadata.namespace,
"resourceVersion":
.metadata.annotations.resourceVersion
}
group: main
keepFullObjectsInMemory: false
У овом случају, jqFilter филтрира све информације осим именског простора и параметра resourceVersion. Последњи параметар је прослеђен напомени приликом креирања тајне: омогућава вам да упоредите верзије тајни и да их ажурирате.
Овако конфигурисана кука ће, када се изврши, примити три горе описана контекста везивања. Они се могу сматрати неком врстом снимка (снимак) кластер.

На основу свих ових информација може се развити основни алгоритам. Итерира преко свих именских простора и:
- ако
hasLabelпитањаtrueза тренутни именски простор:- упоређује глобалну тајну са локалном:
- ако су исти, то не чини ништа;
- ако се разликују – извршава
kubectl replaceилиcreate;
- упоређује глобалну тајну са локалном:
- ако
hasLabelпитањаfalseза тренутни именски простор:- осигурава да Сецрет није у датом именском простору:
- ако је локална тајна присутна, обришите је користећи
kubectl delete; - ако локална тајна није откривена, не ради ништа.
- ако је локална тајна присутна, обришите је користећи
- осигурава да Сецрет није у датом именском простору:

можете преузети у нашој .
Тако смо успели да направимо једноставан Кубернетес контролер користећи 35 линија ИАМЛ конфигурације и отприлике исту количину Басх кода! Посао оператера је да их повеже.
Међутим, копирање тајни није једина област примене услужног програма. Ево још неколико примера који показују за шта је способан.
Пример 1: Уношење промена у ЦонфигМап
Хајде да погледамо Деплоимент који се састоји од три модула. Подови користе ЦонфигМап за чување неке конфигурације. Када су подови покренути, ЦонфигМап је био у одређеном стању (назовимо га в.1). Сходно томе, сви подови користе ову конкретну верзију ЦонфигМап-а.
Сада претпоставимо да се ЦонфигМап променио (в.2). Међутим, подови ће користити претходну верзију ЦонфигМап-а (в.1):

Како могу да их натерам да пређу на нову ЦонфигМап (в.2)? Одговор је једноставан: користите шаблон. Хајде да додамо напомену контролне суме у одељак template Конфигурације примене:

Као резултат тога, ова контролна сума ће бити регистрована у свим подовима, и биће иста као и за Деплоимент. Сада само треба да ажурирате напомену када се ЦонфигМап промени. И схелл-оператор је у овом случају од користи. Све што треба да урадите је да програмирате кука која ће се претплатити на ЦонфигМап и ажурирати контролни збир.
Ако корисник изврши промене у ЦонфигМап-у, љуска-оператер ће их приметити и поново израчунати контролни збир. Након чега ће се укључити магија Кубернетеса: оркестратор ће убити капсулу, створити нову, сачекати да постане Ready, и прелази на следећу. Као резултат тога, Деплоимент ће се синхронизовати и пребацити на нову верзију ЦонфигМап-а.

Пример 2: Рад са прилагођеним дефиницијама ресурса
Као што знате, Кубернетес вам омогућава да креирате прилагођене типове објеката. На пример, можете креирати врсту MysqlDatabase. Рецимо да овај тип има два параметра метаподатака: name и namespace.
apiVersion: example.com/v1alpha1
kind: MysqlDatabase
metadata:
name: foo
namespace: bar
Имамо Кубернетес кластер са различитим именским просторима у којима можемо да креирамо МиСКЛ базе података. У овом случају, схелл-оператор се може користити за праћење ресурса MysqlDatabase, повезујући их са МиСКЛ сервером и синхронизујући жељена и посматрана стања кластера.

Пример 3: Надгледање мреже кластера
Као што знате, коришћење пинга је најједноставнији начин за надгледање мреже. У овом примеру ћемо показати како да имплементирамо такав надзор користећи схелл-оператор.
Пре свега, мораћете да се претплатите на чворове. Оператору љуске је потребно име и ИП адреса сваког чвора. Уз њихову помоћ, он ће пинговати ове чворове.
configVersion: v1
kubernetes:
- name: nodes
apiVersion: v1
kind: Node
jqFilter: |
{
name: .metadata.name,
ip: (
.status.addresses[] |
select(.type == "InternalIP") |
.address
)
}
group: main
keepFullObjectsInMemory: false
executeHookOnEvent: []
schedule:
- name: every_minute
group: main
crontab: "* * * * *"
Параметар executeHookOnEvent: [] спречава покретање куке као одговор на било који догађај (то јест, као одговор на промену, додавање, брисање чворова). Међутим, он ће покренути (и ажурирање листе чворова) Planirano - сваког минута, како прописује терен schedule.
Сада се поставља питање, како тачно знамо о проблемима као што је губитак пакета? Хајде да погледамо код:
function __main__() {
for i in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do
node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')"
node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')"
packets_lost=0
if ! ping -c 1 "$node_ip" -t 1 ; then
packets_lost=1
fi
cat >> "$METRICS_PATH" <<END
{
"name": "node_packets_lost",
"add": $packets_lost,
"labels": {
"node": "$node_name"
}
}
END
done
}
Итерирамо кроз листу чворова, добијамо њихова имена и ИП адресе, пингујемо их и шаљемо резултате Прометеју. Схелл-оператор може да извози метрику у Прометхеус, чувајући их у датотеци која се налази у складу са путањом наведеном у променљивој окружења $METRICS_PATH.
можете направити оператера за једноставно праћење мреже у кластеру.
Механизам чекања
Овај чланак би био непотпун без описа другог важног механизма уграђеног у схелл-оператор. Замислите да извршава неку врсту куке као одговор на догађај у кластеру.
- Шта се дешава ако се у исто време нешто деси у кластеру? још једно догађај?
- Хоће ли схелл-оператор покренути још једну инстанцу куке?
- Шта ако се, рецимо, у кластеру догоди пет догађаја одједном?
- Хоће ли их схелл-оператер обрадити паралелно?
- Шта је са потрошеним ресурсима као што су меморија и ЦПУ?
На срећу, схелл-оператор има уграђени механизам чекања. Сви догађаји се налазе у реду чекања и обрађују се узастопно.
Хајде да то илуструјемо примерима. Рецимо да имамо две куке. Први догађај иде на прву удицу. Када се обрада заврши, ред се креће напред. Следећа три догађаја се преусмеравају на другу куку - уклањају се из реда и уносе у њега „у групи“. То је кука прима низ догађаја — или, тачније, низ обавезујућих контекста.
Такође и ове догађаји се могу комбиновати у једну велику. За ово је одговоран параметар group у конфигурацији везивања.

Можете креирати било који број редова/кукица и њихове различите комбинације. На пример, један ред може да ради са две куке, или обрнуто.

Све што треба да урадите је да конфигуришете поље у складу са тим queue у конфигурацији везивања. Ако име реда није наведено, кука се покреће на подразумеваном реду (default). Овај механизам чекања вам омогућава да у потпуности решите све проблеме управљања ресурсима када радите са кукицама.
Закључак
Објаснили смо шта је схелл-оператор, показали како се може користити за брзо и лако креирање Кубернетес оператора и навели неколико примера његове употребе.
Детаљне информације о схелл-оператору, као и брзи водич о томе како га користити, доступни су у одговарајућем . Не устручавајте се да нас контактирате са питањима: о њима можете разговарати у посебном (на руском) или у (на енглеском).
И ако вам се свидело, увек смо срећни да видимо нова издања/ПР/звезде на ГитХуб-у, где, иначе, можете пронаћи друге . Међу њима вреди истаћи , који је велики брат схелл-оператора. Овај услужни програм користи Хелмове графиконе за инсталирање додатака, може да испоручује ажурирања и надгледа различите параметре/вредности графикона, контролише процес инсталације графикона, а такође може да их мења као одговор на догађаје у кластеру.

Видео снимци и слајдови
Видео са наступа (~23 минута):

Презентација извештаја:
ПС
Прочитајте и на нашем блогу:
- «";
- «";
- «";
- «.
Извор: ввв.хабр.цом
