Minimálne životaschopný Kubernetes

Preklad článku bol pripravený v predstihu pred začiatkom kurzu „Praktiky a nástroje DevOps“.

Minimálne životaschopný Kubernetes

Ak toto čítate, pravdepodobne ste už počuli o Kubernetes (ak nie, ako ste sa sem dostali?) Ale čo vlastne Kubernetes predstavuje? Je to „Orchestrácia kontajnerov na priemyselnej úrovni“? Или „Cloud-Native Operating System“? Что вообще это значит?

Úprimne povedané, nie som si tým na 100% istý. Ale myslím si, že je zaujímavé preskúmať vnútornosti a pozrieť sa, čo sa vlastne deje v Kubernetes pod jeho mnohými vrstvami abstrakcie. Takže z čistej zvedavosti sa pozrime, ako vlastne vyzerá minimálny „Kubernetes klaster“. (Toto bude oveľa jednoduchšie ako Kubernetes The Hard Way.)

Predpokladám, že máte základné poznatky o Kubernetes, Linuxe a kontajneroch. Všetko, o čom tu budeme hovoriť, je určené iba na prieskum/výučbu, nespúšťajte nič z toho v produkcii!

Prehľad

Kubernetes obsahuje veľa komponentov. Podľa wikipédie, architektúra vyzerá nasledovne:

Minimálne životaschopný Kubernetes

Tu je zobrazených aspoň osem komponentov, ale väčšinu z nich ignorujeme. Chcem uviesť, že minimálna vec, ktorú je možné rozumne nazvať Kubernetes, pozostáva z troch základných komponentov:

  • kubelet
  • kube-apiserver (ktorý závisí od etcd — jeho databázy)
  • prostredia pre spúšťanie kontajnerov (v tomto prípade Docker)

Pozrime sa, čo o každom z nich hovorí dokumentácia (ru., en.). Najprv kubelet:

Agent, ktorý beží na každom uzle v klastri. Sleduje, aby boli kontajnery spustené v pode.

Znie to dostatočne jednoducho. Čo hovoríte na prostredie pre spúšťanie kontajnerov (container runtime)?

Prostredie pre spúšťanie kontajnerov je program určený na spúšťanie kontajnerov.

Veľmi informatívne. Ale ak ste oboznámení s Dockerom, mali by ste mať všeobecnú predstavu o tom, čo robí. (Detaily rozdelenia zodpovedností medzi prostredím pre spúšťanie kontajnerov a kubeletom sú vlastne dosť tenké a tu sa nimi nebudem zaoberať.)

A API-server?

API server je komponent Kubernetes ovládacieho panela, ktorý predstavuje API Kubernetes. API server je klientská časť ovládacieho panela Kubernetes.

Každý, kto kedykoľvek robil niečo s Kubernetes, musel interagovať s API buď priamo, alebo cez kubectl. Toto je srdce toho, čo robí Kubernetes Kubernetesom – mozog, ktorý premieňa hory YAML, ktoré všetci poznáme a milujeme, na fungujúcu infraštruktúru. Je zrejmé, že API by malo byť prítomné v našej minimálnej konfigurácii.

Predpoklady

  • Virtuálny alebo fyzický server Linux s root prístupom (ja používam Ubuntu 18.04 na virtuálnom serveri).
  • A to je všetko!

Nudná inštalácia

Na server, ktorý budeme používať, je potrebné nainštalovať Docker. (Nebudem podrobne vysvetľovať, ako Docker a kontajnery fungujú; ak vás to zaujíma, existujú skvelé články). Poďme ho jednoducho nainštalovať pomocou apt:

$ sudo apt install docker.io
$ sudo systemctl start docker

Potom potrebujeme získať binárky Kubernetes. Na naštartovanie nášho "klastra" naozaj potrebujeme iba kubelet, pretože na spustenie ostatných serverových komponentov môžeme použiť kubelet. Na interakciu s naším klastrom po jeho spustení budeme tiež potrebovať kubectl.

$ curl -L https://dl.k8s.io/v1.18.5/kubernetes-server-linux-amd64.tar.gz > server.tar.gz
$ tar xzvf server.tar.gz
$ cp kubernetes/server/bin/kubelet .
$ cp kubernetes/server/bin/kubectl .
$ ./kubelet --version
Kubernetes v1.18.5

