Minimaalne elujõuline Kubernetes

Artikli tõlge valmis kursuse alguse eelõhtul "DevOpsi tavad ja tööriistad".

Minimaalne elujõuline Kubernetes

Kui sa seda loed, oled ilmselt midagi Kubernetesest kuulnud (ja kui ei, siis kuidas sa siia sattusid?) Aga mis Kubernetes täpselt on? See "Tööstusliku kvaliteediga konteinerite orkestreerimine"? Või "Cloud-native operatsioonisüsteem"? Mida see üldse tähendab?

Ausalt öeldes pole ma 100% kindel. Kuid ma arvan, et on huvitav süveneda sisemusse ja näha, mis Kubernetesis selle paljude abstraktsioonikihtide all tegelikult toimub. Nii et nalja pärast vaatame, kuidas minimaalne Kubernetese klaster tegelikult välja näeb. (See on palju lihtsam kui Kubernetes raske tee.)

Eeldan, et teil on põhiteadmised Kubernetese, Linuxi ja konteinerite kohta. Kõik, millest me siin räägime, on ainult uurimise/õppe eesmärgil, ärge pange sellest midagi tootmisse!

Vaadata

Kubernetes содержит много компонент. Согласно Vikipeedia, arhitektuur näeb välja selline:

Minimaalne elujõuline Kubernetes

Siin on näidatud vähemalt kaheksa komponenti, kuid me jätame enamiku neist tähelepanuta. Tahan öelda, et minimaalne asi, mida võib mõistlikult nimetada Kubernetesiks, koosneb kolmest põhikomponendist:

  • kubelet
  • kube-apiserver (который зависит от etcd — его базы данных)
  • среда выполнения контейнера (в данном случае Docker)

Vaatame, mida dokumentatsioon nende kõigi kohta ütleb (rus., Inglise.). Esiteks kubelet:

Agent, mis töötab klastri igas sõlmes. See tagab, et konteinerid töötavad kaunas.

Kõlab piisavalt lihtsalt. Kuidas oleks konteineri tööajad (konteineri tööaeg)?

Среда выполнения контейнера — это программа, предназначенная для выполнения контейнеров.

Очень информативно. Но если вы знакомы с Docker, то у вас должно быть общее представление о том, что он делает. (Детали разделения ответственностей между средой выполнения контейнеров и kubelet на самом деле довольно тонкие и здесь я не буду в них углубляться.)

И API server?

Сервер API — компонент Kubernetes панели управления, который представляет API Kubernetes. API-сервер — это клиентская часть панели управления Kubernetes

Igaüks, kes on kunagi Kubernetesega midagi teinud, on pidanud API-ga suhtlema kas otse või kubectli kaudu. See on selle süda, mis teeb Kubernetes Kubernetes – aju, mis muudab meile kõigile tuttavad ja armastatud (?) YAMLi mäed toimivaks infrastruktuuriks. Näib ilmselge, et API peaks olema meie minimaalses konfiguratsioonis.

Eeltingimused

  • Виртуальная или физическая машина Linux с root-доступом (я использую Ubuntu 18.04 на виртуальной машине).
  • Ja see on ka kõik!

Скучная установка

Peame Dockeri installima kasutatavasse masinasse. (Ma ei hakka Dockeri ja konteinerite tööpõhimõtteid üksikasjalikult kirjeldama; kui olete huvitatud, siis on imelised artiklid). Installime selle lihtsalt koos apt:

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

Pärast seda peame hankima Kubernetese kahendfailid. Tegelikult vajame oma "klastri" esmaseks käivitamiseks ainult kubelet, kuna teiste serverikomponentide käitamiseks saame kasutada kubelet. Klastriga suhtlemiseks pärast selle käitamist kasutame ka 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

Mis juhtub, kui me lihtsalt jookseme kubelet?

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

kubelet должен работать от root. Достаточно логично, так как ему надо управлять всем узлом. Давайте посмотрим на его параметры:

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

Vau, nii palju võimalusi! Õnneks vajame neid vaid paari. Siin on üks meid huvitavatest parameetritest:

--pod-manifest-path string

Tee staatiliste kaustade faile sisaldava kataloogi või staatilisi kaustasid kirjeldava faili tee. Punktidega algavaid faile ignoreeritakse. (AEGUNUD: see suvand tuleb määrata konfiguratsioonifailis, mis edastatakse Kubeletile võtmega --config. Lisateabe saamiseks vt kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)

