A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

április 8-án a konferencián Saint HighLoad++ 2019, a „DevOps and Operations” rovat részeként elhangzott a „Kubernetes bővítése és kiegészítése” című beszámoló, melynek létrehozásában a Flant cég három munkatársa vett részt. Ebben számtalan olyan helyzetről beszélünk, amelyben a Kubernetes képességeit szerettük volna bővíteni, kiegészíteni, de amelyekre nem találtunk kész és egyszerű megoldást. Megvannak a szükséges megoldásaink nyílt forráskódú projektek formájában, és ez a beszéd is ezeknek szól.

A hagyományoknak megfelelően örömmel mutatjuk be videó a riportról (50 perc, sokkal informatívabb, mint a cikk) és a fő összefoglaló szöveges formában. Megy!

Mag és kiegészítések a K8s-ban

A Kubernetes megváltoztatja az iparágat és az adminisztráció már régóta kialakult megközelítését:

  • Köszönet neki absztrakciók, már nem olyan fogalmakkal operálunk, mint a konfiguráció beállítása vagy egy parancs futtatása (Chef, Ansible...), hanem a konténerek, szolgáltatások stb. csoportosítását használjuk.
  • Pályázatokat készíthetünk anélkül, hogy az árnyalatokra gondolnánk konkrét webhely, amin elindul: csupasz fém, valamelyik szolgáltató felhője stb.
  • A K8-asokkal még soha nem volt könnyebben elérhető legjobb gyakorlók az infrastruktúra megszervezéséről: méretezési technikák, öngyógyítás, hibatűrés stb.

Azonban persze nem minden olyan zökkenőmentes: a Kubernetes is hozta a maga új kihívásait.

Kubernetes nincs egy olyan kombájn, amely minden felhasználó problémáját megoldja. A mag A Kubernetes csak a minimálisan szükséges funkciókért felelős, amelyek jelen vannak minden fürt:

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

A Kubernetes mag meghatározza a primitívek alapvető készletét a tárolók csoportosításához, a forgalom kezeléséhez és így tovább. Részletesebben beszéltünk róluk jelentés 2 évvel ezelőtt.

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

Másrészt a K8s nagyszerű lehetőségeket kínál a rendelkezésre álló funkciók bővítésére, amelyek segítenek mások bezárásában - különleges — felhasználói igények. A Kubernetes-kiegészítések a fürtrendszergazdák felelőssége, akiknek mindent telepíteniük és konfigurálniuk kell, hogy a fürt „megfelelő formába” kerüljön [sajátos problémáik megoldása érdekében]. Milyen kiegészítések ezek? Nézzünk néhány példát.

Példák a kiegészítőkre

A Kubernetes telepítése után meglepődhetünk azon, hogy az a hálózat, amely annyira szükséges a pod-ok interakciójához mind a csomóponton belül, mind a csomópontok között, nem működik önmagában. A Kubernetes kernel nem garantálja a szükséges kapcsolatokat, hanem meghatározza a hálózatot az interfész (CNI) harmadik féltől származó kiegészítők esetén. Telepítenünk kell egy ilyen kiegészítőt, amely a hálózati konfigurációért lesz felelős.

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

Közeli példa erre az adattárolási megoldások (helyi lemez, hálózati blokk eszköz, Ceph...). Kezdetben a magban voltak, de adventtel CSI a helyzet a már leírthoz hasonlóvá változik: az interfész Kubernetesben van, megvalósítása pedig harmadik féltől származó modulokban.

További példák:

  • Bemenetel-vezérlők (lásd a véleményüket itt friss cikkünkben).
  • cert-menedzser:

    A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

  • Üzemeltetők a kiegészítők egész osztálya (amely magában foglalja az említett cert-managert is), primitív(eke)t és vezérlő(ke)t határoznak meg. Munkájuk logikájának csak a fantáziánk szab határt, és lehetővé teszi számunkra, hogy a kész infrastruktúra-összetevőket (például egy DBMS-t) primitívekké alakítsuk, amelyekkel sokkal könnyebb dolgozni (mint egy konténerkészlettel és azok beállításaival). Rengeteg operátort írtak – még ha sok közülük még nem is áll készen a gyártásra, ez csak idő kérdése:

    A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

  • Metrikák - egy másik illusztráció arról, hogy a Kubernetes hogyan választotta el az interfészt (Metrics API) a megvalósítástól (harmadik féltől származó kiegészítők, például Prometheus adapter, Datadog fürtügynök...).
  • mert monitoring és statisztika, ahol a gyakorlatban nem csak Prométheusz és Grafana, hanem kube-state-metrics, node-exporter stb.

És ez nem a kiegészítések teljes listája... Például az általunk jelenleg telepített Flant cégnél 29 kiegészítő (melyek összesen 249 Kubernetes objektumot hoznak létre). Egyszerűen fogalmazva, nem láthatjuk egy klaszter életét kiegészítések nélkül.

automatizálás

Az operátorokat úgy tervezték, hogy automatizálják a mindennapi rutinműveleteket. Íme a valós életből származó példák, amelyekre az operátor írása kiváló megoldás lenne:

  1. Létezik egy privát (azaz bejelentkezést igénylő) rendszerleíró adatbázis képekkel az alkalmazáshoz. Feltételezhető, hogy minden egyes podhoz egy speciális titok van hozzárendelve, amely lehetővé teszi a hitelesítést a rendszerleíró adatbázisban. A mi feladatunk annak biztosítása, hogy ez a titok megtalálható legyen a névtérben, hogy a podok letölthessenek képeket. Nagyon sok alkalmazás lehet (mindegyiknek szüksége van egy titokra), és célszerű magukat a titkokat rendszeresen frissíteni, így a titkok kézzel történő lerakásának lehetősége megszűnik. Itt jön a segítség az operátor: létrehozunk egy vezérlőt, amely megvárja a névtér megjelenését, és ezen esemény alapján egy titkot ad a névtérhez.
  2. Alapértelmezés szerint tilos a podokból az internethez való hozzáférés. De néha szükség lehet rá: logikus, hogy a hozzáférés-engedélyezési mechanizmus egyszerűen működjön, anélkül, hogy speciális készségeket igényelne, például egy bizonyos címke jelenléte miatt a névtérben. Hogyan tud nekünk itt segíteni az operátor? Létrejön egy vezérlő, amely megvárja, hogy a címke megjelenjen a névtérben, és hozzáadja a megfelelő házirendet az internet-hozzáféréshez.
  3. Hasonló helyzet: tegyük fel, hogy hozzá kell adnunk egy bizonyos megfertőz, ha hasonló címkével rendelkezik (valamilyen előtaggal). Az operátorral végzett műveletek nyilvánvalóak...

Bármely klaszterben rutinfeladatokat kell megoldani, ill helyesen ezt operátorok segítségével lehet megtenni.

Az összes leírt történetet összegezve arra a következtetésre jutottunk, hogy a kényelmes kubernetesi munkához szüksége van: A) bővítmények telepítése, b) operátorokat fejleszteni (hétköznapi admin feladatok megoldására).

Hogyan írjunk nyilatkozatot a Kubernetes számára?

Általában a séma egyszerű:

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

...de aztán kiderül, hogy:

  • A Kubernetes API egy meglehetősen nem triviális dolog, amelynek elsajátítása sok időt vesz igénybe;
  • a programozás sem való mindenkinek (a Go nyelvet választották preferált nyelvnek, mert van rá egy speciális keret - Operator SDK);
  • Hasonló a helyzet magával a kerettel is.

Az alsó sor: vezérlőt írni (operátor) kell jelentős erőforrásokat költenek el anyagok tanulmányozására. Ez indokolt lenne a „nagy” operátorok esetében – mondjuk a MySQL DBMS esetében. De ha emlékszünk a fent leírt példákra (titkok feltárása, pod-ok elérése az internetre...), amelyeket szintén helyesen szeretnénk megtenni, akkor megértjük, hogy a ráfordított erőfeszítés meghaladja a most szükséges eredményt:

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

Általában egy dilemma adódik: költsön sok erőforrást, és találja meg a megfelelő eszközt a nyilatkozatok írásához, vagy tegye ezt a régi módon (de gyorsan). Ennek megoldására – hogy kompromisszumot találjunk e szélsőségek között – létrehoztuk saját projektünket: shell-operátor (lásd még az övét legutóbbi bejelentés a hub-on).

Shell-kezelő

Hogyan működik? A fürtnek van egy podja, amely egy Go binárist tartalmaz egy shell-operátorral. Mellette egy sor horgok (további részletek róluk – lásd lent). A shell-operátor maga is előfizet bizonyos fejlesztések a Kubernetes API-ban, amelynek előfordulásakor elindítja a megfelelő horgokat.

Honnan tudja a shell-operátor, hogy melyik horgot melyik eseményekre hívja? Ezt az információt maguk a horgok továbbítják a shell-operátorhoz, és ezt nagyon egyszerűen teszik.

A hook egy Bash-szkript vagy bármely más végrehajtható fájl, amely egyetlen argumentumot fogad el --config és JSON-nal válaszol. Ez utóbbi határozza meg, hogy mely objektumok érdeklik őt, és mely eseményekre (ezek esetében) kell reagálni:

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

Egyik példánk shell-operátorán való megvalósítását fogom illusztrálni - titkok lebontása egy privát nyilvántartáshoz alkalmazásképekkel való hozzáféréshez. Két szakaszból áll.

Gyakorlat: 1. Írj egy horgot

Először is, a horogban fogjuk feldolgozni --config, jelezve, hogy érdeklődünk a névterek iránt, és konkrétan a létrehozásuk pillanata:

[[ $1 == "--config" ]] ; then
  cat << EOF
{
  "onKubernetesEvent": [
    {
      "kind": "namespace",
      "event": ["add"]
    }
  ]
}
EOF
…

Hogy nézne ki a logika? Szintén nagyon egyszerű:

…
else
  createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
  kubectl create -n ${createdNamespace} -f - << EOF
Kind: Secret
...
EOF
fi

Az első lépés annak megállapítása, hogy melyik névteret hozták létre, a második pedig annak létrehozása a használatával kubectl titok ehhez a névtérhez.

Gyakorlat: 2. A kép összeállítása

Csak át kell adni a létrehozott horgot a shell-operátornak - hogyan kell ezt megtenni? Maga a shell-operátor Docker-képként érkezik, így a feladatunk az, hogy a hook-ot hozzáadjuk egy speciális könyvtárhoz ebben a képben:

FROM flant/shell-operator:v1.0.0-beta.1
ADD my-handler.sh /hooks

Már csak össze kell szerelni és tolni:

$ docker build -t registry.example.com/my-operator:v1 .
$ docker push registry.example.com/my-operator:v1

Az utolsó simítás a kép telepítése a fürtbe. Ehhez írjunk bevetés:

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              # 2

Két pontra kell figyelni:

  1. az újonnan létrehozott kép jelzése;
  2. Ez egy olyan rendszerösszetevő, amelynek (legalább) jogokra van szüksége a Kubernetes eseményeire való feliratkozáshoz és a titkok névterekhez való hozzárendeléséhez, ezért létrehozunk egy ServiceAccount-ot (és egy szabálykészletet) a hook számára.

Eredmény – megoldottuk a problémánkat rokonai a Kubernetes számára oly módon, hogy operátort hozzon létre a titkok lebontásához.

Egyéb shell-operátor jellemzők

A kiválasztott típusú objektumok korlátozásához, amelyekkel a horog működni fog, szűrhetők, kiválasztva bizonyos címkék szerint (vagy használatával matchExpressions):

"onKubernetesEvent": [
  {
    "selector": {
      "matchLabels": {
        "foo": "bar",
       },
       "matchExpressions": [
         {
           "key": "allow",
           "operation": "In",
           "values": ["wan", "warehouse"],
         },
       ],
     }
     …
  }
]

Biztosítani deduplikációs mechanizmus, amely - jq szűrő segítségével - lehetővé teszi a nagy JSON objektumok kisméretűvé alakítását, ahol csak azok a paraméterek maradnak meg, amelyek változását figyelni akarjuk.

Amikor egy horgot hívnak, a shell-operátor átadja azt objektum adatok, amely bármilyen igényre használható.

A hook-ot kiváltó események nem korlátozódnak a Kubernetes-eseményekre: a shell-operátor támogatást nyújt hívó horgokat az idő (hasonlóan a crontabhoz a hagyományos ütemezőben), valamint egy különleges esemény Indításkor. Mindezek az események kombinálhatók és ugyanahhoz a horoghoz rendelhetők.

És a shell-operátor további két funkciója:

  1. Működik aszinkron módon. Mivel egy Kubernetes-esemény (például egy objektum létrehozása) érkezett, más események (például ugyanaz az objektum törlése) történhettek a fürtben, és ezt a hooknak figyelembe kell venniük. Ha a horgot hibásan hajtották végre, akkor alapértelmezés szerint az lesz visszahívás a sikeres befejezésig (ez a viselkedés megváltoztatható).
  2. Exportál mérőszámok a Prometheus esetében, amellyel megértheti, hogy a shell-operátor működik-e, megtudhatja az egyes hook hibák számát és az aktuális sor méretét.

Összefoglalva a jelentés ezen részét:

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

Kiegészítők telepítése

A Kubernetes-szel való kényelmes munka érdekében a kiegészítők telepítésének szükségessége is szóba került. Mesélek róla, a cégünk útjáról a mostanihoz vezető út példáján.

A Kubernetes-szel több klaszterrel kezdtünk dolgozni, amihez az egyetlen kiegészítés az Ingress volt. Minden klaszterben másként kellett telepíteni, és több YAML konfigurációt készítettünk különböző környezetekhez: csupasz fém, AWS...

Minél több volt a fürt, annál több volt a konfiguráció. Ezen túlmenően ezeket a konfigurációkat javítottuk, aminek eredményeként meglehetősen heterogének lettek:

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

Hogy mindent rendbe tegyünk, egy szkripttel kezdtük (install-ingress.sh), amely érvként vette a fürt típusát, amelyre telepíteni fogjuk, létrehozta a szükséges YAML-konfigurációt, és közzétette a Kubernetesben.

Röviden a további utunk és a hozzá kapcsolódó érvelésünk a következő volt:

  • a YAML konfigurációkkal való munkához sablonmotorra van szükség (az első szakaszban ez egyszerű sed);
  • a fürtök számának növekedésével megjött az igény az automatikus frissítésre (a legkorábbi megoldás az volt, hogy a szkriptet Git-be tettem, cron segítségével frissítettem és futtattam);
  • hasonló szkript kellett a Prometheushoz (install-prometheus.sh), azonban figyelemre méltó, hogy sokkal több bemeneti adatot igényel, valamint ezek tárolását (jó értelemben - központosítva és fürtben), illetve egyes adatok (jelszavak) automatikusan generálhatók:

    A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

  • folyamatosan nőtt a veszélye annak, hogy valami rosszat tesznek közzé egyre több fürt számára, így rájöttünk, hogy a telepítők (azaz két forgatókönyv: az Ingresshez és a Prometheushoz) szakaszolásra volt szükség (több ág a Gitben, több cron a frissítéshez a megfelelő: stabil vagy tesztfürtökben);
  • с kubectl apply nehézkessé vált vele dolgozni, mert nem deklaratív, és csak objektumokat tud létrehozni, de nem hozhat döntést az állapotukról/törli őket;
  • Hiányzott néhány olyan funkció, amelyet akkor még egyáltalán nem implementáltunk:
    • a fürtfrissítések eredményének teljes körű ellenőrzése,
    • egyes paraméterek automatikus meghatározása (bemenet a telepítési szkriptekhez) a fürtből nyerhető adatok alapján (felfedezés),
    • annak logikai fejlődése folyamatos felfedezés formájában.