Čo sa stane, ak jednoducho spustíme kubelet?

$ ./kubelet
F0609 04:03:29.105194    4583 server.go:254] mkdir /var/lib/kubelet: permission denied

kubelet musí bežať ako root. Čo je logické, pretože musí spravovať celý uzlový server. Poďme sa pozrieť na jeho parametre:

$ ./kubelet -h

$ ./kubelet -h | wc -l
284

Wow, toľko možností! Našťastie, budeme potrebovať iba niekoľko z nich. Tu je jeden z parametrov, ktorý nás zaujíma:

--pod-manifest-path string

Cesta k adresáru obsahujúcemu súbory pre statické pody, alebo cesta k súboru s popisom statických podov. Súbory, ktoré začínajú bodkou, sa ignorujú. (ZASTARALÉ: tento parameter by sa mal nastaviť v konfiguračnom súbore, ktorý sa predáva do Kubeletu cez možnosť —config. Pre viac informácií pozri kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)

Tento parameter nám umožňuje spustiť statické pody — pod, ktoré nie sú spravované cez Kubernetes API. Statické pody sa používajú zriedka, ale sú veľmi užitočné na rýchle nasadenie klastra, a presne to potrebujeme. Toto hlasné varovanie ignorujeme (opäť, nespúšťajte to v produkcii!) a pozrime sa, či môžeme spustiť pod.

Najprv vytvoríme adresár pre statické pody a spustíme ho. kubelet:

$ mkdir pods
$ sudo ./kubelet --pod-manifest-path=pods

Potom v inom termináli/okne tmux/niekde inde vytvoríme manifest podu:

$ cat < pods/hello.yaml
apiVersion: v1
kind: Pod
metadata:
  name: hello
spec:
  containers:
  - image: busybox
    name: hello
    command: ["echo", "hello world!"]
EOF

kubelet začne písať nejaké varovania a zdá sa, že sa nič nedeje. Ale nie je to tak! Pozrime sa na 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 prečítal manifest podu a dal Dockeru príkaz spustiť niekoľko kontajnerov podľa našej špecifikácie. (Ak vás zaujíma kontajner "pause", je to hack Kubernetes — podrobnosti nájdete v na tomto blogu.) Kubelet spustí náš kontajner busybox s uvedeným príkazom a bude ho nekonečne reštartovať, pokiaľ nebude statický pod odstránený.

Blahoželajte si. Práve sme vymysleli jeden z najzložitejších spôsobov, ako vypísať text do terminálu!

Spúšťame etcd

Naším konečným cieľom je spustiť Kubernetes API, ale na to musíme najprv spustiť etcd. Poďme spustiť minimálny klaster etcd a umiestnime jeho nastavenia do adresára pods (napríklad, pods/etcd.yaml):

apiVersion: v1
kind: Pod
metadata:
  name: etcd
  namespace: kube-system
spec:
  containers:
  - name: etcd
    command:
    - etcd
    - --data-dir=/var/lib/etcd
    image: k8s.gcr.io/etcd:3.4.3-0
    volumeMounts:
    - mountPath: /var/lib/etcd
      name: etcd-data
  hostNetwork: true
  volumes:
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data

Ak ste niekedy pracovali s Kubernetes, mali by ste byť oboznámení s podobnými YAML súbormi. Tu stojí za zmienku len dva aspekty:

Pripojili sme adresár hostiteľa /var/lib/etcd v pody, aby sa dáta etcd ukladali po reštartovaní (ak to neurobíte, stav klastru sa pri každom reštartovaní podu vymaže, čo nie je dobré ani pre minimálnu inštaláciu Kubernetes).

Nainštalovali sme hostNetwork: true. Tento parameter, ako sa dalo očakávať, nastavuje etcd na používanie siete hostiteľa namiesto vnútornej siete podu (to uľahčí API serveru nájsť klaster etcd).

Jednoduchá kontrola ukazuje, že etcd skutočne beží na localhost a uklada dáta na 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

Spustenie API servera