See valik võimaldab meil käivitada staatilised kaunad — поды, которые не управляются через Kubernetes API. Статические поды используются редко, но они очень удобны для быстрого поднятия кластера, а это именно то, что нам нужно. Мы проигнорируем это громкое предупреждение (опять же, не запускайте это в проде!) и посмотрим, сможем ли мы запустить под.

Kõigepealt loome staatiliste kaunade jaoks kataloogi ja käivitame kubelet:

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

Seejärel loome teises terminali/tmuxi aknas/mis iganes pod-manifesti:

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

kubelet начинает писать какие-то предупреждения и кажется, что ничего не происходит. Но это не так! Давайте посмотрим на 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 Lugesin podmanifesti ja andsin Dockerile käsu käivitada paar konteinerit vastavalt meie spetsifikatsioonidele. (Kui teid huvitab "paus" konteiner, on see Kubernetese häkk - vt see blogi.) Kubelet käivitab meie konteineri busybox määratud käsuga ja taaskäivitab selle määramata ajaks, kuni staatiline pod kustutatakse.

Õnnitle ennast. Leidsime just ühe kõige segasema viisi teksti terminali väljastamiseks!

Käivita jne

Meie lõppeesmärk on käivitada Kubernetes API, kuid selleks peame kõigepealt käivitama jne. Alustame minimaalse etcd klastri loomist, asetades selle sätted kaustade kataloogi (näiteks 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

Kui olete kunagi Kubernetesiga töötanud, peaksid need YAML-failid teile tuttavad olema. Siin on ainult kaks tähelepanekut:

Мы смонтировали папку хоста /var/lib/etcd в под, чтобы данные etcd сохранялись после перезапуска (если этого не сделать, то состояние кластера будет стираться при каждом перезапуске пода, что будет нехорошо даже для минимальной установки Kubernetes).

Oleme installinud hostNetwork: true. See säte ei ole üllatav, et etcd konfigureerib serveri sisevõrgu asemel hostvõrku (see hõlbustab API serveril etcd klastri leidmist).

Lihtne kontroll näitab, et etcd töötab tõepoolest localhostis ja salvestab andmed kettale:

$ 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 serveri käivitamine

Kubernetes API serveri käitamine on veelgi lihtsam. Ainus parameeter, mis tuleb edastada, on --etcd-servers, делает то, что вы ожидаете:

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

Asetage see YAML-fail kataloogi podsja API-server käivitub. Kontrollimine koos curl показывает, что Kubernetes API прослушивает порт 8080 с полностью открытым доступом — аутентификация не требуется!

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

(Jällegi, ärge käivitage seda tootmisrežiimis! Olin veidi üllatunud, et vaikesäte on nii ebakindel. Kuid ma arvan, et see on arendamise ja testimise hõlbustamiseks.)

Ja meeldiv üllatus, kubectl töötab karbist välja ilma lisaseadeteta!

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

probleem

Kuid kui natukene süveneda, tundub, et midagi läheb valesti:

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

Meie loodud staatilised kaunad on kadunud! Tegelikult ei avastata meie kubeleti sõlme üldse:

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

Mis viga? Kui mäletate mõnda lõiku tagasi, käivitasime kubeleti äärmiselt lihtsa käsurea parameetrite komplektiga, nii et kubelet ei tea, kuidas API-serveriga ühendust võtta ja seda oma olekust teavitada. Pärast dokumentatsiooni uurimist leiame vastava lipu:

--kubeconfig string

Faili tee kubeconfig, mis määrab, kuidas luua ühendus API serveriga. Kättesaadavus --kubeconfig lubab API serveri režiimi, nr --kubeconfig lubab võrguühenduseta režiimi.

Kogu selle aja, ilma seda teadmata, käitasime kubeletti võrguühenduseta režiimis. (Kui oleksime pedantsed, võiksime mõelda eraldiseisvast kubeletist kui "minimaalselt elujõulisest Kubernetesest", kuid see oleks väga igav). "Päris" konfiguratsiooni toimimiseks peame edastama kubeconfig-faili kubeletile, et see teaks, kuidas API-serveriga suhelda. Õnneks on see üsna lihtne (kuna meil pole autentimise ega sertifikaadiga probleeme):

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

Salvestage see nimega kubeconfig.yaml, убейте процесс kubelet ja taaskäivitage vajalike parameetritega:

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

(Muide, kui proovite pääseda API-le curli kaudu, kui kubelet ei tööta, näete, et see töötab endiselt! Kubelet ei ole oma kaustade "vanem" nagu Docker, vaid pigem "juhtseade". deemon.” Kubeleti hallatavad konteinerid jätkavad töötamist, kuni kubelet need peatab.)

Mõne minuti pärast kubectl peaks näitama meile kaunasid ja sõlme, nagu me ootame:

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

Õnnitleme ennast seekord tõesti (ma tean, et õnnitlesin ennast juba) – meil on minimaalne Kubernetese "klaster", mis töötab täielikult toimiva API-ga!

Käivitame all

Nüüd vaatame, milleks API on võimeline. Alustame nginx podiga:

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

Siin saame üsna huvitava vea:

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

Siin näeme, kui kahetsusväärselt puudulik on meie Kubernetese keskkond – meil pole teenuste jaoks kontosid. Proovime uuesti, luues teenusekonto käsitsi ja vaatame, mis juhtub.

$ 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

Isegi kui lõime teenusekonto käsitsi, ei genereerita autentimisluba. Kui jätkame oma minimalistliku "klastriga" katsetamist, avastame, et enamik kasulikke asju, mis tavaliselt toimuvad automaatselt, on puudu. Kubernetes API-server on üsna minimalistlik, suurem osa raskete tõstetööde ja automaatse seadistamise toimingutest toimub erinevates kontrollerites ja taustatöödes, mis veel ei tööta.

Saame sellest probleemist mööda minna, määrates valiku automountServiceAccountToken teenusekonto jaoks (kuna me ei pea seda niikuinii kasutama):

$ 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

Lõpuks ometi on kaun ilmunud! Aga tegelikult see ei käivitu, sest meil pole planeerija (plaanija) on veel üks oluline Kubernetese komponent. Jällegi näeme, et Kubernetes API on üllatavalt "rumal" – kui loote API-s Podi, registreerib see selle, kuid ei püüa aru saada, millises sõlmes seda käivitada.

На самом деле для запуска пода планировщик не нужен. Можно вручную добавить узел в манифест в параметре nodeName:

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

(Asenda mink8s sõlme nimele.) Pärast kustutamist ja rakendamist näeme, et nginx on käivitunud ja kuulab sisemist IP-aadressi:

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

Veendumaks, et kaustadevaheline võrk töötab õigesti, saame curli käivitada teisest kaustast:

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

Довольно интересно покопаться в этом окружении и посмотреть, что работает, а что нет. Я обнаружил, что ConfigMap и Secret работают так, как и ожидается, а Service и Deployment нет.

Edu!

See postitus läheb pikaks, seega kuulutan välja võidu ja ütlen, et see on elujõuline konfiguratsioon, mida võib nimetada "Kubernetes". Kokkuvõtteks: neli binaarfaili, viis käsurea parameetrit ja "ainult" 45 rida YAML-i (mitte Kubernetese standardite järgi nii palju) ja meil on üsna palju asju, mis töötavad:

  • Podisid hallatakse tavalise Kubernetes API abil (mõne häkkimisega)
  • Saate avaliku konteineri pilte üles laadida ja hallata
  • Kaubad jäävad ellu ja käivituvad automaatselt
  • Võrgustiku loomine sama sõlme kaunade vahel toimib üsna hästi
  • ConfigMap, Secret и простейшее монтирование хранилищ работает как положено

Kuid palju sellest, mis teeb Kubernetes tõeliselt kasulikuks, on endiselt puudu, näiteks:

  • Podi ajakava
  • Autentimine/volitamine
  • Mitu sõlme
  • Teenuste võrgustik
  • Кластерный внутренний DNS
  • Контроллеры для учетных записей служб, развертываний, интеграции с облачными провайдерами и большинство других “плюшек”, которые приносит Kubernetes

Mida me siis tegelikult saime? Kubernetes API, mis töötab iseseisvalt, on tegelikult vaid platvorm konteinerite automatiseerimine. See ei tee palju – see on töö erinevatele API-d kasutavatele kontrolleritele ja operaatoritele –, kuid see tagab automatiseerimiseks ühtse keskkonna.

Узнать подробнее о курсе на бесплатном вебинаре.

Loe rohkem:

Allikas: www.habr.com

Lisa kommentaar