38-წუთიანი ღრმა ჩაძირვა, რომელიც იქიდან იწყებს, სადაც შესავალი დეკი დასრულდა. Pod-ები, Deployment-ები და Service-ები უკვე ნაცნობად მიგვაჩნია და ერთი შრით ქვემოთ ჩავდივართ: control plane, ოპერატორები და CRD-ები, ქსელის შიდა მექანიკა, უსაფრთხოება, სერვის-მეში და ფლოტების მართვა GitOps-ით.
ნაწილ 1-ში გავეცანით იდეას, რომ თქვენ სასურველ მდგომარეობას აღწერთ, კლასტერი კი მას რეალობად აქცევს (მოკლე გამეორება შესავალ დეკშია). ახლა ყუთს გავხსნით. ყოველი „Kubernetes-მა რაღაც გააკეთა“ სინამდვილეში ესაა: რომელიღაც კონტროლერი უყურებს API server-ს, ადარებს სასურველს დაფიქსირებულს და რეალობას ერთი ნაბიჯით უახლოვებს. ცენტრალური ტვინი ბრძანებებს არ გასცემს — ათეულობით პატარა ციკლი თითო ნაჭერს ფლობს.
etcd-ს მხოლოდ API server კითხულობს და წერს. ყველა სხვა კომპონენტი კლიენტია, რომელიც აკვირდება და მოქმედებს.
// every controller is this shape while (true) { const obj = await informer.next(); // woken by a watch event const desired = obj.spec; // what you asked for const actual = await observe(obj); // what the world looks like if (!isEqual(desired, actual)) { await act(obj); // ONE step toward desired return; // requeue — re-check next loop } }
informer watch-ნაკადს ქეშირებულ სამუშაო რიგად აქცევს; შეთანხმების ფუნქცია თითო ელემენტზე ერთხელ ეშვება და თავს ისევ რიგში აბრუნებს.
კონტროლის ციკლი მხოლოდ ჩაშენებული ტიპებისთვის არაა. CRD-ით შეგიძლიათ საკუთარი ობიექტების ტიპები დაამატოთ და შემდეგ კონტროლერი დაწეროთ, რომელიც მათ ათანხმებს — ეს არის ოპერატორი. სწორედ ასე ხდებიან Postgres, Kafka, cert-manager და Argo სრულფასოვანი „kind“-ები, რომლებსაც kubectl apply-ით მართავთ.
kind: Database ისეთივე რეალურია, როგორც kind: Pod: ინახება etcd-ში, მოწმდება OpenAPI-სქემით, გაიცემა REST-ით, ექვემდებარება RBAC-ს და მისი watch შესაძლებელია. CRD ამატებს არსებით სახელს; თავისით ის არაფერს აკეთებს.თქვენ წერთ Database-ს; ოპერატორი მას იმ ჩაშენებულ ობიექტებად ათანხმებს, რომლებიც Postgres-ს რეალურად უშვებენ.
კარგად აღზრდილი ოპერატორი spec-ს არასოდეს წერს (ის მომხმარებლისაა) და პროგრესს მხოლოდ status-ში აღწერს. /status სუბრესურსი მას საშუალებას აძლევს, status განაახლოს ობიექტის generation-ის გაზრდის გარეშე — ასე ის საკუთარ შეთანხმებას ციკლში აღარ იწვევს.
finalizer ობიექტზე მიწერილი სტრიქონია, რომელიც წაშლას აჩერებს, სანამ ოპერატორი მას არ მოხსნის. წაშლისას ობიექტი deletionTimestamp მდგომარეობაში გადადის; ოპერატორი დასუფთავებას ატარებს (შლის ღრუბლოვან დისკს, აუქმებს DNS-ჩანაწერს), შემდეგ finalizer-ს ხსნის და Kubernetes წაშლას ასრულებს.
საზოგადოების პროექტი, რომელიც controller-runtime-ს ახვევს: აგენერირებს CRD-ტიპებს, მენეჯერსა და შემთანხმებლებს Go-ზე.
Red Hat-ის ინსტრუმენტარიუმი, აშენებული Kubebuilder-ის თავზე: ამატებს Helm-სა და Ansible-ზე დაფუძნებულ ოპერატორებს, OLM-შეფუთვასა და scorecard-ტესტებს.
როგორ აირჩიოთ: კაპოტის ქვეშ ორივე ერთსა და იმავე controller-runtime შემთანხმებელს აწარმოებს. აირჩიეთ Kubebuilder, თუ გინდათ მჭლე Go-ოპერატორი upstream-თან ახლოს; აირჩიეთ Operator SDK, თუ Helm/Ansible გზა ან OLM-ით გავრცელება გჭირდებათ. ნებისმიერი ოპერატორის დაწერამდე შეამოწმეთ, ხომ არ არსებობს უკვე მზა — პოპულარულ პროგრამებს უმეტესად აქვთ.
ნაწილ 1-ში ითქვა: „ყოველი pod იღებს IP-ს და Service მათზე დატვირთვას ანაწილებს“. სწორია — მაგრამ ვინ ანიჭებს ამ IP-ებს და რა აქცევს Service-ის ვირტუალურ IP-ს რეალურ pod-ად? პასუხები ასეთია: CNI — pod-ების ქსელისთვის, kube-proxy (ან მისი eBPF-ჩამნაცვლებლები) — Service-ებისთვის და NetworkPolicy — ფაიერვოლისთვის.
Service-ის პროცესი არ არსებობს. ნოუდის ბირთვი VIP-ს ერთ ჯანმრთელ ენდპოინტზე გადაწერს — დატვირთვის განაწილება data plane-ში ხდება.
api-ს კლასტერის DNS-ით (CoreDNS) Service-ის ClusterIP-ად ამოიცნობს.კლასტერს ბევრი გზა აქვს, ზედმეტად ლმობიერი იყოს: იდენტობები, რომლებსაც ყველაფერი შეუძლიათ, pod-ები, რომლებიც root-ით ეშვება, secret-ები ღია ტექსტად და იმიჯები, რომლებიც არავის შეუმოწმებია. დაცვა შრეებად ეწყობა: RBAC — ვის; Pod Security — რა შეუძლია pod-ს; დაშიფრული secret-ები; და მიწოდების ჯაჭვის შემოწმებები იმისთვის, რასაც საერთოდ უშვებთ.
get, list, create) რესურსების ტიპებზე. RoleBinding ამ როლს სუბიექტს — მომხმარებელს, ჯგუფს ან ServiceAccount-ს — მიაბამს. RBAC მხოლოდ დამატებითია: აკრძალვის წესები არ არსებობს, ამიტომ უფლებებს ნულიდან ზემოთ ანიჭებთ.სუბიექტი + Role = RoleBinding. ზმნები და რესურსები Role-ში ცხოვრობს; მიბმა მხოლოდ ამბობს, რომ „ამ იდენტობას მისი გამოყენება შეუძლია“.
privileged, baseline, restricted — უბრალო ლეიბლით. მიზნად restricted დაისახეთ: root არა, უფლებების ესკალაცია არა, capabilities მოხსნილი.get secrets — ან secret-ები გარე საცავში გაიტანეთ (Vault, ღრუბლის secret-მენეჯერები) External Secrets ოპერატორით.automountServiceAccountToken იქ, სადაც pod API-ს საერთოდ არ იძახებს.Open Policy Agent Gatekeeper admission-კონტროლერთან ერთად. შეზღუდვები Rego-ზე იწერება — ეს სპეციალურად პოლიტიკისთვის შექმნილი ენაა, რომელიც Kubernetes-ს ბევრად სცდება.
Kubernetes-ისთვის მშობლიური ძრავა, სადაც პოლიტიკები YAML-ზე დაწერილი CRD-ებია — ამოწმებს, ცვლის და ქმნის რესურსებს ახალი ენის გარეშე.
როგორ აირჩიოთ: გინდათ პოლიტიკა, რომელიც Kubernetes-ს სცდება, ან ნამდვილად რთული წესები? OPA/Gatekeeper. გინდათ დამცავი მოაჯირები დღესვე გაუშვათ ჩვეულებრივ YAML-ზე, მუტაციის ჩათვლით? Kyverno. ორივე validating/mutating ვებჰუკად მუშაობს — არჩევანი ენაზეა და არა მექანიზმზე.
როცა ბევრი სერვისი გყავთ, გინდათ დაშიფრული ტრაფიკი სერვისებს შორის, ხელახალი მცდელობები და ტრაფიკის ზუსტი დაყოფა — ისე, რომ ეს ყოველ აპლიკაციაში არ ჩააშენოთ. სერვის-მეში თითოეული დატვირთვის გვერდით პროქსის აყენებს და ამ ყველაფერს პლატფორმის შრიდან მართავს.
http://orders-ს, როგორც ადრე — პროქსი კი გამჭვირვალედ ამატებს mTLS-ს, ხელახალ მცდელობებს, ტაიმაუტებსა და მეტრიკებს.პროქსი ყოველ ნახტომს შიფრავს და ტრაფიკს წონის მიხედვით ყოფს — 90% სტაბილურზე, 10% canary-ზე — აპლიკაციის ცვლილების გარეშე.
Envoy-ზეა აგებული, ღრმა ტრაფიკის მართვით, პოლიტიკითა და მრავალკლასტერული მხარდაჭერით; ახლა უკვე გთავაზობთ sidecar-იან და sidecar-ის გარეშე ambient რეჟიმებს.
CNCF-ის დამთავრებული პროექტი, აგებული სპეციალურად შექმნილ Rust-მიკროპროქსზე, ოპტიმიზებული სიმარტივესა და დაბალ ზედნადებზე.
როგორ აირჩიოთ: გინდათ მაქსიმალური კონტროლი, რთული მარშრუტიზაცია ან რამდენიმე კლასტერი? Istio (ზედნადების შესამცირებლად ambient რეჟიმიც განიხილეთ). გინდათ mTLS და ოქროს მეტრიკები მინიმალური საექსპლუატაციო ტვირთით? Linkerd. და გახსოვდეთ: მეში უფასო არაა — მიმართეთ მას მხოლოდ მაშინ, როცა აპლიკაციის დონის ქსელური ტკივილი პროქსებს ამართლებს.
მასშტაბზე ორი პრობლემა დომინირებს: ბევრი კლასტერის ცნობილ, აუდიტირებად მდგომარეობაში შენარჩუნება და pod-ებისა და ნოუდების სწორად გაზომვა დატვირთვის მოძრაობისას. პირველზე პასუხობს GitOps; მეორეზე — ავტოსკეილერების სტეკი.
აგენტი Git-იდან წამოიღებს და განუწყვეტლივ ათანხმებს — ხელით შეტანილი ცვლილება გადახრად იქცევა და შემდეგ რეპოზიტორიის შესაბამისად უკან ბრუნდება.
კონტროლერი მდიდარი დაშბორდით, რომელიც სინქრონიზაციის სტატუსსა და ცოცხალი მდგომარეობის Git-თან სხვაობებს აჩვენებს; პროგრესული მიწოდებისთვის Argo Rollouts-თან წყვილდება.
პატარა, აწყობადი კონტროლერების ნაკრები, Git-ისთვის მშობლიური და CLI-ზე ორიენტირებული, რომელიც სუფთად ინტეგრირდება Helm-სა და Kustomize-თან.
როგორ აირჩიოთ: გინდათ დაშბორდი და მარტივი დასაწყისი? Argo CD. გინდათ მინიმალური, აწყობადი, ავტომატიზაციაზე ორიენტირებული სისტემა? Flux. ორივე Git-ს ჭეშმარიტების წყაროდ აქცევს; სხვაობა ზედაპირშია და არა იდეაში.
შევკრათ ყველაფერი პატარა ოპერატორის ფორმით, რომელიც ერთ წესს აღწერს: „ყოველ Database-ს გარე სარეზერვო ასლი უნდა ჰქონდეს“. ეს იგივე შეთანხმების ციკლია პირველი სექციიდან, ოღონდ ახლა თქვენს არსებით სახელზე მუშაობს.
// the heart of an operator — controller-runtime async reconcile(ctx: Context, req: Request): Promise<Result> { const db = await this.get<Database>(req.namespacedName); if (!db.spec.backup) { // enforce policy return this.reject("backup is required"); } await this.ensureStatefulSet(ctx, db); // converge built-ins await this.ensureBackupCronJob(ctx, db); db.status.phase = "Ready"; await this.updateStatus(ctx, db); // status, never spec return this.requeue(); // level-triggered, forever }
დაკვირვება რესურსზე, წესის აღსრულება, ჩაშენებული ობიექტების დაახლოება, status-ის დაფიქსირება, რიგში დაბრუნება. ეს ერთი შაბლონი კვებავს კლასტერის ყოველ კონტროლერს.
ხუთი კითხვა control plane-ზე, ოპერატორებზე, ქსელის შიდა მექანიკაზე, უსაფრთხოებასა და მეშზე — მყისიერი პასუხი, ავტორიზაციის გარეშე.
ნავიგაცია ← → ღილაკებით ან სქროლით · უკან ბიბლიოთეკაში