Kubernetes Minimu Viable

A traduzzione di l'articulu hè stata preparata à a vigilia di l'iniziu di u corsu "Pratiche è strumenti DevOps".

Kubernetes Minimu Viable

Sè vo leghjite questu, avete probabilmente intesu qualcosa di Kubernetes (è se no, cumu avete finitu quì?) Ma chì hè esattamente Kubernetes? Questu "Orchestrazione di cuntenituri di qualità industriale"? Or "Sistema Operativu Cloud-Native"? Chì significa ancu questu?

Per esse onesto, ùn sò micca sicuru à u 100%. Ma pensu chì hè interessante per sfondà in l'internu è vede ciò chì succede veramente in Kubernetes sottu i so numerosi strati di astrazioni. Dunque, solu per divertimentu, fighjemu un ochju à ciò chì hè veramente un "cluster Kubernetes" minimu. (Questu serà assai più faciule ch'è Kubernetes The Hard Way.)

Pensu chì avete una cunniscenza basica di Kubernetes, Linux è cuntenituri. Tuttu ciò chì parlemu quì hè solu per scopi di ricerca / apprendimentu, ùn ne mette micca in produzzione !

riassuntu

Kubernetes cuntene assai cumpunenti. Secondu Wikipedia, l'architettura s'assumiglia cusì:

Kubernetes Minimu Viable

Ci sò almenu ottu cumpunenti mostrati quì, ma ignuremu a maiò parte di elli. Vogliu dichjarà chì u minimu minimu chì pò esse chjamatu Kubernetes hè custituitu da trè cumpunenti principali:

  • kubelet
  • kube-apiserver (chì dipende da etcd - a so basa di dati)
  • runtime di u containeru (Docker in questu casu)

Videmu ciò chì a documentazione dice nantu à ognunu di elli (rus., Inglese.). Prima kubelet:

Un agente chì corre nantu à ogni node in u cluster. Hè assicuratu chì i cuntenituri currenu in u pod.

Sona abbastanza simplice. Chì ne dici i tempi di esecuzione di u containeru (durata di u containeru)?

Un runtime di cuntainer hè un prugramma cuncepitu per eseguisce cuntenituri.

Moltu informativu. Ma sè cunnosci Docker, allora duvete avè una idea generale di ciò chì face. (I detaglii di a separazione di e responsabilità trà u runtime di u containeru è u kubelet sò in realtà abbastanza sottili è ùn entreraghju micca quì.)

И servitore API?

API Server hè u cumpunente di u pannellu di cuntrollu di Kubernetes chì espone l'API Kubernetes. U servitore API hè u cliente di u pannellu di cuntrollu di Kubernetes

Qualchissia chì hà mai fattu qualcosa cù Kubernetes hà avutu à interagisce cù l'API direttamente o attraversu kubectl. Questu hè u core di ciò chì face Kubernetes Kubernetes - u cervellu chì trasforma e muntagne di YAML chì tutti sapemu è amemu (?) In infrastruttura di travagliu. Sembra evidenti chì l'API deve esse presente in a nostra cunfigurazione minima.

Precondizioni

  • Macchina virtuale o fisica Linux cù accessu root (aghju utilizatu Ubuntu 18.04 in una macchina virtuale).
  • È hè tuttu!

Installazione boring

Avemu bisognu di stallà Docker nantu à a macchina chì useremu. (Ùn andaraghju micca in i dettagli nantu à cumu funziona Docker è i cuntenituri; se site interessatu, ci hè articuli meravigliosi). Stallà solu cù apt:

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

Dopu quì, avemu bisognu di ottene i binari Kubernetes. In fatti, per u lanciu iniziale di u nostru "cluster" avemu solu bisognu kubelet, postu chì per eseguisce altri cumpunenti di u servitore pudemu usà kubelet. Per interagisce cù u nostru cluster dopu chì hè in esecuzione, avemu ancu aduprà 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

Chì succede se corremu solu kubelet?

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

kubelet deve correre cum'è root. Piuttostu logicu, postu chì hà bisognu di gestisce u node sanu. Fighjemu i so paràmetri:

$ ./kubelet -h
<слишком много строк, чтобы разместить здесь>
$ ./kubelet -h | wc -l
284

Wow, tante opzioni! Per furtuna, avemu bisognu solu un paru di elli. Eccu unu di i parametri chì ci interessanu:

--pod-manifest-path string

