Kubernetes minimalisht i jetueshëm

Përkthimi i artikullit është përgatitur në prag të fillimit të kursit «Praktikat dhe mjetet DevOps».

Kubernetes minimalisht i jetueshëm

NĂ«se po e lexoni kĂ«tĂ«, me siguri keni dĂ«gjuar diçka pĂ«r Kubernetes (dhe nĂ«se jo, si e gjeni veten kĂ«tu?) Por çfarĂ« paraqet me tĂ« verdade Kubernetes? Kjo Ă«shtĂ« "Orkestrimi i konteinerĂ«ve tĂ« nivelit industrial"? ИлО "Sistemi Operativ Cloud-Native"? Đ§Ń‚ĐŸ ĐČĐŸĐŸĐ±Ń‰Đ” ŃŃ‚ĐŸ Đ·ĐœĐ°Ń‡ĐžŃ‚?

Sinqerisht, nuk jam 100% i sigurt. Por mendoj se është interesante të shqyrtojmë thellësitë dhe të shohim se çfarë ndodh në të vërtetë në Kubernetes nën shtresat e tij të shumta të abstraksionit. Pra, për të kënaqur kureshtjen, le të shohim si duket në të vërtetë "klastri minimal i Kubernetes". (Kjo do të jetë shumë më e lehtë se Kubernetes The Hard Way.)

Mendoj se keni njohuri bazike mbi Kubernetes, Linux dhe konteinerët. Gjithçka që do të diskutojmë këtu është vetëm për qëllim eksplorimi/apo studimi, mos e vini në production!

Përmbledhje

Kubernetes përmban shumë komponente. Sipas wiki, arkitektura duket si më poshtë:

Kubernetes minimalisht i jetueshëm

Këtu janë të paktën tetë komponentë që shfaqen, por shumicën e tyre do t'i injorojmë. Dua të deklaroj se gjëja minimale që mund të quhet me të drejtë Kubernetes përbëhet nga tre komponentë kryesorë:

  • kubelet
  • kube-apiserver (i cili varet nga etcd — baza e tij e tĂ« dhĂ«nave)
  • mjedisi i ekzekutimit tĂ« konteinerĂ«ve (nĂ« kĂ«tĂ« rast Docker)

Le të shohim çfarë thotë dokumentacioni për secilin prej tyre (rus., angl.). Së pari kubelet:

Agjenti që funksionon në çdo nod në klastra. Ai siguron që konteinerët të jenë aktivë në pod.

Duket mjaft e thjeshtĂ«. ÇfarĂ« ndodh me mjedisin e ekzekutimit tĂ« konteinerĂ«ve (container runtime)?

Mjedisi i ekzekutimit të konteinerëve është një program që ka për qëllim të ekzekutojë konteinerët.

Shumë informuese. Por nëse jeni të njohur me Docker, duhet të keni një ide të përgjithshme se çfarë bën ai. (Detajet e ndarjes së përgjegjësive midis mjedisit të ekzekutimit të konteinerëve dhe kubelet janë në të vërtetë mjaft të holla dhe këtu nuk do të thellohem në to.)

DHE API-server?

Serveri i API-së është komponenti i panelit të kontrollit të Kubernetes që paraqet API-në e Kubernetes. API-serveri është pjesa klient e panelit të kontrollit të Kubernetes

Çdo kush qĂ« ndonjĂ«herĂ« ka punuar me Kubernetes Ă«shtĂ« detyruar tĂ« bashkĂ«veprojĂ« me API-nĂ« ose drejtpĂ«rdrejt ose pĂ«rmes kubectl. Ky Ă«shtĂ« zemra e asaj qĂ« e bĂ«n Kubernetes Kubernetes — truri qĂ« kthen malet e YAML-it, qĂ« tĂ« gjithĂ« e njohim dhe e duam (?), nĂ« njĂ« infrastrukturĂ« funksionale. Duket e qartĂ« se API duhet tĂ« jetĂ« pjesĂ« e konfiguracionit tonĂ« minimal.

Kushtet paraprake

  • NjĂ« makinĂ« virtuale ose fizike Linux me qasje root (unĂ« pĂ«rdor Ubuntu 18.04 nĂ« njĂ« makinĂ« virtuale).
  • Dhe ky Ă«shtĂ« gjithçka!

Instalimi i mërzitshëm

Në makinën që do të përdorim, është e nevojshme të instalojmë Docker. (Nuk kam ndërmend të flas në detaje se si funksionon Docker dhe kontejnerët; nëse jeni të interesuar, ka artikuj të shkëlqyer). Le të instalojmë thjesht atë me apt:

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

