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:
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:
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.
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:
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):
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, делает то, что вы ожидаете:
Asetage see YAML-fail kataloogi podsja API-server käivitub. Kontrollimine koos curl показывает, что Kubernetes API прослушивает порт 8080 с полностью открытым доступом — аутентификация не требуется!
(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):
(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:
$ ./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:
(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.