Percorsu à u cartulare chì cuntene i fugliali per pods statici, o percorsu à un schedariu chì descrive pods statici. I schedari chì cumincianu cù punti sò ignorati. (DEPRECATED: Questa opzione deve esse stabilita in u schedariu di cunfigurazione passatu à u Kubelet via l'opzione --config. Per più infurmazione, vede kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)

Questa opzione ci permette di correre baccelli statici - pods chì ùn sò micca gestiti via l'API Kubernetes. I pods statici sò raramente usati, ma sò assai convenienti per elevà rapidamente un cluster, è questu hè esattamente ciò chì avemu bisognu. Ignuremu stu grande avvisu (di novu, ùn eseguite micca questu in a pruduzzione!) È vede s'ellu pudemu avè u pod in funziunamentu.

Prima creeremu un repertoriu per pods statici è eseguite kubelet:

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

Allora, in un altru terminal / finestra tmux / qualunque, creeremu un manifestu pod:

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

kubelet cumencia à scrive qualchi avvisi è pare chì nunda ùn succede. Ma ùn hè micca vera ! Fighjemu à 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 Aghju lettu u manifestu di pod è detti à Docker u cumandimu per lancià un paru di cuntenituri secondu e nostre specificazioni. (Se vi dumandate di u containeru "pausa", hè un hack Kubernetes - vede stu bloggu.) Kubelet lanciarà u nostru containeru busybox cù u cumandamentu specificatu è riavviarà indefinitu finu à chì u pod staticu hè sguassatu.

Felicitate sè stessu. Avemu ghjustu ghjuntu cù unu di i modi più cunfusu per pruduce testu à u terminal!

Lanciari etcd

U nostru scopu ultimu hè di eseguisce l'API Kubernetes, ma per fà questu avemu prima bisognu di eseguisce eccd. Cuminciamu un cluster minimale etcd mettendu i so paràmetri in u cartulare pods (per esempiu, 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

Se avete mai travagliatu cù Kubernetes, questi schedarii YAML duveranu esse familiarizati per voi. Ci sò solu dui punti chì vale a pena nutà quì:

Avemu muntatu u cartulare host /var/lib/etcd in u pod in modu chì i dati etcd sò cunservati dopu un reiniciu (se ùn hè micca fattu, u statu di cluster serà sguassatu ogni volta chì u pod hè riavviatu, chì ùn serà micca bonu per ancu una stallazione minima di Kubernetes).

Avemu stallatu hostNetwork: true. Stu paràmetru, senza sorpresa, cunfigurà etcd per utilizà a reta di l'ospite invece di a reta interna di u pod (questu farà più faciule per u servitore API per truvà u cluster etcd).

Un cuntrollu simplice mostra chì l'etcd hè veramente in esecuzione nantu à l'host local è salvà dati à u discu:

$ 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

Accuminciari u servitore API

Eseguisce un servitore API Kubernetes hè ancu più faciule. U solu paràmetru chì deve esse passatu hè --etcd-servers, faci ciò chì aspetta:

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

Pone stu schedariu YAML in u cartulare pods, è u servitore API inizierà. Cuntrollà cun curl mostra chì l'API Kubernetes sta à sente nantu à u portu 8080 cù un accessu cumpletamente apertu - senza autentificazione necessaria!

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

(In novu, ùn eseguite micca questu in a pruduzzione! Eru un pocu sorpresu chì u paràmetru predeterminatu hè cusì inseguru. Ma supponu chì questu hè per fà u sviluppu è a prova più faciule.)

E, sorpresa piacevule, kubectl funziona fora di a scatula senza paràmetri supplementari!

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

prublemu

Ma s'è scavate un pocu più in fondu, qualcosa pare chì andarà male:

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

I pods statici chì avemu creatu sò andati! In fattu, u nostru node kubelet ùn hè micca scupertu à tuttu:

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

Chì ci hè? Se vi ricordate uni pochi di paragrafi fà, avemu principiatu u kubelet cun un set estremamente simplice di paràmetri di linea di cummanda, perchè u kubelet ùn sapi micca cumu cuntattà u servitore API è avvisà u so statu. Dopu avè studiatu a documentazione, truvamu a bandiera currispundente:

--kubeconfig string

A strada di u schedariu kubeconfig, chì specifica cumu cunnette à u servitore API. A dispunibilità --kubeconfig attiva u modu di u servitore API, no --kubeconfig permette u modu offline.

Tuttu stu tempu, senza sapè, stavamu eseguendu u kubelet in "modu offline". (Se eramu esse pedanti, pudemu pensà à un kubelet standalone cum'è "Kubernetes viable minimu", ma questu seria assai noioso). Per fà u travagliu di cunfigurazione "reale", avemu bisognu di passà u schedariu kubeconfig à u kubelet per sapè cumu parlà à u servitore API. Per furtuna, hè abbastanza simplice (perchè ùn avemu micca prublemi cù l'autentificazione o i certificati):

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

Salvà questu cum'è kubeconfig.yaml, tumbà u prucessu kubelet è ripigliate cù i paràmetri necessarii:

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

(A propositu, se pruvate d'accede à l'API via curl quandu u kubelet ùn hè micca in esecuzione, truverete chì hè sempre in esecuzione! Kubelet ùn hè micca un "parent" di i so pods cum'è Docker, hè più cum'è un "controllu". daemon." I cuntenituri gestiti da un kubelet continuanu à curriri finu à chì u kubelet li ferma.)

In pochi minuti kubectl duverebbe mustrà i pods è i nodi cum'è l'aspettemu:

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

Congratulemu veramente noi sta volta (sò chì aghju digià felicitatu) - avemu un "cluster" minimu di Kubernetes chì funziona cù una API cumplettamente funziunale!

Lanciamu sottu

Avà vede ciò chì l'API hè capace di. Cuminciamu cù u pod nginx:

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

Quì avemu un errore piuttostu interessante:

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

Quì vedemu quant'ellu hè incompletu u nostru ambiente Kubernetes - ùn avemu micca cunti per i servizii. Pruvemu di novu creendu manualmente un contu di serviziu è vede ciò chì succede:

$ 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

Ancu quandu avemu creatu u contu di serviziu manualmente, u token di autentificazione ùn hè micca generatu. Mentre cuntinuemu à sperimentà cù u nostru "cluster" minimalista, truveremu chì a maiò parte di e cose utili chì generalmente succedenu automaticamente saranu mancanti. U servitore API di Kubernetes hè abbastanza minimalista, cù a maiò parte di l'elevazione pesante è a cunfigurazione automatica chì succede in diversi cuntrolli è travaglii di fondo chì ùn sò ancu in esecuzione.

Pudemu travaglià stu prublema mettendu l'opzione automountServiceAccountToken per u contu di serviziu (perchè ùn avemu micca bisognu à aduprà in ogni modu):

$ 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

Finalmente, u pod hè apparsu! Ma in fatti ùn principia micca perchè ùn avemu micca pianificatore (scheduler) hè un altru cumpunente impurtante di Kubernetes. In novu, vedemu chì l'API Kubernetes hè sorprendentemente "mutu" - quandu crea un Pod in l'API, u registra, ma ùn prova micca di capisce quale nodu per eseguisce.

In fatti, ùn avete micca bisognu di un pianificatore per eseguisce un pod. Pudete aghjunghje manualmente un node à u manifestu in u paràmetru nodeName:

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

(Sustituitu mink8s à u nome di u node.) Dopu sguassate è applicà, vedemu chì nginx hà iniziatu è stà à sente l'indirizzu IP internu:

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

Per assicurà chì a reta trà pods funziona bè, pudemu eseguisce curl da un altru pod:

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

Hè assai interessante di scavà in questu ambiente è vede ciò chì funziona è ciò chì ùn hè micca. Aghju trovu chì ConfigMap è Secret travaglianu cum'è previstu, ma u Serviziu è u Deployment ùn sò micca.

Successu!

Stu postu hè diventatu longu, dunque aghju da dichjarà a vittoria è dicu chì questa hè una cunfigurazione viable chì pò esse chjamata "Kubernetes". Per riassume: quattru binari, cinque paràmetri di linea di cummanda è "solu" 45 linee di YAML (micca). tantu per i standard Kubernetes) è avemu parechje cose chì travaglianu:

  • I pods sò gestiti cù l'API Kubernetes regulare (cun ​​​​pochi pirate)
  • Pudete carricà è gestisce l'imaghjini di u containeru publicu
  • I pods restanu vivi è riavvianu automaticamente
  • A rete trà pods in u stessu node funziona abbastanza bè
  • ConfigMap, segretu è simplice di stallazione di almacenamentu travaglia cum'è previstu

Ma assai di ciò chì rende Kubernetes veramente utile hè sempre mancante, cum'è:

  • Pod Scheduler
  • Autentificazione / auturizazione
  • Nodi multipli
  • Rete di servizii
  • DNS internu in cluster
  • Controllers per i cunti di serviziu, implementazioni, integrazione cù i fornitori di nuvola è a maiò parte di l'altri boni chì Kubernetes porta

Allora chì avemu veramente uttene? L'API Kubernetes, chì funziona da sè stessu, hè veramente solu una piattaforma per l'automatizazione di u containeru. Ùn face micca assai - hè un travagliu per diversi cuntrolli è operatori chì utilizanu l'API - ma furnisce un ambiente coherente per l'automatizazione.

Sapete più nantu à u corsu in u webinar gratuitu.

Leghjite più:

Source: www.habr.com

Add a comment