
Më 8 prill në konferencë , në kuadër të seksionit "DevOps dhe operimi", u shpall referati "Zgjerimi dhe plotësimi i Kubernetes", në krijimin e të cilit morën pjesë tre punonjës të kompanisë "Flant". Në të tregojmë për situatat e shumta ku dëshironim të zgjeronim dhe plotësonim mundësitë e Kubernetes, por për të cilat nuk gjetëm një zgjidhje të gatshme dhe të thjeshtë. Zgjidhjet e nevojshme i gjetëm në formën e projekteve Open Source, të cilave u kushtohet ky performancë.
Sipas traditës, jemi të lumtur të paraqesim (50 minuta, shumë më informuese se artikujt) dhe përmbledhjen kryesore në formë tekstual. Le të fillojmë!
Nuk dhe shtesat në K8s
Kubernetes po ndryshon industrinë dhe qasjet ndaj administratës, të cilat kanë qenë prej kohësh të konsoliduara:
- FalĂ« abstraksioneve, ne nuk veprojmĂ« mĂ« me konceptet si konfigurimi i skedarĂ«ve apo ekzekutimi i komandave (Chef, AnsibleâŠ), por pĂ«rdorim grumbujt e kontejnerĂ«ve, shĂ«rbimet etj.
- Ne mund të përgatisim aplikacione, pa u shqetësuar për detajet e platformës specifike, në të cilën do të ekzekutohet: bare metal, cloud e njërit prej ofruesve etj.
- Me Kubernetes është bërë më e lehtë se kurrë më parë praktikat më të mira për organizimin e infrastrukturës: teknikat e shkallëzimit, rimëkëmbjes, qëndrueshmërisë etj.
Megjithatë, natyrisht, gjithçka nuk është aq e lehtë: me Kubernetes erdhën edhe sfida të reja.
Kubernetes nuk është një kombiner që zgjidh të gjitha problemet e përdoruesve. Nuk është Kubernetes i përgjigjet vetëm një grupi funksionesh minimalisht të nevojshme, që janë të pranishme në çdo klaster:

NĂ« themel tĂ« Kubernetes pĂ«rcaktohet grupi bazĂ« i primitivĂ«ve â pĂ«r grupimin e kontejnerĂ«ve, menaxhimin e trafikut etj. MĂ« shumĂ« rreth tyre kemi folur nĂ« .
Nga ana tjetĂ«r, K8s ofron mundĂ«si tĂ« mrekullueshme pĂ«r zgjerimin e funksioneve nĂ« dispozicion, qĂ« ndihmojnĂ« nĂ« pĂ«rmbushjen e nevojave tĂ« tjera â specifike â tĂ« pĂ«rdoruesve. Shtesat nĂ« Kubernetes janĂ« pĂ«rgjegjĂ«si e administratorĂ«ve tĂ« klastereve, tĂ« cilĂ«t duhet tĂ« instalojnĂ« dhe konfiguroni gjithçka tĂ« nevojshme qĂ« klasteri i tyre "tĂ« marrĂ« formĂ«n e duhur" [pĂ«r zgjidhjen e detyrave tĂ« tyre specifike]. ĂfarĂ« janĂ« kĂ«to shtesa? Le tĂ« shqyrtojmĂ« disa shembuj.
Shembujt e shtesave
Pas instalimit tĂ« Kubernetes, mund tĂ« habitemi se rrjeti, i nevojshĂ«m pĂ«r tĂ« mundĂ«suar ndĂ«rveprimin e pod'ave brenda dhe mes nyjeve, vetĂ« nuk funksionon. Kernel-i i Kubernetes nuk garanton lidhjet e nevojshme â pĂ«rkundrazi, ai pĂ«rcakton rrjetin ndĂ«rfaqja () pĂ«r shtesa tĂ« jashtme. Ne duhet tĂ« instalojmĂ« njĂ« nga kĂ«to shtesa, e cila do tĂ« jetĂ« pĂ«rgjegjĂ«se pĂ«r konfigurimin e rrjetit.

NjĂ« shembull i ngjashĂ«m janĂ« zgjidhjet pĂ«r ruajtjen e tĂ« dhĂ«nave (disku lokal, pajisja e rrjetit tĂ« bllokut, CephâŠ). NĂ« fillim ato ishin nĂ« bĂ«rthamĂ«, por me ardhjen e situata ndryshon nĂ« njĂ« analogji me atĂ« tĂ« pĂ«rshkruar: nĂ« Kubernetes, ndĂ«rfaqja Ă«shtĂ« e definuar, ndĂ«rsa implementimi i saj Ă«shtĂ« nĂ« modulet e jashtme.
Mes shembujve të tjerë:
- Ingress-kontrollerët (përmbledhjen e tyre shihni në ).
- :

- â Ă«shtĂ« njĂ« klasĂ« e tĂ«rĂ« shtesash (midis tĂ« cilave Ă«shtĂ« edhe cert-manager), ato pĂ«rcaktojnĂ« primit(e) dhe kontrolluesit. Logjika e funksionimit tĂ« tyre Ă«shtĂ« e kufizuar vetĂ«m nga imagjinata jonĂ« dhe na lejon tĂ« kthejmĂ« komponentĂ«t e gatshĂ«m tĂ« infrastrukturĂ«s (p.sh., DBMS) nĂ« primitive, duke e bĂ«rĂ« mĂ« tĂ« lehtĂ« punĂ«n me to (se sa me njĂ« grup kontejnerĂ«sh dhe cilĂ«simeve tĂ« tyre). Ka shkruar njĂ« sasi tĂ« madhe operatorĂ«sh â megjithĂ«se shumĂ« prej tyre ende nuk janĂ« tĂ« gatshĂ«m pĂ«r prodhim, Ă«shtĂ« vetĂ«m njĂ« çështje kohe:

- Metricat â njĂ« ilustrim tjetĂ«r se si nĂ« Kubernetes ndarĂ« ndĂ«rfaqen (Metrics API) nga realizimi (shtesa tĂ« jashtme, si Prometheus adapter, agjent klasteri DatadogâŠ).
- Për monitorimit dhe statistikave, ku në praktikë janë të nevojshme jo vetëm , por edhe kube-state-metrics, node-exporter etj.
Dhe kjo nuk është lista e plotë e shtesave⊠Për shembull, në kompaninë «Flant» sot instalojmë 29 shtesa (të gjitha së bashku krijojnë 249 objekte Kubernetes). Në mënyrë të thjeshtë, ne nuk e shohim jetën e klasterit pa shtesa.
Automatizimi
Operatorët janë krijuar për automatizimin e operacioneve të zakonshme me të cilat ndeshemi çdo ditë. Këtu janë disa shembuj nga jeta, për të cilat një zgjidhje e shkëlqyer do të ishte shkrimi i një operatori:
- Ekziston një registry privat (dmth, që kërkon log in) me imazhe për aplikacionin. Supozohet se çdo pod lidh një sekret të veçantë, duke lejuar autentifikimin në registry. Detyra jonë është të sigurojmë që ky sekret të gjendet në namespace, për të mundësuar që pod-të të shkarkojnë imazhet. Ekzistojnë shumë aplikacione (secili prej të cilave ka nevojë për një sekret), dhe vetë sekretet është e dobishme t'i përditësojmë rregullisht, kështu që opsioni i shpërndarjes fizike të sekreteve përmes duarve bie në këtë rast. Këtu vjen në ndihmë operatori: ne krijojmë një kontrollues që do të presë shfaqjen e namespace-it dhe, me këtë ngjarje, do të shtojë sekretin në namespace.
- Leja qĂ«, si parazgjedhje, qasja nga podâĂ«t nĂ« internet Ă«shtĂ« e ndaluar. Por ndonjĂ«herĂ« ajo mund tĂ« jetĂ« e nevojshme: Ă«shtĂ« logjike qĂ« mekanizmi i lejes sĂ« qasjes tĂ« funksionojĂ« thjesht, pa kĂ«rkuar aftĂ«si specifike â pĂ«r shembull, nĂ« bazĂ« tĂ« pranisĂ« sĂ« njĂ« etikete tĂ« caktuar nĂ« hapĂ«sirĂ«n emĂ«rtuese. Si do tĂ« na ndihmojĂ« kĂ«tu operatori? Krijohet njĂ« kontrollues qĂ« pret shfaqjen e njĂ« etikete nĂ« hapĂ«sirĂ«n emĂ«rtuese dhe shton politikĂ«n pĂ«r qasje nĂ« internet.
- Një situatë e ngjashme: le të supozojmë se na nevojitet të shtojmë një , nëse ka një etiketë të ngjashme (me ndonjë prefiks). Veprimet me operatorin janë të qarta...
Në çdo klaster duhet të zgjidhen detyra rutinë, dhe duhet të bëhet nëpërmjet operatorëve.
Duke e përmbledhur të gjitha historitë e përshkruara, ne arritëm në përfundimin se për një punë komode në Kubernetes nevojitet: a) të instalohen shtesa, b) të zhvillohen operatorë (për zgjidhjen e detyrave të përditshme administrative).
Si të shkruani një operator për Kubernetes?
Në përgjithësi skema është e thjeshtë:

⊠por këtu zbulohet se:
- API i Kubernetes është një gjë mjaft e ndërlikuar, e cila kërkon kohë të konsiderueshme për t'u mësuar;
- programimi nuk Ă«shtĂ« pĂ«r tĂ« gjithĂ« (gjuha Go Ă«shtĂ« zgjedhur si e preferuar, sepse ka njĂ« framework tĂ« veçantĂ« â );
- situata është e ngjashme me framework-un si të tillë.
PĂ«rfundimi: pĂ«r tĂ« shkruar njĂ« kontrollues (operatori) Ă«shtĂ« e nevojshme tĂ« investosh burime tĂ« konsiderueshme pĂ«r tĂ« studiuar materien. Kjo do tĂ« ishte e arsyeshme pĂ«r "operatorĂ«t e mĂ«dhenj" â le tĂ« themi, pĂ«r DBMS MySQL. Por nĂ«se e kujtojmĂ« shembujt tuaj tĂ« pĂ«rmendur (shpĂ«rndarja e sekretĂ«ve, aksesin e pod-eve nĂ« internet...), tĂ« cilat duam gjithashtu tâi bĂ«jmĂ« siç duhet, do tĂ« kuptojmĂ« se pĂ«rpjekjet e shpenzuara do tĂ« tejkalojnĂ« rezultatin e nevojshĂ«m tani:

I gjithĂ« kjo krijon njĂ« dilemĂ«: tĂ« shpenzosh shumĂ« burime dhe tĂ« fitosh mjete tĂ« duhura pĂ«r tĂ« shkruar operatorĂ«t ose tĂ« veprosh "siç bĂ«hej mĂ« parĂ«" (por shpejt). PĂ«r ta zgjidhur kĂ«tĂ« â gjetjen e njĂ« kompromisi midis kĂ«tyre ekstremisht â ne krijuam projektin tonĂ«: (shih gjithashtu njoftimin e tij tĂ« nĂ« habr).
Shell-operator
Si funksionon ai? NĂ« klaster ka njĂ« pod, nĂ« tĂ« cilĂ«n ndodhet bineri Go me shell-operator. PranĂ« tij ruhet njĂ« grup hook-esh (mĂ« shumĂ« rreth tyre â shih mĂ« poshtĂ«). VetĂ« shell-operatori abonon nĂ« disa ngjarje nĂ« API-nĂ« Kubernetes, kur ndodhin ato ai aktivizon thirrjet pĂ«rkatĂ«se.
Si e kupton shell-operatori se cilat thirrje të bëjë në cilat ngjarje? Këtë informacion e japin vetë thirrjet shell-operatorit dhe e bëjnë këtë shumë thjeshtë.
Një thirrje është një skenar në Bash ose një skedar tjetër ekzekutues që mbështet një argument të vetëm --config dhe në përgjigje të tij jep JSON. Ky i fundit përcakton cilët objekte e interesojnë dhe për cilat ngjarje (për këto objekte) duhet të reagojnë:

Do e ilustroj realizimin nĂ« shell-operator me njĂ« nga shembujt tanĂ« â shpĂ«rndarja e sekreteve pĂ«r qasje nĂ« njĂ« registry privat me imazhe aplikacionesh. Ajo pĂ«rbĂ«het nga dy etapa.
Praktika: 1. Shkruajmë thirrjen
SĂ« pari, nĂ« thirrje do tĂ« trajtojmĂ« --config, duke treguar se na interesojnĂ« namespace-t, nĂ« veçanti â momenti i krijimit tĂ« tyre:
[[ $1 == "--config" ]] ; pastaj
cat << EOF
{
"onKubernetesEvent": [
{
"kind": "namespace",
"event": ["add"]
}
]
}
EOF
âŠSi do tĂ« duket logjika? Edhe kjo mjaft e thjeshtĂ«:
âŠ
ndryshe
createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
kubectl create -n ${createdNamespace} -f - << EOF
Lloji: Sekret
...
EOF
fi Hapi i parĂ« Ă«shtĂ« tĂ« kuptojmĂ« se cili namespace Ă«shtĂ« krijuar, dhe hapi i dytĂ« â krijojmĂ« pĂ«rmes kubectl sekretit pĂ«r kĂ«tĂ« hapĂ«sirĂ« emĂ«rtimi.
Praktika: 2. Krijimi i imazhit
Na mbetet tĂ« transferojmĂ« hook-un e krijuar te shell-operatori â si ta bĂ«jmĂ« kĂ«tĂ«? Shell-operatori ofrohet si njĂ« imazh Docker, kĂ«shtu qĂ« detyra jonĂ« Ă«shtĂ« tĂ« shtojmĂ« hook-un nĂ« njĂ« katalog tĂ« posaçëm nĂ« kĂ«tĂ« imazh:
FROM flant/shell-operator:v1.0.0-beta.1
ADD my-handler.sh /hooksTani duhet ta ndërtojmë dhe ta push-ojmë:
$ docker build -t registry.example.com/my-operator:v1 .
$ docker push registry.example.com/my-operator:v1Prekja pĂ«rfundimtare â tĂ« deplojmĂ« imazhin nĂ« klasĂ«r. PĂ«r kĂ«tĂ« do tĂ« shkruajmĂ« Deployment:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-operator
spec:
template:
spec:
containers:
- name: my-operator
image: registry.example.com/my-operator:v1 # 1
serviceAccountName: my-operator # 2Në të nevojitet të kushtohet vëmendje dy pikave:
- përcaktimi i imazhit të sapokrijuar;
- ky është një komponent sistemik, i cili (të paktën) kërkon të ketë të drejta për të regjistruar ngjarje në Kubernetes dhe për të shpërndarë sekretet sipas namespace-ve, prandaj krijojmë për hook-un një ServiceAccount (dhe një set rregullash).
Rezultati â ne zgjidhĂ«m problemin tonĂ« nĂ« mĂ«nyrĂ«n e tij pĂ«r Kubernetes, duke krijuar njĂ« operator pĂ«r shpĂ«rndarjen e sekreteve.
Mundësitë e tjera të shell-operatorit
Për të kufizuar objektet e llojit tuaj të zgjedhur, me të cilat do të punojë hook-u, ato mund të filtrohen, duke përzgjedhur sipas etiketave të caktuara (ose me anë të matchExpressions):
"onKubernetesEvent": [
{
"selector": {
"matchLabels": {
"foo": "bar",
},
"matchExpressions": [
{
"key": "allow",
"operation": "In",
"values": ["wan", "warehouse"],
},
],
}
âŠ
}
]Parashikuar mekanizmi i deduplikimit, i cili â me anĂ« tĂ« filtrit jq â lejon transformimin e JSON-eve tĂ« mĂ«dha nĂ« tĂ« vogla, ku mbeten vetĂ«m ato parametra pĂ«r ndryshimin e tĂ« cilĂ«ve dĂ«shirojmĂ« tĂ« ndjekim.
Kur thirret hook, shell-operator i kalon të dhënat për objektin, të cilat mund të përdoren për nevojat e ndryshme.
Ngjarjet gjatë të cilave thirren hook-et nuk janë të kufizuara në ngjarjet e Kubernetes: në shell-operator parashikohet mbështetje për thirrjen e hook-ve në kohë (sa njësoj si crontab në planifikuesin tradicional), si dhe ngjarje të veçanta onStartup. Të gjitha këto ngjarje mund të kombinohen dhe të caktohen për të njëjtin hook.
Dhe dy veçori të tjera të shell-operator:
- Ai punon asinhron. Nga momenti i marrjes së ngjarjes Kubernetes (p.sh., krijimi i një objekti) në klaster, mund të ndodhin edhe ngjarje të tjera (p.sh., fshirja e të njëjtit objekt), dhe kjo duhet të merret parasysh në hooks. Nëse hook-u përfundon me gabim, atëherë për default ai do të ri-thirret deri në përfundim të suksesshëm (kjo sjellje mund të ndryshohet).
- Ai eksporton metrika për Prometheus, me të cilat mund të kuptohet nëse shell-operatori funksionon, të dihet numri i gabimeve për çdo hook dhe madhësia aktuale e radhës.
Duke përmbledhur këtë pjesë të raportit:

Instalimi i shtesave
Për një punë të rehatshme me Kubernetes, u përmend gjithashtu nevoja për instalimin e shtesave. Për këtë do të flas në shembullin e rrugës së kompanisë tonë për mënyrën si e bëjmë këtë tani.
PunĂ«n me Kubernetes e filluam me disa klasterĂ«, me shtesĂ«n e vetme qĂ« ishte Ingress. NĂ« çdo klaster, ai duhej tĂ« instalohej ndryshe, dhe ne bĂ«mĂ« disa konfigurime YAML pĂ«r mjedise tĂ« ndryshme: bare metal, AWSâŠ
KlasterĂ«t po bĂ«heshin mĂ« shumĂ« â mĂ« shumĂ« po rriteshin edhe konfigurimet. PĂ«r mĂ« tepĂ«r, ne pĂ«rmirĂ«suam kĂ«to konfigurime, duke bĂ«rĂ« qĂ« ato tĂ« bĂ«heshin mjaft tĂ« ndryshme:

Për të vendosur gjithçka në rregull, ne filluam me skriptin (install-ingress.sh), i cili merrte si argument tipin e klasterit në të cilin do të shpërndaheshim, gjeneronte konfigurimin YAML të nevojshëm dhe e hapte atë në Kubernetes.
Në përmbledhje, rruga jonë e mëtejshme dhe mendimet që lidhen ishin si më poshtë:
- për të punuar me konfigurimet YAML nevoja për një modelues (në fazat e para ky ishte një sed i thjeshtë);
- me rritjen e numrit tĂ« klasterĂ«ve erdhi nevoja pĂ«r pĂ«rditĂ«sim automatik (zgjidhja mĂ« e hershme â e vendosĂ«m skriptin nĂ« Git, e pĂ«rditĂ«sojmĂ« dhe e ekzekutojmĂ« me cron);
- një skript i ngjashëm ishte i domosdoshëm për Prometheus (
install-prometheus.sh), megjithatĂ« ai Ă«shtĂ« i njohur pĂ«r faktin se kĂ«rkon shumĂ« mĂ« shumĂ« tĂ« dhĂ«na hyrĂ«se, si dhe ruajtjen e tyre (duke qenĂ« nĂ« mĂ«nyrĂ«n e duhur â tĂ« centralizuara dhe nĂ« klaster), pĂ«r mĂ« tepĂ«r disa tĂ« dhĂ«na (fjalĂ«kalimet) mund tĂ« gjeneroheshin automatikisht:
- rreziku pĂ«r tĂ« shpĂ«rndarĂ« diçka tĂ« gabuar nĂ« njĂ« numĂ«r nĂ« rritje klasterĂ«sh po rritej vazhdimisht, prandaj e kuptuam se instalueseve (dmth. dy skripteve: pĂ«r Ingress dhe Prometheus) iu nevojitet njĂ« skenĂ« (disa degĂ« nĂ« Git, disa cron pĂ«r pĂ«rditĂ«simin e tyre nĂ« pĂ«rkatĂ«sitĂ«: stabile ose testuese â nĂ« klasterĂ«);
- me
kubectl aplikoniu bë e vështirë të punosh, sepse ai nuk është deklarativ dhe di vetëm të krijojë objekte, por jo të marrë vendime për statusin e tyre / t'i fshijë ato; - na kanë munguar disa funksione që ne në atë kohë nuk i kishim realizuar fare:
- kontroll të plotë të rezultatit të përditësimit të klasterëve,
- përkufizimin automatik të disa parametrave (input për skriptet e instalimit) duke u bazuar në të dhënat që mund të merren nga klasteri (discovery),
- në zhvillimin e tij logjik në formën e zbulimit të vazhdueshëm.
E gjithĂ« kjo pĂ«rvojĂ« e akumuluar e kemi zbatuar nĂ« kuadĂ«r tĂ« njĂ« projekti tjetĂ«r tonin â .
Addon-operator
Në themel të tij është shell-operatori, i përmendur më parë. E gjithë sistemi duket si më poshtë:
Ngjiten me shell-operatorin:
- depoja e vlerave,
- Helm-chart,
- komponenti, i cili monitoron depozitat e vlerave dhe â nĂ« rast tĂ« çdo ndryshimi â kĂ«rkon nga Helm tĂ« ri-deploy çartin.

KĂ«shtu, mund tĂ« reagojmĂ« ndaj njĂ« ngjarjeje nĂ« Kubernetes, tĂ« aktivizojmĂ« njĂ« hook, dhe nga ky hook â tĂ« bĂ«jmĂ« ndryshime nĂ« depozitĂ«, pas tĂ« cilave do tĂ« ri-deploy çarti. NĂ« skemĂ«n e rezultuar kemi ndarĂ« njĂ« grup hooks dhe çart nĂ« njĂ« komponent, tĂ« cilin e quajmĂ« modul:

Mundësi të shumta modulash janë të mundshme, dhe për to ne shtojmë hooks globale, një depo globale values dhe një komponent që e monitoron këtë depo globale.
Tani, kur diçka ndodh në Kubernetes, ne mund të reagojmë përmes një hook-u global dhe të ndryshojmë diçka në depo globale. Ky ndryshim do të vërehet dhe do të sjellë përditësimin e të gjithë moduleve në klaster:

Ky skemë i përmbush të gjitha kërkesat për instalimin e shtesave që u përmendën më lart:
- Për templating dhe deklarativitetin është përgjegjës Helm.
- Problemi i auto-update është zgjidhur falë një hook-u global, i cili sipas një grafiku kontrollon registry-në dhe, nëse sheh një imazh të ri sistemi atje, e ri-instalon atë (dmth. "vetveten").
- Ruajtja e cilësimeve në klaster është realizuar me anë të ConfigMap, në të cilin janë shkruar të dhënat fillestare për depozitat (në fillim ato ngarkohen në depo).
- Problemet e gjenerimit të fjalëkalimeve, discovery dhe continuous discovery janë zgjidhur me anë të hook-ëve.
- Stage-imi është arritur falë etiketave që Docker i mbështet nga kutia.
- Kontrolli i rezultatit bëhet përmes metrikave, me të cilat mund të kuptojmë statusin.
E gjithë kjo sistem është realizuar në formën e një binar të vetëm në Go, i cili mori emrin addon-operator. Falë kësaj, struktura duket më e thjeshtë:

Komponenti kryesor në këtë strukturë është një grup modulash (të shënuar me ngjyrë gri në fund). Tani mund të shkruajmë një modul për shtesën e nevojshme me pak përpjekje dhe të jemi të sigurt se do të instalohet në çdo klaster, do të përditësohet dhe do të reagojë ndaj ngjarjeve që i nevojiten në klaster.
«Flant» përdor në 70+ klasterë Kubernetes. Statusi aktual është version alfa. Tani po përgatisim dokumentacionin për të lëshuar betën, ndërsa në depo , mbi bazën e të cilëve mund të krijoni addon-in tuaj.
Ku mund të marr modulat e vetë addon-operator? Publikimi i bibliotekës tonë është faza tjetër për ne, ne planifikojmë ta bëjmë këtë verë.
Video dhe prezentime
Video nga prezantimi (~50 minuta):

Prezantimi i referatit:
P.S.
Referate të tjera në blogun tonë:
- «»; (Dmitri Stolyarov; 8 Nëntor 2018 në HighLoad++);
- «»; (Dmitri Stolyarov; 28 Maj 2018 në RootConf);
- «»; (Dmitri Stolyarov; 7 Nëntor 2017 në HighLoad++);
- «»; (Dmitri Stolyarov; 6 qershor 2017 në RootConf).
Mund t'ju interesojnë edhe këto publikime:
- «».
Burimi: habr.com