Spustiť API server Kubernetes je ešte jednoduchšie. Jediný parameter, ktorý treba zadať, --etcd-servers, robí to, čo očakávate:

apiVersion: v1
kind: Pod
metadata:
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - name: kube-apiserver
    command:
    - kube-apiserver
    - --etcd-servers=http://127.0.0.1:2379
    image: k8s.gcr.io/kube-apiserver:v1.18.5
  hostNetwork: true

Umiestnite tento YAML súbor do adresára pods, a API server sa spustí. Kontrola pomocou curl ukazuje, že Kubernetes API počúva na porte 8080 s úplným prístupom — autentifikácia nie je potrebná!

$ curl localhost:8080/healthz
ok
$ curl localhost:8080/api/v1/pods
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/pods",
    "resourceVersion": "59"
  },
  "items": []
}

(Opäť, nespúšťajte to v produkcii! Bol som trochu prekvapený, že predvolená konfigurácia je tak nebezpečná. Ale predpokladám, že je to urobené pre uľahčenie vývoja a testovania.)

A, príjemné prekvapenie, kubectl funguje hneď z krabice bez akýchkoľvek dodatočných nastavení!

$ ./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.

Problém

Ale ak sa pozriete hlbšie, zdá sa, že niečo nie je v poriadku:

$ ./kubectl get pod -n kube-system
No resources found in kube-system namespace.

Statické pody, ktoré sme vytvorili, zmizli! V skutočnosti, náš kubelet uzol nie je vôbec detekovaný:

$ ./kubectl get nodes
No resources found in default namespace.

O čo ide? Ak si pamätáte, pred niekoľkými odstavcami sme spustili kubelet s veľmi jednoduchým súborom príkazových parametrov, takže kubelet nevie, ako sa pripojiť k serveru API a informovať ho o svojom stave. Po preskúmaní dokumentácie nájdeme vhodnú vlajku:

--kubeconfig reťazec

Cesta k súboru kubeconfig, v ktorom je uvedené, ako sa pripojiť k serveru API. Prítomnosť --kubeconfig aktívuje režim API servera, jeho absencia --kubeconfig aktívuje offline režim.

Po celý ten čas, ani si to neuvedomujúc, sme spúšťali kubelet v "offline režime". (Keby sme boli pedantskí, mohli by sme považovať offline režim kubeletu za "minimálne životaschopný Kubernetes", ale to by bola veľmi nudná myšlienka). Aby sme získali "právoplatnú" konfiguráciu, musíme odovzdať súbor kubeconfig kubeletu, aby vedel, ako komunikovať s API serverom. Našťastie je to celkom jednoduché (pretože nemáme problémy s autentifikáciou ani certifikátmi):

apiVersion: v1
kind: Config
clusters:
- cluster:
    server: http://127.0.0.1:8080
  name: mink8s
contexts:
- context:
    cluster: mink8s
  name: mink8s
current-context: mink8s

Uložte to ako kubeconfig.yaml, zabite proces kubelet a reštartujte s požadovanými parametrami:

$ sudo ./kubelet --pod-manifest-path=pods --kubeconfig=kubeconfig.yaml

(Mimochodom, ak sa pokúsite pristúpiť k API cez curl, keď kubelet nefunguje, zistíte, že stále funguje! Kubelet nie je "rodičom" svojich podov, ako Docker, je skôr podobný "správcovi démona". Kontajnery spravované kubeletom budú fungovať, pokiaľ ich kubelet nezastaví.)

O pár minút kubectl by sa mali zobraziť podi a uzly, ako očakávame:

$ ./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       21h   v1.18.5   10.70.10.228           Ubuntu 18.04.4 LTS   4.15.0-109-generic   docker://19.3.6

Tentoraz si naozaj gratulujme (viem, že už som gratuloval) — máme minimálny "klaster" Kubernetes, ktorý funguje s plnohodnotným API!

Spúšťame pod

Teraz sa pozrime, čo všetko API dokáže. Začneme s podom nginx:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx

Tu dostaneme celkom zaujímavú chybu:

$ ./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.

