Gutxieneko Kubernetes Bideragarriak

Ikastaroa hasi bezperan prestatu zen artikuluaren itzulpena "DevOps praktikak eta tresnak".

Gutxieneko Kubernetes Bideragarriak

Hau irakurtzen ari bazara, ziurrenik Kubernetes-i buruz zerbait entzun duzu (eta hala ez bada, nola iritsi zara hemen?) Baina zer da zehazki Kubernetes? Hau "Industria-mailako edukiontzien orkestrazioa"? Edo "Hodeiaren jatorrizko sistema eragilea"? Zer esan nahi du horrek?

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:

Gutxieneko Kubernetes Bideragarriak

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:

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

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.

$ 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

Zer gertatzen da korrika egiten badugu kubelet?

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

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:

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

Ondoren, beste terminal/tmux leiho batean/edozertan, pod manifest bat sortuko dugu:

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

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):

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

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:

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

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!

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

(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):

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

Gorde hau honela kubeconfig.yaml, prozesua hil kubelet eta berrabiarazi beharrezko parametroekin:

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

(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:

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

Hemen akats interesgarri samarra jasoko dugu:

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

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

(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.

Lortu informazio gehiago ikastaroari buruz doako webinar-ean.

Irakurri gehiago:

Iturria: www.habr.com

Gehitu iruzkin berria