Pas kësaj, na nevojiten binarët e Kubernetes. Faktikisht, për fillimin e "klasterit" tonë, na nevojitet vetëm kubelet, pasi për të nisur komponentët e tjerë serverë, do të mund të përdorim kubelet. Për të ndërvepruar me klasterin tonë pasi ai të funksionojë, gjithashtu do të përdorim 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

ÇfarĂ« do tĂ« ndodhĂ« nĂ«se thjesht e ekzekutojmĂ« kubelet?

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

kubelet duhet të funksionojë nga root. Mjafton logjikisht, pasi ai duhet të menaxhojë të gjithë nyjën. Le të shohim parametrat e tij:

$ ./kubelet -h

$ ./kubelet -h | wc -l
284

Wow, sa shumë opsione! Fatmirësisht, na nevojiten vetëm disa prej tyre. Ja një nga parametrat që na intereson:

--pod-manifest-path string

Rruga për katalogun që përmban skedarët për podet statike, ose rruga për skedarin me përshkrimin e podëve statike. Skedarët që fillojnë me pika injorohen. (E vjetruar: ky parametr duhet të vendoset në skedarin e konfiguruar, që i kalon Kubelet përmes opsionit --config. Për informacion shtesë shih. kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)

Ky parametr na lejon të nisim podet statike - podet që nuk menaxhohen përmes API Kubernetes. Podet statike përdoren rrallë, por janë shumë të dobishme për ngritjen e shpejtë të klasterit, dhe kjo është ajo çfarë na nevojitet. Ne do të injorojmë këtë paralajmërim të fortë (sërish, mos e nisni këtë në prodhim!) dhe do të shohim nëse mund të nisim një pod.

Së pari, do të krijojmë një katalog për podet statike dhe do të nisim kubelet:

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

Pastaj, në një terminal tjetër/fenë tmux/ndonëse diku tjetër, do të krijojmë manifestin e podit:

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

kubelet fillon të shkruajë disa paralajmërime dhe duket se nuk po ndodh asgjë. Por nuk është kështu! Le të shohim Docker-in:

$ sudo docker ps -a
CONTAINER ID        IMAGE                  COMMAND                 CREATED             STATUS                      PORTS               NAMES
8c8a35e26663        busybox                "echo 'hello world!'"   36 sekonda më parë      Doli (0) 36 sekonda më parë                       k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
68f670c3c85f        k8s.gcr.io/pause:3.2   "/pause"                2 minuta më parë       Up 2 minuta                                    k8s_POD_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_0
$ sudo docker logs k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
hello world!

kubelet lexoi manifestin e pod-it dhe i dha Docker-it komandĂ«n pĂ«r tĂ« nisur disa konteinerĂ« sipas specifikimeve tona. (NĂ«se jeni tĂ« interesuar pĂ«r konteinerin “pause”, kjo Ă«shtĂ« njĂ« hile e Kubernetes — pĂ«r detaje shikoni nĂ« kĂ«tĂ« blog.) Kubelet do tĂ« nisĂ« konteinerin tonĂ« busybox me komandĂ«n e caktuar dhe do ta rindizĂ« atĂ« pafundĂ«sisht, derisa pod-i statik tĂ« fshihet.

Urime vetes. Ne sapo menduam një nga mënyrat më të komplikuara për të shfaqur tekst në terminal!

Nisni etcd