Mindezt a felhalmozott tapasztalatot másik projektünk keretében valósítottuk meg - addon-operátor.

Addon-operátor

A már említett shell-operatorra épül. Az egész rendszer így néz ki:

A következőkkel egészül ki a héj-kezelő horgok:

  • értékek tárolása,
  • Helm diagram,
  • összetevője annak figyeli az értéktárat és - bármilyen változás esetén - megkéri Helmet, hogy dobja újra a diagramot.

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

Így a Kubernetesben egy eseményre reagálhatunk, hook-ot indíthatunk, és ebből a hook-ból tudunk változtatásokat végrehajtani a tárhelyen, ami után újra letöltődik a diagram. Az így kapott diagramban a horgok halmazát és a diagramot egyetlen komponensre választjuk, amelyet nevezünk modul:

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

Sok modul lehet, és ezekhez hozzáadunk globális hookokat, globális értéktárat és egy komponenst, amely ezt a globális tárolót figyeli.

Most, amikor valami történik a Kubernetesben, reagálhatunk rá egy globális horog segítségével, és megváltoztathatunk valamit a globális áruházban. Ezt a változást a rendszer észreveszi, és a fürt összes modulját bevezeti:

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

Ez a séma megfelel a bővítmények telepítésére vonatkozó összes fenti követelménynek:

  • Helm felelős a sablonozásért és a deklarativitásért.
  • Az automatikus frissítés problémáját egy globális hook segítségével oldották meg, amely ütemezetten megy a rendszerleíró adatbázisba, és ha új rendszerképet lát ott, akkor azt kigörgeti (azaz „magát”).
  • A beállítások tárolása a fürtben a segítségével valósul meg ConfigMap, amely a tárolók elsődleges adatait tartalmazza (indításkor ezek betöltődnek a tárolókba).
  • A jelszó generálással, felderítéssel és folyamatos felderítéssel kapcsolatos problémákat hook segítségével oldották meg.
  • A szakaszolás a címkéknek köszönhetően érhető el, amelyeket a Docker már a dobozból támogat.
  • Az eredményt olyan mérőszámok segítségével figyeljük, amelyek alapján megérthetjük az állapotot.

Ez az egész rendszer egyetlen bináris formában van megvalósítva a Go-ban, amelyet addon-operatornak neveznek. Ez egyszerűbbé teszi a diagramot:

A Kubernetes bővítése és kiegészítése (áttekintés és videóriport)

A diagram fő összetevője egy modulkészlet (lent szürkével kiemelve). Most már kis erőfeszítéssel megírhatunk egy modult a szükséges kiegészítőhöz, és biztosak lehetünk benne, hogy az minden fürtbe telepítve lesz, frissül, és reagál a fürtben szükséges eseményekre.

"lapos" felhasználások addon-operátor 70+ Kubernetes-klaszteren. Jelenlegi állapot - alfa verzió. Most készítjük elő a dokumentációt a béta kiadásához, de egyelőre az adattárban példák állnak rendelkezésre, ami alapján elkészítheted saját addonodat.

Hol szerezhetem be az addon-operator moduljait? Könyvtárunk kiadása a következő lépés számunkra, ezt a nyáron tervezzük.

Videók és diák

Videó az előadásról (~50 perc):

A jelentés bemutatása:

PS

További beszámolók a blogunkon:

Az alábbi kiadványok is érdekelhetik:

Forrás: will.com

Hozzászólás