Egia esateko, ez nago %100 ziur. Baina uste dut interesgarria dela barnean sakontzea eta Kubernetesen benetan gertatzen ari dena bere abstrakzio-geruza askoren azpian ikustea. Beraz, ondo pasatzeko, ikus dezagun nolakoa den gutxieneko “Kubernetes kluster” bat. (Hau baino askoz errazagoa izango da Kubernetes Bide gogorra.)
Kubernetes, Linux eta edukiontziei buruzko oinarrizko ezagutzak dituzula suposatzen dut. Hemen hitz egiten dugun guztia ikerketa/ikaskuntza helburuetarako soilik da, ez jarri produkzioan!
Обзор
Kubernetesek osagai asko ditu. Ren arabera Wikipedia, arkitekturak honela dauka:
Gutxienez zortzi osagai agertzen dira hemen, baina horietako gehienak alde batera utziko ditugu. Adierazi nahi dut arrazoiz Kubernetes deitu daitekeen gutxieneko gauza hiru osagai nagusi ditu:
kubelet
kube-apiserver (etcd-en araberakoa - bere datu-basea)
edukiontziaren exekuzio-denbora (Docker kasu honetan)
Ikus dezagun dokumentazioak zer dioen horietako bakoitzari buruz (rus., ingelesa.). Hasteko kubelet:
Klusterreko nodo bakoitzean exekutatzen den agente bat. Ontziak ontzian ibiltzen ari direla ziurtatzen du.
Nahikoa sinplea dirudi. Zer deritzozu edukiontzien exekuzio-denborak (edukiontziaren exekuzioa)?
Edukiontziaren exekuzio-denbora edukiontziak exekutatzeko diseinatutako programa da.
Oso informatzailea. Baina Docker ezagutzen baduzu, orduan zer egiten duen ideia orokorra izan beharko zenuke. (Edukiontziaren exekuzio-denboraren eta kubelet-aren arteko erantzukizunen banaketaren xehetasunak nahiko sotilak dira eta ez ditut hemen sartuko.)
И API zerbitzaria?
API Server Kubernetes APIa erakusten duen Kubernetes kontrol panelaren osagaia da. API zerbitzaria Kubernetes kontrol panelaren bezeroaren aldea da
Kubernetesekin ezer egin duen edonork APIarekin zuzenean edo kubectl bidez elkarreragin behar izan du. Hau da Kubernetes Kubernetes egiten duenaren muina: guztiok ezagutzen eta maite ditugun YAML mendiak (?) lan-azpiegitura bihurtzen dituen garuna. Bistan da APIa gure konfigurazio minimoan egon behar dela.
Aurrebaldintzak
Linux makina birtuala edo fisikoa root sarbidea duen (Ubuntu 18.04 erabiltzen ari naiz makina birtual batean).
Eta dena!
Instalazio aspergarria
Erabiliko dugun makinan Docker instalatu behar dugu. (Ez dut Docker eta edukiontziak nola funtzionatzen duten xehetasunetan sartuko; interesatzen bazaizu, hor dago artikulu zoragarriak). Besterik gabe, instalatu dezagun apt:
Horren ostean, Kubernetes bitarrak lortu behar ditugu. Izan ere, gure “kluster” hasierako abian jartzeko besterik ez dugu behar kubelet, erabil ditzakegun zerbitzariaren beste osagai batzuk exekutatzeko kubelet. Exekutatu ondoren gure klusterrekin elkarreragiteko ere erabiliko dugu kubectl.
kubelet root gisa exekutatu behar da. Nahiko logikoa, nodo osoa kudeatu behar baitu. Ikus ditzagun bere parametroak:
$ ./kubelet -h
<слишком много строк, чтобы разместить здесь>
$ ./kubelet -h | wc -l
284
Aupa, hainbeste aukera! Zorionez, pare bat besterik ez ditugu behar. Hona hemen interesatzen zaigun parametroetako bat:
--pod-manifest-path string
Pod estatikoen fitxategiak dituen direktoriorako bidea edo pod estatikoak deskribatzen dituen fitxategi baterako bidea. Puntuekin hasten diren fitxategiak ez dira aintzat hartzen. (GARAKITUTA: aukera hau Kubelet-era pasatzen den konfigurazio fitxategian ezarri behar da --config aukeraren bidez. Informazio gehiago lortzeko, ikus kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)
Aukera honek korrika egiteko aukera ematen digu leka estatikoak — Kubernetes APIaren bidez kudeatzen ez diren lekak. Leka estatikoak gutxitan erabiltzen dira, baina oso erosoak dira kluster bat azkar altxatzeko, eta horixe da behar duguna. Abisu handi honi jaramonik egingo diogu (berriz ere, ez exekutatu hau ekoizpenean!) eta ikusiko dugu poda martxan jartzen dugun.
Lehenik eta behin, pod estatikoetarako direktorio bat sortu eta exekutatu egingo dugu kubelet:
kubelet abisu batzuk idazten hasten da eta badirudi ez dela ezer gertatzen. Baina hori ez da egia! Ikus dezagun Dockerra:
$ 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 Pod manifestua irakurri nuen eta Dockerri ontzi pare bat abiarazteko agindua eman nion gure zehaztapenen arabera. («Pausa» edukiontziari buruz galdetzen bazaizu, Kubernetes hack bat da - ikusi blog hau.) Kubelet-ek gure edukiontzia kaleratuko du busybox zehaztutako komandoarekin eta mugagabe berrabiaraziko du pod estatikoa ezabatu arte.
Zorionak zeure buruari. Testua terminalera ateratzeko modu nahasgarrienetako bat sortu berri dugu!
Abiarazi etcd
Gure azken helburua Kubernetes APIa exekutatzea da, baina horretarako lehenik exekutatu behar dugu etab. Has dezagun gutxieneko etcd kluster bat bere ezarpenak pods direktorioan jarriz (adibidez, pods/etcd.yaml):
Inoiz Kubernetesekin lan egin baduzu, YAML fitxategi hauek ezagunak izan beharko zenuke. Hemen aipatzeko moduko bi puntu baino ez daude:
Ostalari karpeta muntatu dugu /var/lib/etcd pod-ean, etcd datuak berrabiarazi ondoren gorde daitezen (hau egiten ez bada, kluster-egoera ezabatuko da poda berrabiarazten den bakoitzean, eta hori ez da ona izango Kubernetes instalazio minimo baterako ere).
Instalatu dugu hostNetwork: true. Ezarpen honek, ez da harritzekoa, etcd konfiguratzen du ostalari-sarea erabiltzeko pod-aren barne-sarearen ordez (horrela erraztuko du API zerbitzariak etcd cluster-a aurkitzea).
Egiaztapen sinple batek erakusten du etcd lokalean exekutatzen ari dela eta datuak diskoan gordetzen:
$ 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
API zerbitzaria abiarazten
Kubernetes API zerbitzari bat exekutatzea are errazagoa da. Pasatu behar den parametro bakarra da --etcd-servers, espero duzuna egiten du:
Jarri YAML fitxategi hau direktorioan pods, eta API zerbitzaria hasiko da. -rekin egiaztatzen curl erakusten du Kubernetes APIa 8080 atakan entzuten ari dela sarbide guztiz irekiarekin - ez da autentifikaziorik behar!
(Berriro ere, ez exekutatu hau ekoizpenean! Harrituta geratu nintzen ezarpen lehenetsia hain segurua ez izateak. Baina uste dut hau garapena eta probak errazteko direla.)
Eta, sorpresa atsegina, kubectl-ek kutxatik kanpo funtzionatzen du ezarpen gehigarririk gabe!
$ ./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.
arazoa
Baina pixka bat sakontzen baduzu, badirudi zerbait gaizki doala:
$ ./kubectl get pod -n kube-system
No resources found in kube-system namespace.
Sortu ditugun lekak estatikoak desagertu dira! Izan ere, gure kubelet nodoa ez da batere aurkitu:
$ ./kubectl get nodes
No resources found in default namespace.
Zein da ba arazoa? Duela paragrafo batzuk gogoratzen badituzu, kubelet-a komando lerroko parametro multzo oso sinple batekin hasi genuen, beraz, kubelet-ek ez daki nola jarri harremanetan API zerbitzariarekin eta haren egoeraren berri eman. Dokumentazioa aztertu ondoren, dagokion bandera aurkituko dugu:
--kubeconfig string
Fitxategiaren bidea kubeconfig, API zerbitzariari nola konektatu zehazten duena. Eskuragarritasuna --kubeconfig API zerbitzari modua gaitzen du, ez --kubeconfig lineaz kanpoko modua gaitzen du.
Denbora honetan guztian, jakin gabe, kubelet-a " lineaz kanpoko moduan " exekutatzen ari ginen. (Pedanteak izango bagina, kubelet autonomo bat "gutxieneko Kubernetes bideragarri" dela pentsa genezake, baina hori oso aspergarria izango litzateke). Konfigurazio "benetakoa" funtziona dezan, kubeconfig fitxategia kubelet-era pasa behar dugu, API zerbitzariarekin hitz egiten jakin dezan. Zorionez, nahiko erraza da (ez baitugu autentifikazio- edo ziurtagiri-arazorik):
(Bide batez, kurl bidez APIra sartzen saiatzen bazara kubelet exekutatzen ez dagoenean, oraindik exekutatzen ari dela ikusiko duzu! Kubelet ez da Docker bezalako poden "gurasoa", "kontrol" baten antzekoa da. daemon.” Kubelet batek kudeatutako edukiontziak martxan jarraituko du kubeletak geldiarazi arte.)
Minutu gutxi barru kubectl lekak eta nodoak erakutsi behar dizkigute espero dugun moduan:
$ ./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
Benetan zoriondu gaitezen oraingoan (badakit dagoeneko zoriondu nintzela) - Kubernetes "kluster" minimo bat dugu API guztiz funtzional batekin!
azpian abiarazten dugu
Orain ikus dezagun zertarako gai den APIa. Has gaitezen nginx pod-arekin:
$ ./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.
Hemen ikusten dugu gure Kubernetes ingurunea zeinen oso osatugabea den: ez dugu zerbitzuetarako konturik. Saia gaitezen berriro eskuz zerbitzu-kontu bat sortuz eta ea zer gertatzen den:
$ 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
Zerbitzu-kontua eskuz sortu dugunean ere, autentifikazio-tokena ez da sortzen. Gure "kluster" minimalistarekin esperimentatzen jarraitzen dugun heinean, automatikoki gertatu ohi diren gauza baliagarri gehienak faltako direla ikusiko dugu. Kubernetes API zerbitzaria nahiko minimalista da, oraindik exekutatzen ez diren hainbat kontrolagailu eta atzeko lanetan gertatzen diren astuntasun eta konfigurazio automatiko gehienak.
Arazo honi aurre egin ahal izango diogu aukera ezarriz automountServiceAccountToken zerbitzu konturako (ez baitugu hala ere erabili beharko):
$ 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
Azkenik, leka agertu da! Baina egia esan ez da hasiko ez daukagulako planifikatzailea (planifikatzailea) Kubernetes-en beste osagai garrantzitsu bat da. Berriz ere, Kubernetes APIa harrigarriro "tontua" dela ikusten dugu; APIan Pod bat sortzen duzunean, erregistratzen du, baina ez da saiatzen zein nodotan exekutatu behar duen asmatzen.
Izan ere, ez duzu programatzailerik behar pod bat exekutatzeko. Nodo bat eskuz gehi dezakezu manifestuan parametroan nodeName:
(Ordezkatu mink8s nodoaren izenari.) Ezabatu eta aplikatu ondoren, nginx hasi dela eta barne IP helbidea entzuten ari dela ikusiko dugu:
$ ./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>
Poden arteko sarea ondo funtzionatzen duela ziurtatzeko, curl beste pod batetik exekutatu dezakegu:
$ 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>
Nahiko interesgarria da ingurune honetan sakontzea eta zer funtzionatzen duen eta zer ez ikustea. ConfigMap eta Secretek espero bezala funtzionatzen dutela ikusi nuen, baina Zerbitzuak eta Inplementazioak ez.
Arrakasta!
Post hau luzea egiten ari da, beraz, garaipena aldarrikatu eta "Kubernetes" deitu daitekeen konfigurazio bideragarria dela esango dut.Laburbilduz: lau bitar, bost komando lerroko parametro eta "soilik" YAML-ren 45 lerro (ez Kubernetes estandarren arabera) eta gauza dezente ditugu lanean:
Podak Kubernetes API arrunta erabiliz kudeatzen dira (hack batzuekin)
Edukiontzi publikoen irudiak igo eta kudea ditzakezu
Podek bizirik jarraitzen dute eta automatikoki berrabiarazi
Nodo bereko poden arteko sareak nahiko ondo funtzionatzen du
ConfigMap, biltegiratze sekretua eta sinplea muntatzen espero bezala funtzionatzen du
Baina Kubernetes benetan erabilgarria egiten duenaren zati handi bat falta da oraindik, hala nola:
Pod Scheduler
Autentifikazioa/baimena
Nodo anitz
Zerbitzuen sarea
Klusteratutako barne DNS
Zerbitzu-kontuetarako kontrolatzaileak, inplementazioak, hodeiko hornitzaileekin integratzeko eta Kubernetes-ek ekartzen dituen beste ontasun gehienak
Beraz, zer lortu dugu benetan? Kubernetes APIa, bere kabuz exekutatzen dena, benetan plataforma bat besterik ez da edukiontzien automatizazioa. Ez du asko egiten - APIa erabiltzen duten hainbat kontrolatzaile eta operadoreren lana da - baina automatizaziorako ingurune koherentea eskaintzen du.