Idén med en skal-operatör är ganska enkel: prenumerera på händelser från Kubernetes-objekt, och när dessa händelser tas emot, starta ett externt program som ger det information om händelsen:
Behovet av det uppstod när det under driften av kluster började dyka upp små uppgifter som vi verkligen ville automatisera på rätt sätt. Alla dessa små uppgifter löstes med enkla bash-skript, även om det som ni vet är bättre att skriva operatorer i Golang. Uppenbarligen skulle det vara ineffektivt att investera i fullskalig utveckling av en operatör för varje sådan liten uppgift.
Operatör på 15 minuter
Låt oss titta på ett exempel på vad som kan automatiseras i ett Kubernetes-kluster och hur skal-operatören kan hjälpa till. Ett exempel skulle vara följande: replikera en hemlighet för att komma åt docker-registret.
Pods som använder bilder från ett privat register måste i sitt manifest innehålla en länk till en hemlighet med data för åtkomst till registret. Denna hemlighet måste skapas i varje namnområde innan du skapar poddar. Detta kan göras manuellt, men om vi sätter upp dynamiska miljöer kommer namnutrymmet för en applikation att bli mycket. Och om det inte heller finns 2-3 ansökningar... blir antalet hemligheter väldigt stort. Och en sak till om hemligheter: Jag skulle vilja ändra nyckeln för att komma åt registret då och då. Så småningom, manuella operationer som en lösning helt ineffektivt — vi måste automatisera skapandet och uppdateringen av hemligheter.
Enkel automatisering
Låt oss skriva ett skalskript som körs en gång var N:e sekund och kontrollerar namnutrymmen för närvaron av en hemlighet, och om det inte finns någon hemlighet skapas den. Fördelen med denna lösning är att den ser ut som ett skalskript i cron – ett klassiskt och begripligt förhållningssätt för alla. Nackdelen är att i intervallet mellan dess lanseringar kan ett nytt namnutrymme skapas och under en tid kommer det att förbli utan en hemlighet, vilket kommer att leda till fel vid lansering av pods.
Automatisering med skal-operatör
För att vårt skript ska fungera korrekt måste den klassiska cron-lanseringen ersättas med en lansering när ett namnområde läggs till: i det här fallet kan du skapa en hemlighet innan du använder den. Låt oss se hur man implementerar detta med hjälp av shell-operator.
Låt oss först titta på manuset. Skript i skal-operatortermer kallas hooks. Varje krok när den körs med en flagga --config informerar skaloperatören om sina bindningar, dvs. på vilka evenemang det ska lanseras. I vårt fall kommer vi att använda onKubernetesEvent:
#!/bin/bash
if [[ $1 == "--config" ]] ; then
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "namespace",
"event":["add"]
}
]}
EOF
fi
Det beskrivs här att vi är intresserade av att lägga till evenemang (add) objekt av typen namespace.
Nu måste du lägga till koden som kommer att köras när händelsen inträffar:
#!/bin/bash
if [[ $1 == "--config" ]] ; then
# конфигурация
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "namespace",
"event":["add"]
}
]}
EOF
else
# реакция:
# узнать, какой namespace появился
createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
# создать в нём нужный секрет
kubectl create -n ${createdNamespace} -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
...
data:
...
EOF
fi
Bra! Resultatet blev ett litet vackert manus. För att "återuppliva" den finns det två steg kvar: förbered bilden och starta den i klustret.
Förbereder en bild med en krok
Om du tittar på skriptet kan du se att kommandona används kubectl и jq. Det betyder att bilden måste ha följande saker: vår krok, en skal-operator som övervakar händelser och kör kroken, och kommandona som används av kroken (kubectl och jq). Hub.docker.com har redan en färdig bild där shell-operator, kubectl och jq är förpackade. Allt som återstår är att lägga till en enkel krok Dockerfile:
Låt oss titta på kroken igen och den här gången skriva ner vilka åtgärder och med vilka objekt den utför i klustret:
prenumererar på händelser för att skapa namnutrymme;
skapar en hemlighet i andra namnutrymmen än den där den lanseras.
Det visar sig att podden där vår bild kommer att lanseras måste ha behörighet att utföra dessa åtgärder. Detta kan göras genom att skapa ditt eget ServiceAccount. Tillståndet måste göras i form av ClusterRole och ClusterRoleBinding, eftersom vi är intresserade av föremål från hela klustret.
Den slutliga beskrivningen i YAML kommer att se ut ungefär så här:
Det är allt: skaloperatorn startar, prenumererar på händelser för att skapa namnutrymme och kör kroken när det behövs.
Sålunda ett enkelt skalskript förvandlades till en riktig operatör för Kubernetes och fungerar som en del av ett kluster. Och allt detta utan den komplexa processen att utveckla operatörer i Golang:
Det finns en annan illustration i denna fråga...
Vi kommer att avslöja dess innebörd mer i detalj i en av följande publikationer.
filtrering
Att spåra föremål är bra, men det finns ofta ett behov att reagera på ändra vissa objektegenskaper, till exempel för att ändra antalet repliker i Deployment eller för att ändra objektetiketter.
När en händelse anländer tar skaloperatören emot JSON-manifestet för objektet. Vi kan välja de egenskaper som intresserar oss i denna JSON och köra kroken endast när de ändras. Det finns ett fält för detta jqFilter, där du måste ange jq-uttrycket som ska tillämpas på JSON-manifestet.
Till exempel, för att svara på ändringar i etiketter för distributionsobjekt måste du filtrera fältet labels utanför fältet metadata. Konfigurationen blir så här:
En liten avvikelse: ja, skal-operatör stöder kör crontab-stilskript. Mer information finns i dokumentation.
För att särskilja varför kroken lanserades skapar skaloperatorn en temporär fil och skickar sökvägen till den i en variabel till kroken BINDING_CONTEXT_TYPE. Filen innehåller en JSON-beskrivning av anledningen till att haken körs. Till exempel, var tionde minut kommer kroken att köras med följande innehåll:
Innehållet i fälten kan förstås från deras namn, och mer detaljer kan läsas i dokumentation. Ett exempel på att få ett resursnamn från ett fält resourceName att använda jq har redan visats i en krok som replikerar hemligheter:
jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH
Du kan få andra fält på liknande sätt.
Vad händer nu?
I projektförvaret, i /exempelkataloger, det finns exempel på krokar som är redo att köras på ett kluster. När du skriver dina egna krokar kan du använda dem som grund.
Det finns stöd för att samla in mätvärden med hjälp av Prometheus - tillgängliga mätvärden beskrivs i avsnittet METRIK.
Som du kanske gissar är skal-operatorn skriven i Go och distribuerad under en Open Source-licens (Apache 2.0). Vi kommer att vara tacksamma för allt utvecklingsbistånd projekt på GitHub: och stjärnor, och utfärdar, och pull-förfrågningar.
Vi lyfter på hemlighetsslöjan, vi kommer också att informera dig om att skal-operatören är små del av vårt system som kan hålla tillägg installerade i Kubernetes-klustret uppdaterade och utföra olika automatiska åtgärder. Läs mer om detta system berättade bokstavligen på måndag på HighLoad++ 2019 i St. Petersburg - vi kommer snart att publicera videon och transkriptionen av denna rapport.
Vi har en plan för att öppna upp resten av detta system: addon-operatören och vår samling av krokar och moduler. Förresten, addon-operator är det redan tillgänglig på github, men dokumentationen för det är fortfarande på väg. Releasen av samlingen av moduler är planerad till sommaren.