Qëllimi ynë përfundimtar është të nisni API-në e Kubernetes, por për këtë na nevojitet së pari të nisni etcd. Le të nisnim një klasër minimal etcd duke vendeosur konfigurimin e tij në katalogun pods (p.sh., 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

Nëse keni punuar ndonjëherë me Kubernetes, këto lloje YAML duhet të jenë të njohura për ju. Këtu do të theksojmë vetëm dy çështje:

Ne montuam dosjen e hostit /var/lib/etcd në pod, në mënyrë që të dhënat e etcd të ruhen pas rindizjes (nëse nuk e bëni këtë, gjendja e klasës do të fshihet me çdo rindizje të pod-it, gjë që nuk do të ishte mirë as për një instalim minimal të Kubernetes).

Ne konfiguruam hostNetwork: true. Ky parametrat, nuk është çudi, e konfiguronte etcd për të përdorur rrjetin e hostit në vend të rrjetit të brendshëm të pod-it (kjo do ta lehtësojë për API-serverin për të gjetur klasën etcd).

Një kontroll i thjeshtë tregon se etcd është vërtet i nisur 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 API-serverit

Nisja e API-serverit të Kubernetes është edhe më e thjeshtë. Parametri i vetëm që duhet të kalosh, --etcd-servers, bën atë që pritet:

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

Vendosni kĂ«tĂ« skedar YAML nĂ« katalogun pods, dhe API-serveri do tĂ« nisĂ«. Kontrolli me curl tregon se API i Kubernetes dĂ«gjon pĂ«r portin 8080 me qasje tĂ« plotĂ« — nuk kĂ«rkohet autentifikim!

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

(Përsëri, mos e nisni këtë në prodhim! Unë isha pak i çuditur që konfigurimi i parazgjedhur ishte kaq i pasigurt. Por supozoj se kjo është bërë për të lehtësuar zhvillimin dhe testimin.)

Dhe, një surprizë e këndshme, kubectl punon nga kutia pa asnjë konfigurim 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.

Problemi

Por nëse shkoni pak më thellë, duket se diçka nuk po shkon siç duhet:

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

Podi statik që krijuam ka humbur! Në të vërtetë, nodo kubelet nuk po zbulon fare:

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

ÇfarĂ« ndodhi? NĂ«se e mbani mend, disa paragrafĂ« mĂ« parĂ« ne po e drejtonim kubelet me njĂ« grup shumĂ« tĂ« thjeshtĂ« parametresh tĂ« linjĂ«s sĂ« komandĂ«s, ndaj kubelet nuk di si tĂ« lidhet me serverin API dhe ta njoftojĂ« atĂ« pĂ«r gjendjen e tij. Duke studiuar dokumentacionin, ne gjejmĂ« flamurin pĂ«rkatĂ«s:

--kubeconfig string

Rruga drejt skedarit kubeconfig, ku është përcaktuar si të lidhet me serverin API. Prania e tij --kubeconfig aktivizon modin e serverit API, mungesa e tij --kubeconfig aktivizon modin e autonomisë.

Në të gjithë këtë kohë, pa e ditur, ne kemi drejtuar kubelet në "modin autonom". (Nëse do të ishim të kujdesshëm, mund ta konsideronim modin autonom të kubelet si një "Kubernetes minimalisht i jetueshëm", por kjo do të ishte shumë e mërzitshme). Për të bërë të funksionojë konfigurimi "i vërtetë", na nevojitet të kalojmë skedarin kubeconfig në kubelet, që ai të di si të komunikoje me serverin API. Fatmirësisht, është mjaft e thjeshtë (pasi nuk kemi probleme me autentifikimin ose certifikatat):

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

Ruaj këtë si kubeconfig.yaml, vritni procesin kubelet dhe rini në funksion me parametrat e nevojshëm:

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

(Për më tepër, nëse provoni të qaseni në API nëpërmjet curl kur kubelet nuk funksionon, do të zbuloni se ai ende është aktiv! Kubelet nuk është *prindi* i pod-ëve të tij, si Docker; ai është më shumë si një "demon menaxhues". Kontejnerët e menaxhuar nga kubelet do të funksionojnë derisa kubelet t'i ndalojë.)

Pas disa minutash kubectl duhet të na tregojë pod-et dhe nyjat, ashtu siç e 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       21h   v1.18.5   10.70.10.228           Ubuntu 18.04.4 LTS   4.15.0-109-generic   docker://19.3.6

TĂ« festojmĂ« kĂ«tĂ« herĂ« me tĂ« vĂ«rtetĂ« (e di qĂ« kam festuar mĂ« parĂ«) — kemi krijuar njĂ« "kluster" minimal Kubernetes qĂ« funksionon me njĂ« API plotĂ«sisht funksionale!

Lançoni një pod

Tani do të shohim se çfarë mund të bëjë API-ja. Le të fillojmë me pod-in e nginx:

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

Këtu do të marrim një gabim mjaft interesant:

$ ./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 sa e paplotĂ« Ă«shtĂ« mjedisi ynĂ« Kubernetes — nuk kemi llogari shĂ«rbimi. Le tĂ« provojmĂ« pĂ«rsĂ«ri, duke krijuar manualisht njĂ« llogari shĂ«rbimi dhe tĂ« shohim ç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 manualisht një llogari shërbimi, tokeni i autentikimit nuk krijohet. Duke vazhduar eksperimentimin me "klusterin" tonë minimalistik, do të zbulojmë se shumica e gjërave të dobishme, të cilat zakonisht ndodhin automatikisht, nuk do të jenë të pranishme. Serveri Kubernetes API është mjaft minimalistik, shumica e konfigurimeve automatike të rënda ndodhin në kontrollet dhe detyrat e prapme që ende nuk janë duke funksionuar.

Mund ta kalojmë këtë problem duke vendosur opsionin automountServiceAccountToken për llogarinë e shërbimit (pasi në çdo rast nuk do ta përdorim):

$ 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, pod-i u shfaq! Por nĂ« tĂ« vĂ«rtetĂ« ai nuk do tĂ« nisĂ«, pasi nuk kemi planifikuesin (scheduler) — njĂ« tjetĂ«r komponent tĂ« rĂ«ndĂ«sishĂ«m tĂ« Kubernetes. PĂ«rsĂ«ri, ne shohim se API Kubernetes Ă«shtĂ« befasueshĂ«m "i pavĂ«mendshĂ«m" — kur krijoni njĂ« pod nĂ« API, ai e regjistron, por nuk pĂ«rpiqet tĂ« zbulojĂ« se nĂ« cilin nyje duhet ta niset.

Në të vërtetë, për të nisur një pod, nuk është i nevojshëm planifikuesi. Mund të shtoni me dorë një nyje në manifestin në parametrin nodeName:

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

(Zëvendësoni mink8s me emrin e nyjes.) Pas fshirjes dhe aplikimit ne shohim se nginx është aktiv dhe po dëgjon në adresën IP të brendshme:

$ ./kubectl fshi pod nginx
pod "nginx" u fshi
$ ./kubectl aplikoni -f nginx.yaml
pod/nginx u krijua
$ ./kubectl merrni pods -owide
EMRI    GATI   STATUSI    RIGJEN   MOSHA   IP           NODE     NODE I NOMINUAR   PORTAT E GATSHMERISE
nginx   1/1     Po funksionon   0          30s   172.17.0.2   mink8s   <none>           <none>
$ curl -s 172.17.0.2 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Mirë se erdhët në nginx!</title>

Për të siguruar se rrjeti midis pod-ëve funksionon siç duhet, mund të ekzekutojmë curl nga një pod tjetër:

$ 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>Mirë se erdhët në nginx!</title>

ËshtĂ« mjaft interesante tĂ« shqyrtojmĂ« kĂ«tĂ« mjedis dhe tĂ« shohim se çfarĂ« funksionon dhe çfarĂ« jo. Kam zbuluar se ConfigMap dhe Secret funksionojnĂ« siç pritet, ndĂ«rsa ShĂ«rbimi dhe Dispozita jo.

Sukses!

Ky post Ă«shtĂ« duke u bĂ«rĂ« i gjatĂ«, kĂ«shtu qĂ« do tĂ« shpall njĂ« fitore dhe do tĂ« deklaroj se kjo Ă«shtĂ« njĂ« konfigurim funksional, tĂ« cilin mund ta quajmĂ« “Kubernetes”. PĂ«rmbledhje: katĂ«r skedarĂ« binarĂ«, pesĂ« parametra tĂ« komandĂ«s dhe “vetĂ«m” 45 rreshta YAML (nuk Ă«shtĂ« shumĂ« sipas standardeve tĂ« Kubernetes) dhe na funksionojnĂ« disa gjĂ«ra:

  • Pod-et menaxhohen pĂ«rmes API standard tĂ« Kubernetes (me disa hile)
  • Mund tĂ« ngarkojmĂ« imazhe publike tĂ« konteinerĂ«ve dhe t'i menaxhojmĂ« ato
  • Pod-et mbijetojnĂ« dhe rinisin automatikisht
  • Rrjeti midis pod-Ă«ve nĂ« njĂ« nyje funksionon mjaft mirĂ«
  • ConfigMap, Secret dhe montimi mĂ« i thjeshtĂ« i ruajtjes funksionojnĂ« siç duhet

Por shumica e asaj që e bën Kubernetes vërtet të dobishëm, ende mungon, për shembull:

  • Planifikuesi i pod-ve
  • Autentikimi / autorizimi
  • PĂ«rmbajtje tĂ« shumĂ« nyjeve
  • Rrjeti i shĂ«rbimeve
  • DNS i brendshĂ«m tĂ« klasterit
  • Kontrolluesit pĂ«r llogaritĂ« e shĂ«rbimeve, implementimet, integrimin me ofruesit e mjeteve dhe shumicĂ«n e “thumbave” tĂ« tjerĂ« qĂ« sjell Kubernetes

ÇfarĂ« kemi marrĂ« nĂ« tĂ« vĂ«rtetĂ«? API i Kubernetes-it, duke funksionuar vetĂ«, nĂ« tĂ« vĂ«rtetĂ« Ă«shtĂ« vetĂ«m njĂ« platformĂ« pĂ«r automatizimin e kontejnerĂ«ve. Ai nuk bĂ«n shumĂ« - kjo Ă«shtĂ« punĂ« pĂ«r kontrollues tĂ« ndryshĂ«m dhe operatorĂ« qĂ« pĂ«rdorin API-nĂ«, - por ai siguron njĂ« ambient tĂ« qĂ«ndrueshĂ«m pĂ«r automatizimin.

Mëso më shumë rreth kursit në webinarin falas.

Lexo më shumë:

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster