Bu il əsas Avropa Kubernetes konfransı - KubeCon + CloudNativeCon Europe 2020 virtual idi. Lakin formatın belə dəyişməsi çoxdan planlaşdırdığımız “Get? Bash! Açıq Mənbə layihəmizə həsr olunmuş Shell-operatoru ilə tanış olun .
Söhbətdən ilhamlanan bu məqalə Kubernetes üçün operatorların yaradılması prosesini sadələşdirməyə yanaşmanı təqdim edir və bir shell-operatordan istifadə edərək minimum səylə necə özünüz edə biləcəyinizi göstərir.

Təqdim edir (İngilis dilində ~ 23 dəqiqə, məqalədən nəzərəçarpacaq dərəcədə daha informativdir) və ondan mətn şəklində əsas çıxarış. Get!
Flant-da biz daim hər şeyi optimallaşdırır və avtomatlaşdırırıq. Bu gün başqa bir maraqlı konsepsiya haqqında danışacağıq. Tanış: bulud-doğma qabıq skripti!
Ancaq gəlin bütün bunların baş verdiyi kontekstdən başlayaq: Kubernetes.
Kubernetes API və nəzarətçiləri
Kubernetes-dəki API hər bir obyekt növü üçün qovluqları olan bir növ fayl serveri kimi təqdim edilə bilər. Bu serverdəki obyektlər (resurslar) YAML faylları ilə təmsil olunur. Bundan əlavə, server üç şeyi etməyə imkan verən əsas API-yə malikdir:
- almaq növü və adı ilə resurs;
- dəyişmək resurs (bu halda server yalnız "düzgün" obyektləri saxlayır - bütün səhv formalaşmış və ya digər qovluqlar üçün nəzərdə tutulmuş obyektlər silinir);
- təqib edin resurs üçün (bu halda istifadəçi dərhal onun cari/yenilənmiş versiyasını alır).
Beləliklə, Kubernetes üç əsas metodla bir növ fayl serveri (YAML manifestləri üçün) kimi çıxış edir (bəli, əslində başqaları da var, lakin biz onları hələlik buraxacağıq).

Problem ondadır ki, server yalnız məlumatları saxlaya bilir. İşləmək üçün sizə lazımdır nəzarətçi - Kubernetes dünyasında ikinci ən vacib və əsas konsepsiya.
Nəzarətçilərin iki əsas növü var. Birincisi Kubernetes-dən məlumat alır, onu iç-içə məntiqə uyğun emal edir və K8-lərə qaytarır. İkincisi Kubernetesdən məlumat alır, lakin birinci növdən fərqli olaraq bəzi xarici resursların vəziyyətini dəyişir.
Kubernetes-də Yerləşdirmənin yaradılması prosesinə daha yaxından nəzər salaq:
- Yerləşdirmə Nəzarətçisi (daxildir
kube-controller-manager) Yerləşdirmə haqqında məlumat alır və ReplicaSet yaradır. - ReplicaSet bu məlumat əsasında iki replika (iki pod) yaradır, lakin bu podlar hələ planlaşdırılmayıb.
- Planlayıcı podları planlaşdırır və onların YAML-lərinə qovşaq məlumatı əlavə edir.
- Kubelets xarici resursda dəyişikliklər edir (deyin Docker).
Sonra bütün bu ardıcıllıq tərs qaydada təkrarlanır: kubelet konteynerləri yoxlayır, podun statusunu hesablayır və onu geri göndərir. ReplicaSet nəzarətçisi statusu alır və replika dəstinin vəziyyətini yeniləyir. Eyni şey Deployment Controller ilə baş verir və istifadəçi nəhayət yenilənmiş (cari) statusu alır.

Shell-operator
Belə çıxır ki, Kubernetes müxtəlif kontrollerlərin birgə işinə əsaslanır (Kubernetes operatorları da nəzarətçilərdir). Sual yaranır, minimal səylə öz operatorunuzu necə yaratmaq olar? Və burada inkişaf etdirdiyimiz köməyə gəlir . Bu, sistem administratorlarına tanış metodlardan istifadə edərək öz bəyanatlarını yaratmağa imkan verir.
Sadə misal: sirləri kopyalamaq
Sadə bir misala baxaq.
Tutaq ki, Kubernetes klasterimiz var. Onun ad sahəsi var default bir sirr ilə mysecret. Bundan əlavə, klasterdə başqa ad boşluqları da var. Bəzilərinin üzərinə xüsusi etiket yapışdırılır. Məqsədimiz Secreti etiketlə ad boşluqlarına köçürməkdir.
Tapşırıq ona görə çətinləşir ki, klasterdə yeni ad boşluqları görünə bilər və bəzilərində bu etiket ola bilər. Digər tərəfdən, etiket silinəndə Gizli də silinməlidir. Bundan əlavə, Sirrin özü də dəyişə bilər: bu halda, yeni Gizli etiketləri olan bütün ad boşluqlarına kopyalanmalıdır. Gizli hər hansı bir ad məkanında təsadüfən silinərsə, operatorumuz onu dərhal bərpa etməlidir.
Tapşırıq tərtib edildikdən sonra, shell-operatordan istifadə edərək onu həyata keçirməyə başlamağın vaxtı gəldi. Ancaq əvvəlcə qabıq operatorunun özü haqqında bir neçə söz söyləməyə dəyər.
Shell-operator necə işləyir
Kubernetesdəki digər iş yükləri kimi, shell-operator da öz podunda işləyir. Kataloqdakı bu podda /hooks icra edilə bilən fayllar saxlanılır. Bunlar Bash, Python, Ruby və s.-də skriptlər ola bilər. Biz belə icra edilə bilən faylları qarmaqlar adlandırırıq (qarmaqlar).

Shell-operator Kubernetes tədbirlərinə abunə olur və ehtiyac duyduğumuz hadisələrə cavab olaraq bu qarmaqları işlədir.

Qabıq operatoru hansı qarmağın və nə vaxt işə salınacağını necə bilir? Məsələ ondadır ki, hər qarmağın iki mərhələsi var. Başlanğıc zamanı shell-operator bütün qarmaqları arqumentlə işlədir --config Bu konfiqurasiya mərhələsidir. Və ondan sonra qarmaqlar normal şəkildə işə salınır - bağlandıqları hadisələrə cavab olaraq. Sonuncu halda, çəngəl bağlama kontekstini alır (məcburi kontekst) - aşağıda daha ətraflı danışacağımız JSON formatında məlumatlar.
Bash-da operator etmək
İndi biz həyata keçirməyə hazırıq. Bunun üçün iki funksiya yazmalıyıq (yeri gəlmişkən, tövsiyə edirik kitabxana , Bash-də yazı qarmaqlarını çox asanlaşdırır):
- birincisi konfiqurasiya mərhələsi üçün lazımdır - o, bağlama kontekstini göstərir;
- ikincisi qarmağın əsas məntiqini ehtiva edir.
#!/bin/bash
source /shell_lib.sh
function __config__() {
cat << EOF
configVersion: v1
# BINDING CONFIGURATION
EOF
}
function __main__() {
# THE LOGIC
}
hook::run "$@"
Növbəti addım hansı obyektlərə ehtiyacımız olduğuna qərar verməkdir. Bizim vəziyyətimizdə izləməliyik:
- dəyişikliklər üçün mənbə sirri;
- klasterdəki bütün ad boşluqları, beləliklə hansıların onlara etiket əlavə edildiyini biləsiniz;
- onların hamısının mənbə sirri ilə sinxron olmasını təmin etmək üçün hədəf sirləri.
Gizli mənbəyə abunə olun
Bunun üçün bağlama konfiqurasiyası olduqca sadədir. Adı ilə Secret ilə maraqlandığımızı bildiririk mysecret ad məkanında 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
Nəticədə, mənbə sirri dəyişdikdə çəngəl işə salınacaq (src_secret) və aşağıdakı məcburi konteksti qəbul edin:

Gördüyünüz kimi, adı və bütün obyekti ehtiva edir.
Ad boşluqlarının izlənməsi
İndi ad boşluqlarına abunə olmalısınız. Bunu etmək üçün aşağıdakı bağlama konfiqurasiyasını təyin edirik:
- name: namespaces
group: main
apiVersion: v1
kind: Namespace
jqFilter: |
{
namespace: .metadata.name,
hasLabel: (
.metadata.labels // {} |
contains({"secret": "yes"})
)
}
group: main
keepFullObjectsInMemory: false
Gördüyünüz kimi, adla konfiqurasiyada yeni bir sahə meydana çıxdı jqFilter. Adından da göründüyü kimi, jqFilter bütün lazımsız məlumatları filtrləyir və bizi maraqlandıran sahələrlə yeni JSON obyekti yaradır. Bənzər konfiqurasiyaya malik çəngəl aşağıdakı bağlama kontekstini alacaq:

O, bir sıra ehtiva edir filterResults klasterdəki hər ad sahəsi üçün. Boolean dəyişəni hasLabel etiketin verilmiş ad sahəsinə əlavə edilib-edilmədiyini göstərir. Seçici keepFullObjectsInMemory: false tam obyektləri yaddaşda saxlamağa ehtiyac olmadığını göstərir.
Hədəf sirlərini izləmək
Annotasiyası olan bütün sirlərə abunə oluruq managed-secret: "yes" (bunlar bizim hədəfimizdir 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
Bu vəziyyətdə jqFilter ad sahəsi və parametrdən başqa bütün məlumatları süzür resourceVersion. Sonuncu parametr sirri yaratarkən annotasiyaya keçdi: o, sirlərin versiyalarını müqayisə etməyə və onları aktual saxlamağa imkan verir.
Bu şəkildə konfiqurasiya edilmiş çəngəl, icra edildikdə, yuxarıda təsvir edilən üç bağlama kontekstini alacaq. Onlar bir növ snapshot kimi düşünülə bilər (snapshot) klaster.

Bütün bu məlumatlara əsaslanaraq əsas alqoritm hazırlana bilər. Bütün ad boşluqlarında təkrarlanır və:
- əgər
hasLabelməsələlərtruecari ad sahəsi üçün:- qlobal sirri yerli ilə müqayisə edir:
- əgər onlar eynidirsə, heç nə etmir;
- fərqlidirlərsə - icra edir
kubectl replacevə yacreate;
- qlobal sirri yerli ilə müqayisə edir:
- əgər
hasLabelməsələlərfalsecari ad sahəsi üçün:- Secretin verilmiş ad məkanında olmadığına əmin olur:
- yerli sirr varsa, istifadə edərək onu silin
kubectl delete; - yerli sirr aşkar olunmazsa, heç nə etmir.
- yerli sirr varsa, istifadə edərək onu silin
- Secretin verilmiş ad məkanında olmadığına əmin olur:

saytımızdan yükləyə bilərsiniz .
Beləliklə, 35 sətir YAML konfiqurasiyasından və təxminən eyni miqdarda Bash kodundan istifadə edərək sadə Kubernetes nəzarətçisi yarada bildik! Qabıq-operatorun işi onları bir-birinə bağlamaqdır.
Bununla belə, sirləri kopyalamaq yardım proqramının yeganə tətbiq sahəsi deyil. Onun nəyə qadir olduğunu göstərmək üçün daha bir neçə misal göstərmək olar.
Nümunə 1: ConfigMap-a dəyişikliklərin edilməsi
Üç poddan ibarət Yerləşdirməyə baxaq. Podlar bəzi konfiqurasiyaları saxlamaq üçün ConfigMap-dən istifadə edir. Podlar işə salındıqda, ConfigMap müəyyən bir vəziyyətdə idi (gəlin onu v.1 adlandıraq). Müvafiq olaraq, bütün podlar ConfigMap-in bu xüsusi versiyasını istifadə edir.
İndi fərz edək ki, ConfigMap dəyişib (v.2). Bununla belə, podlar ConfigMap-in (v.1) əvvəlki versiyasından istifadə edəcək:

Onları yeni ConfigMap-a (v.2) keçməyə necə nail ola bilərəm? Cavab sadədir: şablondan istifadə edin. Bölməyə yoxlama məbləği annotasiyası əlavə edək template Yerləşdirmə konfiqurasiyaları:

Nəticə olaraq, bu yoxlama cəmi bütün podlarda qeydə alınacaq və Yerləşdirmə ilə eyni olacaq. İndi yalnız ConfigMap dəyişdikdə annotasiyanı yeniləməlisiniz. Və bu vəziyyətdə shell-operator kömək edir. Sizə lazım olan tək şey proqramdır ConfigMap-a abunə olacaq və yoxlama məbləğini yeniləyəcək çəngəl.
İstifadəçi ConfigMap-da dəyişikliklər edərsə, shell-operator onları görəcək və yoxlama məbləğini yenidən hesablayacaq. Bundan sonra Kubernetesin sehri işə düşəcək: orkestr podu öldürəcək, yenisini yaradacaq və onun olmasını gözləyəcək. Ready, və növbəti birinə keçir. Nəticədə, Deployment sinxronlaşdırılacaq və ConfigMap-in yeni versiyasına keçəcək.

Nümunə 2: Xüsusi Resurs Tərifləri ilə işləmək
Bildiyiniz kimi, Kubernetes sizə fərdi növ obyektlər yaratmağa imkan verir. Məsələn, növ yarada bilərsiniz MysqlDatabase. Tutaq ki, bu növün iki metadata parametri var: name и namespace.
apiVersion: example.com/v1alpha1
kind: MysqlDatabase
metadata:
name: foo
namespace: bar
MySQL verilənlər bazası yarada biləcəyimiz müxtəlif ad boşluqları olan Kubernetes klasterimiz var. Bu halda shell-operator resursları izləmək üçün istifadə edilə bilər MysqlDatabase, onları MySQL serverinə qoşmaq və klasterin arzu olunan və müşahidə olunan vəziyyətlərini sinxronlaşdırmaq.

Nümunə 3: Klaster Şəbəkəsinin Monitorinqi
Bildiyiniz kimi, ping-dən istifadə şəbəkəyə nəzarət etməyin ən sadə yoludur. Bu nümunədə shell-operator istifadə edərək belə monitorinqin necə həyata keçiriləcəyini göstərəcəyik.
Əvvəlcə qovşaqlara abunə olmalısınız. Shell operatoru hər bir qovşağın adına və IP ünvanına ehtiyac duyur. Onların köməyi ilə o, bu qovşaqlara ping atacaq.
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: "* * * * *"
Parametr executeHookOnEvent: [] hər hansı bir hadisəyə cavab olaraq (yəni qovşaqların dəyişdirilməsinə, əlavə edilməsinə, silinməsinə cavab olaraq) çəngəl işləməsinin qarşısını alır. Bununla belə, o qaçacaq (və qovşaqların siyahısını yeniləyin) Planlaşdırılıb - sahənin müəyyən etdiyi kimi hər dəqiqə schedule.
İndi sual yaranır ki, biz paket itkisi kimi problemləri necə dəqiq bilirik? Koda nəzər salaq:
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
}
Biz qovşaqların siyahısını təkrarlayırıq, onların adlarını və IP ünvanlarını alırıq, onlara ping edirik və nəticələri Prometeyə göndəririk. Shell-operator ölçüləri Prometheus-a ixrac edə bilər, onları mühit dəyişənində göstərilən yola uyğun olaraq yerləşən faylda saxlamaq $METRICS_PATH.
klasterdə sadə şəbəkə monitorinqi üçün operator edə bilərsiniz.
Növbə mexanizmi
Shell-operatora daxil edilmiş başqa bir vacib mexanizmi təsvir etmədən bu məqalə natamam olardı. Təsəvvür edin ki, o, klasterdəki bir hadisəyə cavab olaraq bir növ qarmaq yerinə yetirir.
- Eyni zamanda klasterdə bir şey baş verərsə nə olar? Başqası hadisə?
- Shell-operator çəngəlin başqa bir nümunəsini işlədəcəkmi?
- Bəs, deyək ki, klasterdə eyni anda beş hadisə baş verərsə?
- Shell-operator onları paralel olaraq emal edəcəkmi?
- Yaddaş və CPU kimi istehlak resursları haqqında nə demək olar?
Xoşbəxtlikdən, shell-operator daxili növbə mexanizminə malikdir. Bütün hadisələr növbəyə qoyulur və ardıcıllıqla işlənir.
Bunu misallarla izah edək. Tutaq ki, bizdə iki qarmaq var. İlk hadisə ilk qarmağa gedir. Onun işlənməsi başa çatdıqdan sonra növbə irəliləyir. Növbəti üç hadisə ikinci çəngələ yönləndirilir - onlar növbədən çıxarılır və "paketə" daxil edilir. Yəni hook bir sıra hadisələr qəbul edir — və ya daha dəqiq desək, bağlayan kontekstlər massivi.
Həm də bunlar hadisələr bir böyük hadisədə birləşdirilə bilər. Parametr buna cavabdehdir group bağlama konfiqurasiyasında.

