Për të qenë i sinqertë, nuk jam 100% i sigurt. Por unë mendoj se është interesante të gërmosh në brendësi dhe të shohësh se çfarë po ndodh vërtet në Kubernetes nën shtresat e shumta të abstraksioneve. Pra, thjesht për argëtim, le të hedhim një vështrim se si duket në të vërtetë një "grup Kubernetes" minimal. (Kjo do të jetë shumë më e lehtë se Kubernetes Rruga e Vështirë.)
Supozoj se keni njohuri bazë të Kubernetes, Linux dhe kontejnerëve. Gjithçka për të cilën flasim këtu është vetëm për qëllime kërkimore/mësimore, mos e vendosni asnjë prej tyre në prodhim!
Rishikimi
Kubernetes përmban shumë komponentë. Sipas wikipedia, arkitektura duket si kjo:
Janë të paktën tetë komponentë të paraqitur këtu, por ne do t'i injorojmë shumicën e tyre. Dua të them se gjëja minimale që mund të quhet me arsye Kubernetes përbëhet nga tre komponentë kryesorë:
kubelet
kube-apiserver (i cili varet nga etcd - databaza e tij)
Koha e funksionimit të kontejnerit (Docker në këtë rast)
Le të shohim se çfarë thotë dokumentacioni për secilën prej tyre (rusisht., Anglisht.). Ne fillim kubelet:
Një agjent që funksionon në secilën nyje në grup. Siguron që kontejnerët të funksionojnë në pod.
Tingëllon mjaft e thjeshtë. Po për kohëzgjatja e kontejnerëve (koha e funksionimit të kontejnerit)?
Koha e funksionimit të kontejnerit është një program i krijuar për të ekzekutuar kontejnerët.
Shumë informues. Por nëse jeni njohur me Docker, atëherë duhet të keni një ide të përgjithshme se çfarë bën. (Detajet e ndarjes së përgjegjësive midis kohëzgjatjes së kontejnerit dhe kubelet janë në të vërtetë mjaft delikate dhe unë nuk do të hyj në to këtu.)
И Serveri API?
Serveri API është komponenti i panelit të kontrollit Kubernetes që ekspozon API-në e Kubernetes. Serveri API është ana e klientit të panelit të kontrollit Kubernetes
Kushdo që ka bërë ndonjëherë ndonjë gjë me Kubernetes është dashur të ndërveprojë me API-në ose drejtpërdrejt ose përmes kubectl. Kjo është zemra e asaj që e bën Kubernetes Kubernetes - truri që i kthen malet e YAML që të gjithë i njohim dhe i duam (?) në infrastrukturë pune. Duket qartë se API duhet të jetë i pranishëm në konfigurimin tonë minimal.
Parakushtet
Makinë virtuale ose fizike Linux me qasje rrënjësore (Unë jam duke përdorur Ubuntu 18.04 në një makinë virtuale).
Dhe është gjithçka!
Instalim i mërzitshëm
Duhet të instalojmë Docker në makinën që do të përdorim. (Nuk do të hyj në detaje se si funksionojnë Docker dhe kontejnerët; nëse jeni të interesuar, ka artikuj të mrekullueshëm). Le ta instalojmë vetëm me apt:
Pas kësaj, ne duhet të marrim binaret Kubernetes. Në fakt, për nisjen fillestare të "grupit" tonë na duhet vetëm kubelet, pasi për të ekzekutuar komponentë të tjerë të serverit ne mund të përdorim kubelet. Për të bashkëvepruar me grupin tonë pasi të funksionojë, ne do të përdorim gjithashtu kubectl.
kubelet duhet të funksionojë si rrënjë. Shumë logjike, pasi ai duhet të menaxhojë të gjithë nyjen. Le të shohim parametrat e tij:
$ ./kubelet -h
<слишком много строк, чтобы разместить здесь>
$ ./kubelet -h | wc -l
284
Wow, kaq shumë opsione! Për fat të mirë, na duhen vetëm disa prej tyre. Këtu është një nga parametrat që na intereson:
--pod-manifest-path string
Rruga drejt drejtorisë që përmban skedarë për pods statike, ose shtegu drejt një skedari që përshkruan pods statike. Skedarët që fillojnë me pika injorohen. (I DEPRECATED: Ky opsion duhet të vendoset në skedarin e konfigurimit të kaluar në Kubelet nëpërmjet opsionit --config. Për më shumë informacion, shih kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)
Ky opsion na lejon të ekzekutojmë bishtaja statike — pods që nuk menaxhohen nëpërmjet Kubernetes API. Bishtajat statike përdoren rrallë, por ato janë shumë të përshtatshme për të ngritur shpejt një grup, dhe kjo është pikërisht ajo që na nevojitet. Ne do ta injorojmë këtë paralajmërim të madh (përsëri, mos e ekzekutoni këtë në prodhim!) dhe do të shohim nëse mund ta bëjmë podin të funksionojë.
Së pari ne do të krijojmë një direktori për pods statike dhe do të ekzekutojmë kubelet:
kubelet fillon të shkruajë disa paralajmërime dhe duket sikur asgjë nuk po ndodh. Por kjo nuk është e vërtetë! Le të shohim Docker:
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c8a35e26663 busybox "echo 'hello world!'" 36 seconds ago Exited (0) 36 seconds ago k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
68f670c3c85f k8s.gcr.io/pause:3.2 "/pause" 2 minutes ago Up 2 minutes k8s_POD_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_0
$ sudo docker logs k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
hello world!
kubelet Lexova manifestin e pod dhe i dhashë Docker komandën për të nisur disa kontejnerë sipas specifikimeve tona. (Nëse po pyesni veten për kontejnerin "pauzë", është një hak i Kubernetes - shih këtë blog.) Kubelet do të lëshojë kontejnerin tonë busybox me komandën e specifikuar dhe do ta rifillojë atë për një kohë të pacaktuar derisa të fshihet pod statike.
Përgëzoje veten. Sapo dolëm me një nga mënyrat më konfuze për të nxjerrë tekst në terminal!
Nisja etj
Qëllimi ynë përfundimtar është të ekzekutojmë Kubernetes API, por për ta bërë këtë, së pari duhet të ekzekutojmë etj. Le të fillojmë një grup minimal etcd duke vendosur cilësimet e tij në direktorinë e pods (për shembull, pods/etcd.yaml):
Nëse keni punuar ndonjëherë me Kubernetes, këta skedarë YAML duhet të jenë të njohur për ju. Këtu vlen të përmenden vetëm dy pika:
Ne kemi montuar dosjen e hostit /var/lib/etcd në pod në mënyrë që të dhënat e etcd të ruhen pas një rinisjeje (nëse kjo nuk bëhet, gjendja e grupit do të fshihet sa herë që pod riniset, gjë që nuk do të jetë e mirë as për një instalim minimal Kubernetes).
Ne kemi instaluar hostNetwork: true. Ky cilësim, çuditërisht, konfiguron etcd për të përdorur rrjetin pritës në vend të rrjetit të brendshëm të pod (kjo do ta bëjë më të lehtë për serverin API gjetjen e grupit etcd).
Një kontroll i thjeshtë tregon se etcd po funksionon me të vërtetë në localhost dhe ruan të dhënat në disk:
$ curl localhost:2379/version
{"etcdserver":"3.4.3","etcdcluster":"3.4.0"}
$ sudo tree /var/lib/etcd/
/var/lib/etcd/
└── member
├── snap
│ └── db
└── wal
├── 0.tmp
└── 0000000000000000-0000000000000000.wal
Nisja e serverit API
Drejtimi i një serveri Kubernetes API është edhe më i lehtë. Parametri i vetëm që duhet të kalohet është --etcd-servers, bën atë që prisni:
Vendoseni këtë skedar YAML në drejtori pods, dhe serveri API do të fillojë. Duke kontrolluar me curl tregon se Kubernetes API po dëgjon në portin 8080 me akses plotësisht të hapur - nuk kërkohet vërtetim!
(Përsëri, mos e përdorni këtë në prodhim! U habita pak që cilësimi i paracaktuar është kaq i pasigurt. Por mendoj se kjo është për ta bërë më të lehtë zhvillimin dhe testimin.)
Dhe, surprizë e këndshme, kubectl funksionon jashtë kutisë pa asnjë cilësim shtesë!
$ ./kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:47:41Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.5", GitCommit:"e6503f8d8f769ace2f338794c914a96fc335df0f", GitTreeState:"clean", BuildDate:"2020-06-26T03:39:24Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
$ ./kubectl get pod
No resources found in default namespace.
problem
Por nëse gërmoni pak më thellë, duket se diçka po shkon keq:
$ ./kubectl get pod -n kube-system
No resources found in kube-system namespace.
Bishtajat statike që krijuam janë zhdukur! Në fakt, nyja jonë kubelet nuk është zbuluar fare:
$ ./kubectl get nodes
No resources found in default namespace.
Per Cfarë bëhet fjalë? Nëse ju kujtohet disa paragrafë më parë, ne e filluam kubelet me një grup jashtëzakonisht të thjeshtë parametrash të linjës së komandës, kështu që kubelet nuk di se si të kontaktojë serverin API dhe ta njoftojë atë për gjendjen e tij. Pas studimit të dokumentacionit, gjejmë flamurin përkatës:
--kubeconfig string
Rruga për në skedar kubeconfig, i cili specifikon se si të lidheni me serverin API. Disponueshmëria --kubeconfig aktivizon modalitetin e serverit API, nr --kubeconfig aktivizon modalitetin offline.
Gjatë gjithë kësaj kohe, pa e ditur, ne po përdornim kubelet në "modalitetin offline". (Nëse do të ishim pedantë, mund të mendonim për një kubelet të pavarur si "Kubernetes minimale të zbatueshme", por kjo do të ishte shumë e mërzitshme). Për ta bërë konfigurimin "real" të funksionojë, ne duhet të kalojmë skedarin kubeconfig në kubelet në mënyrë që ai të dijë se si të flasë me serverin API. Për fat të mirë është mjaft e thjeshtë (pasi nuk kemi ndonjë problem vërtetimi ose certifikate):
(Meqë ra fjala, nëse përpiqeni të hyni në API përmes curl kur kubelet nuk po funksionon, do të zbuloni se ai ende po funksionon! Kubelet nuk është një "prind" i pod-eve të tij si Docker, ai është më shumë si një "kontroll Daemon." Kontejnerët e menaxhuar nga një kubelet do të vazhdojnë të funksionojnë derisa kubelet t'i ndalojë ato.)
Në pak minuta kubectl duhet të na tregojë podet dhe nyjet siç presim:
$ ./kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
default hello-mink8s 0/1 CrashLoopBackOff 261 21h
kube-system etcd-mink8s 1/1 Running 0 21h
kube-system kube-apiserver-mink8s 1/1 Running 0 21h
$ ./kubectl get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
mink8s Ready <none> 21h v1.18.5 10.70.10.228 <none> Ubuntu 18.04.4 LTS 4.15.0-109-generic docker://19.3.6
Le të urojmë vërtet veten këtë herë (e di që tashmë e kam uruar veten) - ne kemi një "grup" minimal Kubernetes që funksionon me një API plotësisht funksionale!
Ne nisim nën
Tani le të shohim se çfarë është në gjendje API. Le të fillojmë me podin nginx:
$ ./kubectl apply -f nginx.yaml
Error from server (Forbidden): error when creating "nginx.yaml": pods "nginx" is
forbidden: error looking up service account default/default: serviceaccount
"default" not found
$ ./kubectl get serviceaccounts
No resources found in default namespace.
Këtu shohim se sa mjerisht i paplotë është mjedisi ynë Kubernetes - ne nuk kemi llogari për shërbime. Le të provojmë përsëri duke krijuar manualisht një llogari shërbimi dhe të shohim se çfarë ndodh:
$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
EOS
serviceaccount/default created
$ ./kubectl apply -f nginx.yaml
Error from server (ServerTimeout): error when creating "nginx.yaml": No API
token found for service account "default", retry after the token is
automatically created and added to the service account
Edhe kur krijuam llogarinë e shërbimit manualisht, shenja e vërtetimit nuk gjenerohet. Ndërsa vazhdojmë të eksperimentojmë me "grupin" tonë minimalist, do të zbulojmë se shumica e gjërave të dobishme që zakonisht ndodhin automatikisht do të mungojnë. Serveri Kubernetes API është mjaft minimalist, me shumicën e ngritjes së rëndë dhe konfigurimit automatik që ndodh në kontrollues të ndryshëm dhe punë në sfond që ende nuk janë duke u ekzekutuar.
Ne mund ta zgjidhim këtë problem duke vendosur opsionin automountServiceAccountToken për llogarinë e shërbimit (pasi nuk do të na duhet ta përdorim gjithsesi):
$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
automountServiceAccountToken: false
EOS
serviceaccount/default configured
$ ./kubectl apply -f nginx.yaml
pod/nginx created
$ ./kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 0/1 Pending 0 13m
Më në fund, gjilpëra u shfaq! Por në fakt nuk do të fillojë sepse ne nuk kemi planifikues (programuesi) është një tjetër komponent i rëndësishëm i Kubernetes. Përsëri, ne shohim se API Kubernetes është çuditërisht "memec" - kur krijoni një Pod në API, ai e regjistron atë, por nuk përpiqet të kuptojë se në cilën nyje duhet ta ekzekutojë.
Në fakt, nuk ju nevojitet një planifikues për të drejtuar një pod. Mund të shtoni manualisht një nyje në manifest në parametër nodeName:
(Zëvendësoni mink8s në emrin e nyjës.) Pas fshirjes dhe aplikimit, shohim që nginx ka filluar dhe po dëgjon adresën e brendshme IP:
$ ./kubectl delete pod nginx
pod "nginx" deleted
$ ./kubectl apply -f nginx.yaml
pod/nginx created
$ ./kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 30s 172.17.0.2 mink8s <none> <none>
$ curl -s 172.17.0.2 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
Për t'u siguruar që rrjeti ndërmjet podave po funksionon siç duhet, mund të ekzekutojmë curl nga një pod tjetër:
$ cat <<EOS | ./kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: curl
spec:
containers:
- image: curlimages/curl
name: curl
command: ["curl", "172.17.0.2"]
nodeName: mink8s
EOS
pod/curl created
$ ./kubectl logs curl | head -6
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
Është mjaft interesante të gërmosh në këtë mjedis dhe të shohësh se çfarë funksionon dhe çfarë jo. Zbulova se ConfigMap dhe Secret funksionojnë siç pritej, por Shërbimi dhe Vendosja jo.
Urgjent!
Ky postim po zgjatet, kështu që unë do të shpall fitoren dhe do të them se ky është një konfigurim i zbatueshëm që mund të quhet "Kubernetes". Për ta përmbledhur: katër binare, pesë parametra të linjës komanduese dhe "vetëm" 45 rreshta YAML (jo aq shumë sipas standardeve Kubernetes) dhe ne kemi mjaft gjëra që funksionojnë:
Pods menaxhohen duke përdorur API-në e rregullt të Kubernetes (me disa hakime)
Mund të ngarkoni dhe menaxhoni imazhe të kontejnerëve publikë
Pods mbeten të gjalla dhe rinisin automatikisht
Rrjetëzimi midis pods brenda së njëjtës nyje funksionon mjaft mirë
ConfigMap, montimi sekret dhe i thjeshtë i ruajtjes funksionojnë siç pritej
Por shumë nga ato që e bëjnë Kubernetes vërtetë të dobishëm ende mungojnë, të tilla si:
Pod Scheduler
Autentifikimi/autorizimi
Nyje të shumta
Rrjeti i shërbimeve
DNS e brendshme e grumbulluar
Kontrollorët për llogaritë e shërbimeve, vendosjet, integrimin me ofruesit e cloud dhe shumicën e të mirave të tjera që sjell Kubernetes
Pra, çfarë morëm në të vërtetë? Kubernetes API, që funksionon më vete, është me të vërtetë vetëm një platformë për të automatizimi i kontejnerëve. Nuk bën shumë - është një punë për kontrollues dhe operatorë të ndryshëm që përdorin API - por siguron një mjedis të qëndrueshëm për automatizimin.