Tu vidíme, ako hrozne neúplné je naše prostredie Kubernetes — nemáme žiadne účty pre služby. Skúsme to znova a vytvorme účet služby ručne a pozrime sa, čo sa stane:

$ 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

Aj keď sme vytvorili účet služby ručne, autentifikačný token sa nevytvára. Pokračovaním v experimentovaní s naším minimalistickým „klastrom“ zistíme, že väčšina užitočných vecí, ktoré sa zvyčajne dejú automaticky, bude chýbať. Server Kubernetes API je dosť minimalistický, väčšina ťažkých automatických nastavení sa uskutočňuje v rôznych kontroléroch a background jobs, ktoré sa ešte nevykonávajú.

Túto situáciu môžeme obísť nastavením voľby automountServiceAccountToken pre účet služby (keďže ho aj tak nebudeme musieť používať):

$ 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

Nakoniec sa pod objavil! Ale v skutočnosti sa nezapne, pretože nemáme plánovač (scheduler) — ďalšia dôležitá súčasť Kubernetes. Opäť vidíme, že API Kubernetes je prekvapivo „hlúpe“ — keď vytvoríte pod v API, zaregistruje ho, ale nesnaží sa zistiť, na ktorom uzle ho spustiť.

V skutočnosti na spustenie podu nie je plánovač potrebný. Môžete ručne pridať uzol do manifestu pomocou parametra nodeName:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
  nodeName: mink8s

(Nahradiť mink8s názvom uzla.) Po delete a apply vidíme, že nginx sa spustil a počúva na vnútornom IP adrese:

$ .\/kubectl delete pod nginx
pod "nginx" bol vymazaný
$ .\/kubectl apply -f nginx.yaml
pod\/nginx bol vytvorený
$ .\/kubectl get pods -owide
NÁZOV   PLNÝ   STAV   REŠTARTY   VEK   IP           NOD     NOMINOVANÝ NOD   PRÍSTUPOVÉ BRÁNY
nginx   1\/1     Beží     0          30s   172.17.0.2   mink8s   <none>           <none>
$ curl -s 172.17.0.2 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Vitajte pri nginx!</title>

Aby sme sa uistili, že sieť medzi podmi funguje správne, môžeme spustiť curl z iného podu:

$ cat &lt;&lt;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>Vitajte pri nginx!</title>

Je celkom zaujímavé preskúmať toto prostredie a pozrieť sa, čo funguje a čo nie. Zistil som, že ConfigMap a Secret fungujú tak, ako sa očakáva, ale Service a Deployment nie.

Úspech!

Tento príspevok sa stáva väčším, preto sa chystám oznámiť víťaza a tvrdiť, že ide o funkčnú konfiguráciu, ktorú môžeme nazvať „Kubernetes“. Zhrnutie: štyri binárne súbory, päť parametrov príkazového riadku a „iba“ 45 riadkov YAML (nie tak veľa podľa štandardov Kubernetes) a máme rozbehnutých niekoľko vecí:

  • Pody sú spravované prostredníctvom klasického Kubernetes API (s niekoľkými hackmi)
  • Môžeme nahrávať verejné obrazy kontajnerov a spravovať ich
  • Pody zostávajú aktívne a automaticky sa reštartujú
  • Sieť medzi podmi v rámci jedného uzla funguje celkom dobre
  • ConfigMap, Secret a najjednoduchšie montovanie úložiska funguje tak, ako má

Ale väčšina toho, čo robí Kubernetes skutočne užitočným, stále chýba, napríklad:

  • Plánovač podov
  • Autentifikácia / autorizácia
  • Viaceré uzly
  • Sieť služieb
  • Klastrový vnútorný DNS
  • Kontroléry pre účty služieb, nasadenia, integráciu s cloudovými poskytovateľmi a väčšinu ďalších „vychytávok“, ktoré Kubernetes prináša

Čo sme teda naozaj získali? Kubernetes API, fungujúce samostatne, je vlastne len platformou na automatizáciu kontajnerov. Nerobí veľa — je to práca pre rôzne kontroléry a operátory, ktorí používajú API — ale poskytuje konzistentné prostredie na automatizáciu.

Zistite viac o kurze na bezplatnom webinári.

Čítať ďalej:

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster