
8. aprill konverentsil , DevOps ja haldamise sektsiooni raames toimus ettekande "Kubernetesi laiendamine ja tĂ€iendamine" esitus, mille koostamisel osalesid kolm ettevĂ”tte "Flant" töötajat. Selles rÀÀgime mitmetest olukordadest, kus soovisime Kuberneteset laiendada ja tĂ€iendada, kuid ei leidnud selleks valmis ja lihtsat lahendust. Vajalikud lahendused ilmusid meile Open Source projektide nĂ€ol, millele see ettekande ka pĂŒhendatud.
Traditsiooniliselt oleme uhked esitama (50 minutit, palju informatiivsem kui artikkel) ja peamise kokkuvÔtte tekstivormis. Alustame!
K8si tuum ja lisandused
Kubernetes muudab valdkonda ja administreerimise lÀhenemisi, mis on juba ammu kindlaks kujunenud:
- TĂ€nu tema abstraktsioonidele, opereme me enam mitte selliste mĂ”istetega nagu konfi seadistamine vĂ”i kĂ€su kĂ€ivitamine (Chef, AnsibleâŠ), vaid kasutame konteinerite rĂŒhmitamist, teenuseid jne.
- Saame rakendusi valmistada, mĂ”tlemata konkreetse platvormi, millel see kĂ€ivitub: bare metal, ĂŒhe teenusepakkuja pilv jne.
- K8si abil on muutunud kergemaks parimate praktikate kasutamine infrastruktuuri korraldamise osas: skaleerimise, enesetÀiustamise, vigade taastumise tehnikaid jne.
Kuid loomulikult ei ole kÔik nii sujuv: koos Kubernetesega tulid ka uued vÀljakutsed.
Kubernetes ei on kombain, mis lahendab kÔigi kasutajate probleemid. Tuuma Kubernetes vastutab ainult minimaalsete vajalike funktsioonide komplekti eest, mis on olemas igal klastril:

Kubernetes tuum mÀÀratleb pĂ”hikomplekti primitiive â konteinerite rĂŒhmitamiseks, liikluse haldamiseks ning nii edasi. RÀÀkisime neist lĂ€hemalt .
Teiselt poolt pakub K8s suurepĂ€raseid vĂ”imalusi olemasolevate funktsioonide laiendamiseks, et katta ka teised â spetsiifilised kasutajate vajadused. Kubernetese tĂ€ienduste eest vastutavad klastri administraatorid, kes peavad kĂ”ik vajalikud koostisosad installima ja konfigureerima, et nende klaster "omandaks vajaliku vormi" [nende spetsiifiliste ĂŒlesannete lahendamiseks]. Millised need tĂ€iendused on? Vaatame mĂ”nda nĂ€idet.
TÀienduste nÀited
Kubernetes'i seadistamisel vĂ”ime olla ĂŒllatunud, et pod-ide omavaheline suhtlemine, nii sĂ”lmede sees kui ka nende vahel, ei toimi. Kubernetes'i sĂŒda ei taga vajalikke ĂŒhendusi â selle asemel defineerib see vĂ”rgu liidese () kolmandate osapoolte pluginatele. Me peame installima ĂŒhe sellise plugina, mis vastutab vĂ”rgu seadistamise eest.

LĂ€hedane nĂ€ide â andmesalvestuslahendused (kohalik kett, vĂ”rgutöötlusseade, Ceph...). Alguses olid need sĂŒsteemi sees, kuid koos muutub olukord sarnaseks juba kirjeldatule: Kubernetes'is on liides ja selle teostamine on kolmandate osapoolte moodulites.
Teiste nÀidete seast:
- Ingress-kontrollerid (ĂŒlevaate saamiseks vt meie ).
- :

- â on terve rikka klass laiendusi (kuhu kuulub ka mainitud cert-manager), mis mÀÀratleb primitiivid ja kontrollijad. Nende töö loogika on piiratud vaid meie kujutlusvĂ”imega ning vĂ”imaldab muuta olemasolevad infrastruktuuri komponendid (nĂ€iteks andmebaasid) primitiivideks, millega on palju lihtsam töötada (kui konteinerite ja nende seadistuste kogumiga). Operaatoreid on kirjutatud tohutult palju â ja kuigi paljud neist pole veel produzentsiks valmis, on see vaid aja kĂŒsimus:

- MÔÔdikud â veel ĂŒks illustratsioon, kuidas Kubernetes eraldas liidese (Metrics API) rakendusest (kolmandate osapoolte laiendused, nagu Prometheus adapter, Datadog cluster agentâŠ)
- Kuna monitooringu ja statistika, kus praktikas on vajalikud mitte ainult , vaid ka kube-state-metrics, node-exporter jpt.
Ja see ei ole kaugeltki tĂ€ielik nimekiri laiendustest⊠NĂ€iteks installime meie ettevĂ”ttes âFlantâ iga Kubernetes-klastrile tĂ€naseks 29 laiendust (kĂ”ik loovad kokku 249 Kubernetes objekt). TeisisĂ”nu, me ei nĂ€e klastrite elu ilma laiendusteta.
Automatiseerimine
Operaatoreid on loodud rutiinsete toimingute automatiseerimiseks, millega igapÀevaselt kokku puutume. Siin on elust nÀited, mille jaoks oleks optimaalne lahendus operaatori kirjutamine:
- On olemas privaatne (s.t. sisselogimist nĂ”udev) register rakenduse piltide jaoks. Eeldatakse, et igale podâile seostatakse spetsiaalne saladus, mis vĂ”imaldab autentida ennast registris. Meie ĂŒlesanne on tagada, et see saladus asub nimedruumis, et podâid saaksid pilte allalaadida. Rakendusi (kellel on igaĂŒhel vaja saladust) vĂ”ib olla vĂ€ga palju ja saladusi on mĂ”istlik regulaarselt uuendada, nii et kĂ€sitsi saladuste paigutamine pole variant. Just siin tulebki abi operaatorist: loome kontrolleri, mis ootab nimedruumi ilmumist ja selle sĂŒndmuse puhul lisab saladuse nimedruumi.
- Oletame, et vaikimisi on podâide internetiĂŒhendus keelatud. Kuid mĂ”nikord vĂ”ib see vajalik olla: loogiline on, et juurdepÀÀsumehanism töötaks lihtsalt, ilma spetsiifiliste oskuste nĂ”udmiseta â nĂ€iteks teatud silti olemasolu pĂ”hjal namespaceâis. Kuidas saab operaator siin abiks olla? Loo kontrollija, mis ootab silti namespaceâis ja lisab vastava poliitika internetiĂŒhenduse jaoks.
- Sarnane olukord: oletame, et peame lisama sĂ”lmele teatud , kui sellel on samasugune silt (mingi eesliitega). Tegevused operaatoriga on ilmsedâŠ
Igas klastris tuleb lahendada rutiinseid ĂŒlesandeid ning Ă”igesti seda teha â operaatorite abil.
KokkuvĂ”tteks kĂ”igist kirjeldatud lugudest jĂ”udsime jĂ€reldusele, et Kuberneteses mugavalt töötamiseks on vajalik: a) paigaldada lisandmooduleid, b) arendada operaatorite (igapĂ€evaste administraatoriĂŒlesannete lahendamiseks).
Kuidas kirjutada Kubernetes'e operaatorit?
Ăldiselt on skeem lihtne:

⊠kuid selgub, et:
- Kubernetes API on piisavalt mittetriviaalne asi, mis nÔuab palju aega Ôppimiseks;
- programmeerimine ei ole ka kĂ”igile (Go keel on valitud eelistatuna, sest selle jaoks on olemas spetsiaalne raamistik â );
- raamistikuga on olukord sarnane.
KokkuvĂ”te: kontrolleri kirjutamiseks (operaatori) tuleb kulutada mĂ€rkimisvÀÀrseid ressursse Ă”pikute tundmiseks. See oleks pĂ”hjendatud "suuremate" operaatorite jaoks â nĂ€iteks MySQL andmebaasi jaoks. Kuid kui me meenutame eelnevalt kirjeldatud nĂ€iteid (saladuste jagamine, pod'ide juurdepÀÀs internetisâŠ), mida tahame samuti Ă”igesti teha, siis saame aru, et tehtud pingutused ĂŒletavad vajaliku tulemuse:

KokkuvĂ”ttes tekib dilemma: kulutada palju ressursse ja omandada Ă”ige tööriist operaatorite kirjutamiseks vĂ”i tegutseda "vana viisi" (aga kiiresti). Selle lahendamiseks â kompromissi leidmiseks nende ÀÀrmuslike lĂ€henemiste vahel â lĂ”ime oma projekti: (vt ka selle Habrast).
Shell-operator
Kuidas see töötab? Klusteris on pod, milles asub Go binaar shell-operatoriga. Selle kĂ”rval hoitakse komplekti hook'ide (lisainfot nende kohta â vt allpool). Shell-operator ise kuulub kindlatele sĂŒndmustele Kubernetes API-s kĂ€ivitavad vastavaid hĂŒbriidide vastavad sĂŒndmused.
Kuidas shell-operator mĂ”istab, milliseid hĂŒbriide milliste sĂŒndmuste korral kutsuda? Selle teabe edastavad shell-operatorile hĂŒbriidid ise, tehes seda vĂ€ga lihtsalt.
HĂŒbro on Bash-skripti vĂ”i mĂ”ne muu tĂ€idetava faili, mis toetab ĂŒhte argumenti --config ja tagastab selle peale JSON-i. Viimane mÀÀrab, millised objektid teda huvitavad ja millistele sĂŒndmustele (neid objekte silmas pidades) tuleks reageerida:

Illustreerin shell-operatori rakendust meie nĂ€itest â saladuste jaotamine privaatse registry-le rakenduse piltide juurdepÀÀsuks. See koosneb kahest etapist.
Praktika: 1. Kirjutame hĂŒbriidi
Esimese asjana töötame hĂŒbriidi sees --config, mĂ€rkides, et meid huvitavad namespace'id, ja konkreetsemalt â nende loomise hetk:
[[ $1 == "--config" ]] ; siis
cat << EOF
{
"onKubernetesEvent": [
{
"kind": "namespace",
"event": ["add"]
}
]
}
EOF
âŠKuidas see loogika vĂ€lja nĂ€eb? Samuti ĂŒsna lihtne:
âŠ
muud
createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
kubectl create -n ${createdNamespace} -f - << EOF
Kind: Secret
...
EOF
fi Esimese sammuna saame teada, milline namespace on loodud, ja teiseks â loome lĂ€bi kubectl saladuse selle nimede alale.
Praktika: 2. Loome pilti
JÀÀnud on edastada loodud kĂ€epide shell-operatorile â kuidas seda teha? Shell-operator tuleb Docker-pildina, seega meie ĂŒlesanne on lisada kĂ€epide spetsiaalsesse katalooge selles pildis:
FROM flant/shell-operator:v1.0.0-beta.1
ADD my-handler.sh /hooksJÀÀb alles see ĂŒles ehitada ja push'ida:
$ docker build -t registry.example.com/my-operator:v1 .
$ docker push registry.example.com/my-operator:v1Viimane puudutus â laadida pilt klastrisse. Selleks kirjutame 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 # 2Siin tuleb tÀhelepanu pöörata kahele punktile:
- just loodud pildi nÀitamine;
- see on sĂŒsteemikomponent, millel (vĂ€hemalt) on vaja Ă”igusi, et registreeruda Kubernetes'is sĂŒndmustele ja et jagada saladusi namespace'ide vahel, seega loome kĂ€epideme jaoks ServiceAccount'i (ja komplekti reegleid).
Tulemus â me lahendasime oma probleemi loodud Kubernetes'i viisil, luues operaatori saladuste jagamiseks.
Muud shell-operatori vÔimalused
Et piirata teie valitud tĂŒĂŒpi objekte, millega kĂ€epide töötama hakkab, saab neid filtreerida, valides etiketid valides on (vĂ”i koos matchExpressions):
"onKubernetesEvent": [
{
"selector": {
"matchLabels": {
"foo": "bar",
},
"matchExpressions": [
{
"key": "allow",
"operation": "In",
"values": ["wan", "warehouse"],
},
],
}
âŠ
}
]Kavandatud deduplikaatsiooni mehhanism, mis â jq-filtri abil â vĂ”imaldab suuri JSON objekte konverteerida vĂ€ikesteks, kus jÀÀvad alles vaid need parameetrid, mille muutust me tahame jĂ€lgida.
Hooki shell-operatori kutsumisel edastab ta andmed objekti kohta, mida saab kasutada igasugusteks vajadusteks.
SĂŒndmused, mille korral hĂŒpikuid kutsutakse, ei ole piiratud Kubernetes sĂŒndmustega: shell-operator toetab hĂŒpikute kutsumist ajas (sarnane crontabile traditsioonilises ajakava koostajas), samuti spetsiaalset sĂŒndmust onStartup. KĂ”iki neid sĂŒndmusi saab kombineerida ja mÀÀrata ĂŒhele ja samale hĂŒpikule.
Ja veel kaks omadust shell-operatori kohta:
- Ta töötab asĂŒnkroonselt. Alates Kubernetes'i sĂŒndmuse (nĂ€iteks objekti loomise) saamisest on klastris vĂ”inud toimuda ka teisi sĂŒndmusi (nĂ€iteks sama objekti kustutamine), mida tuleb hookides arvesse vĂ”tta. Kui hook lĂ”ppes vea tĂ”ttu, siis kordab sĂŒsteem seda vaikimisi. korduvkutsumist kuni see Ă”nnestub (seda kĂ€itumist saab muuta).
- See eksportib metriika Prometheus'ele, millega on vÔimalik aru saada, kas shell-operator töötab, teada saada iga hooki vigade arvu ja praeguse jÀrjekorra suuruse.
KokkuvÔttes selles osa ettekandest:

Lisandmoodulite installimine
Kubernetesega mugava töötamise jaoks mainiti ka lisandmoodulite installimise vajadust. RÀÀgin sellest meie ettevÔtte teekonna nÀitel, kuidas me seda praegu teeme.
Kubernetes'e kasutamine algas meil mitmest klastrist, kus ainsaks lisandmooduliks oli Ingress. Iga klastrisse tuli seda paigaldada erinevalt, ning tegime erinevate keskkondade jaoks mitmeid YAML-konfiguratsioone: bare metal, AWSâŠ
Klastrite arv kasvas â koos suurenes ka konfiguratsioonide arv. Lisaks parandasime neid konfiguratsioone, mistĂ”ttu need muutusid ĂŒsna mitmekesisteks:

Ettevalmistamiseks alustasime skriptist (install-ingress.sh), mis vĂ”ttis argumendiks klastrityĂŒbi, kuhu me oleme paigaldamas, genereeris vajaliku YAML-konfiguratsiooni ja edastas selle Kubernetesesse.
LĂŒhidalt öeldes nĂ€gi meie edasine tee ja seotud arutlused vĂ€lja sellised:
- YAML-konfiguratsioonide töötlemiseks on vajalik malligeneraator (esimestel etappidel oli see lihtne sed);
- klastrite arvu suurenedes tekkis vajadus automaatseks uuendamiseks (kĂ”ige varasem lahendus â panime skripti Git'i, uuendame seda cron'i abil ja kĂ€ivitame);
- sarnast skripti nÔuti ka Prometheusele (
install-prometheus.sh), kuid see on tĂ€helepanuvÀÀrne, kuna nĂ”uab palju rohkem sisendandmeid ja nende sĂ€ilitamist (ideaaljuhul â tsentraliseeritult klastris), lisaks olid mĂ”ned andmed (salasid) automaatselt genereeritavad:
- risk panna vale asi kasvavatesse klastritesse kasvas pidevalt, seega mÔistsime, et installeerijatele (st kahe skripti: Ingressi ja Prometheuse jaoks) oli vajalik st stages (mitmed harud Git'is, mitmed cron'id nende uuendamiseks vastavalt: stabiilsetes vÔi testklastrites);
- koos
kubectl applytöötamine muutus keeruliseks, kuna see ei ole deklaratiivne ja oskab vaid objekte luua, kuid ei suuda nende staatust otsustada ega neid kustutada; - puudusid mÔned funktsioonid, mida me tol ajal tÀielikult ei rakendanud:
- tĂ€ielikku kontrolli klastrite uuendamise tulemuse ĂŒle,
- automaatset teatud parameetrite mÀÀramist (sisseseadmise skriptide sisendeid) andmete pÔhjal, mida saab klastri (discovery) kaudu kÀtte saada,
- loogilist arengut pideva avastamise kujul.
Kogu see kogunenud kogemus on rakendatud meie teises projektis â .
Addon-operator
Selle pĂ”hielement on juba mainitud shell-operator. Kogu sĂŒsteem nĂ€eb vĂ€lja jĂ€rgmine:
Shell-operator'i hook'idele lisatakse:
- values hoidla,
- Helm-chart,
- komponent, mis jĂ€lgib values hoidlat ja â muudatuste korral â palub Helm'il vĂ€lja lasta chart.

Nii saame reageerida sĂŒndmusele Kubernetes'is, kĂ€ivitada hook'i ja sealt teha muudatusi hoidlas, mille jĂ€rel chart uuesti vĂ€lja antakse. Saadud skeemis eristame hulka hook'e ja chart'i ĂŒheks komponendiks, mida nimetame mooduliks:

Moduleid vÔib olla palju, ja nendele lisame globaalsete hook'ide, globaalsete vÀÀrtuste salvestusruumi ja komponendi, mis jÀlgib seda globaalset salvestusruumi.
NĂŒĂŒd, kui Kubernetes'is midagi juhtub, saame sellele reageerida globaalse hook'i abil ja muuta midagi globaalsete vÀÀrtuste salvestusruumis. See muudatus mĂ€rgatakse ja see kĂ€ivitab kĂ”igi klastris olevate moodulite uuendamise:

See skeem vastab kÔigile lisandmoodulite installimise nÔuetele, mis on eelnevalt vÀlja toodud:
- Mallide loomise ja deklaratiivsuse eest vastutab Helm.
- Automaatse vĂ€rskenduse kĂŒsimus lahendatakse globaalsete hook'ide abil, mis plaanipĂ€raselt kĂ€ivad registris ja, kui seal nĂ€hakse uut sĂŒsteemipilti, uuendavad selle (st "iseennast").
- Seadete salvestamine klastris on rakendatud lÀbi ConfigMap, kuhu on salvestatud algandmed salvestusruumide jaoks (kÀivitamisel laaditakse need salvestusruumidesse).
- Paroolide genereerimise, avastamise ja pideva avastamise probleemid on lahendatud hook'ide kaudu.
- Etapid on saavutatud tÀnu siltidele, mida Docker toetab otse vÀlja.
- Tulemuse kontroll toimub meetrikate kaudu, mille abil saame aru staatusest.
Kogu see sĂŒsteem on teostatud ĂŒhe Go binaarprogrammina, mille nimi on addon-operator. SeetĂ”ttu tundub skeem lihtsam:

Selle skeemi peamine komponent on moodulite komplekt (tumedas hallis alt vĂ€lja toodud). NĂŒĂŒd suudame vĂ€ikeste pingutustega kirjutada mooduli vajaliku lisafunktsiooni jaoks ja olla kindlad, et see installitakse igasse klastrisse, uuendatakse ja reageerib sealsetele vajalikele sĂŒndmustele.
Flant kasutab ĂŒle 70 Kubernetes-klastri. Praegune staatus on alfaversioon. Praegu valmistame ette dokumentatsiooni, et vĂ€lja anda beetaversioon, samal ajal on meie hoidlas , mille pĂ”hjal suudate luua oma addon.
Kust saada addon-operatori mooduleid? Oma teegi avaldamine on meie jaoks jÀrgmine samm, plaanime selle suvel teha.
Video ja slaidid
Esitlusvideo (~50 minutit):

Ettekande esitlus:
P.S.
Teised ettekanded meie blogis:
- «»; (Dmitri Stolyarov; 8. november 2018 HighLoad++);
- «»; (Dmitri Stolyarov; 28. mai 2018 RootConf'is);
- «»; (Dmitri Stolyarov; 7. november 2017 HighLoad++);
- «»; (Dmitri Stolyarov; 6. juuni 2017 RootConf'il).
VÔib-olla huvitavad teid ka jÀrgmised publikatsioonid:
- «».
Allikas: habr.com