İstənilən sayda növbə/qarmaq və onların müxtəlif kombinasiyalarını yarada bilərsiniz. Məsələn, bir növbə iki qarmaq ilə işləyə bilər və ya əksinə.

Sizə lazım olan tək şey sahəni müvafiq olaraq konfiqurasiya etməkdir queue bağlama konfiqurasiyasında. Əgər növbə adı göstərilməyibsə, çəngəl standart növbədə işləyir (default). Bu növbə mexanizmi qarmaqlarla işləyərkən bütün resursların idarə edilməsi problemlərini tamamilə həll etməyə imkan verir.
Nəticə
Biz shell-operatorun nə olduğunu izah etdik, ondan tez və asanlıqla Kubernetes operatorlarını yaratmaq üçün necə istifadə oluna biləcəyini göstərdik və onun istifadəsinə dair bir neçə nümunə verdik.
Shell-operator haqqında ətraflı məlumat, eləcə də ondan necə istifadə olunacağına dair sürətli təlimat müvafiq bölmədə mövcuddur. . Suallarınız üçün bizimlə əlaqə saxlamaqdan çəkinməyin: onları xüsusi müzakirələrdə müzakirə edə bilərsiniz (rus dilində) və ya dildə (ingilis dilində).
Bəyəndinizsə, GitHub-da yeni buraxılışları/PR/ulduzları görməkdən həmişə şad olarıq, yeri gəlmişkən, başqalarını da tapa bilərsiniz. . Onların arasında vurğulamağa dəyər , shell-operatorun böyük qardaşıdır. Bu yardım proqramı əlavələri quraşdırmaq üçün Helm diaqramlarından istifadə edir, yeniləmələri çatdıra və müxtəlif diaqram parametrlərinə/dəyərlərinə nəzarət edə bilər, diaqramların quraşdırılması prosesinə nəzarət edir və həmçinin klasterdəki hadisələrə cavab olaraq onları dəyişdirə bilər.

Videolar və slaydlar
Tamaşadan video (~23 dəqiqə):

Hesabat təqdimatı:
PS
Bloqumuzda da oxuyun:
- «";
- «";
- «";
- «.
Mənbə: www.habr.com
