A cikk fordítása a kurzus megkezdése előtt készült .

Ha ezt olvasod, valószínűleg hallottál már a Kubernetesről (ha nem, akkor hogyan kerültél ide?). De mi is valójában a Kubernetes? Ez ? Или ? Что вообще это значит?
Őszintén szólva, nem vagyok 100%-ig biztos. De úgy gondolom, érdekes megnézni, hogy mi történik a Kubernetes mélyén, a sok absztrakciós réteg alatt. Szóval, az érdekesség kedvéért nézzük meg, hogy valójában hogyan néz ki a minimális „Kubernetes klaszter”. (Ez sokkal egyszerűbb lesz, mint .)
Feltételezem, hogy van némi alapvető ismereted a Kubernetesről, a Linuxról és a konténerekről. Az itt tárgyaltak mind csak kutatásra/megismerésre szolgálnak, ne futtass semmit ebből éles környezetben!
Áttekintés
A Kubernetes számos komponenst tartalmaz. A , az architektúra a következőképpen néz ki:

Itt legalább nyolc komponenst láthatunk, de a legtöbbet figyelmen kívül hagyjuk. Azt szeretném mondani, hogy a legkisebb dolog, amit érdemben Kubernetesnek lehet nevezni, három fő komponensből áll:
- kubelet
- kube-apiserver (mely az etcd-tól — az adatbázisától — függ)
- konténer futtatási környezet (jelen esetben Docker)
Nézzük meg, mit mond róluk a dokumentáció (., ). Először kubelet:
Ügynök, amely minden csomóponton működik a klaszterben. Figyelemmel kíséri, hogy a konténerek futnak-e a podban.
Ez elég egyszerűen hangzik. Mi a helyzet a konténer futtatási környezettel (container runtime)?
A konténer futtatási környezet egy olyan program, amely a konténerek végrehajtására szolgál.
Nagyon informatív. De ha ismered a Dockert, akkor valószínűleg van egy átfogó képed arról, hogy mit csinál. (A konténer futtatási környezet és a kubelet közötti felelősségmegosztás részletei valójában eléggé finomak, és itt nem fogok részletekbe bonyolódni.)
és API-szerver?
Az API-szerver a Kubernetes irányítópult egyik komponenstje, amely a Kubernetes API-t képviseli. Az API-szerver a Kubernetes irányítópult kliensoldali része
Bárkinek, aki valaha is foglalkozott a Kubernetes-szel, közvetlenül vagy a kubectl-en keresztül is kapcsolatba kellett lépnie az API-val. Ez annak a szíve, ami a Kubernetessé teszi a Kubernetist — az agy, ami a sok YAML-t, amit mindannyian ismerünk és szeretünk (?) működő infrastruktúrává alakít. Nyilvánvalónak tűnik, hogy az API-nak jelen kell lennie a minimális konfigurációnkban.
Előfeltételek
- Linux alapú virtuális vagy fizikai gép root hozzáféréssel (én az Ubuntu 18.04-et használom egy virtuális gépen).
- Ennyi az egész!
Unalmas telepítés
A használt gépre telepíteni kell a Dockert. (Nem fogom részletezni, hogyan működik a Docker és a konténerek; ha érdekel, vannak ). Telepítsük csak egyszerűen a következő parancsokkal: apt:
$ sudo apt install docker.io
$ sudo systemctl start docker Ezután meg kell szereznünk a Kubernetes bináris fájljait. Valójában az "klaszterünk" kezdeti elindításához csak kubelet, mivel a többi kiszolgáló komponens indításához használni tudjuk kubelet. A klaszterünkkel való interakcióhoz, miután az elindult, szintén használni fogjuk 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 Mi történik, ha csak elindítjuk kubelet?
$ ./kubelet
F0609 04:03:29.105194 4583 server.go:254] mkdir /var/lib/kubelet: permission denied kubelet root-tól kell futnia. Ez elég logikus, hiszen kezelnie kell az egész csomópontot. Nézzük meg a paramétereit:
$ ./kubelet -h
$ ./kubelet -h | wc -l
284Hű, mennyi opció! Szerencsére csak párra lesz szükségünk. Íme egy paraméter, ami érdekel minket:
--pod-manifest-path stringAz a könyvtár, amely tartalmazza a statikus podok fájljait, vagy statikus podok leíró fájljának elérési útja. A ponttal kezdődő fájlokat figyelmen kívül hagyják. (ELAVULT: ezt a paramétert a konfigurációs fájlban kell beállítani, amelyet a Kubelet-hez adunk át a --config opcióval. További információért lásd: .)
Ez a paraméter lehetővé teszi számunkra, hogy futtassuk — podokat, amelyeket nem a Kubernetes API kezel. A statikus podokat ritkán használják, de nagyon hasznosak a klaszter gyors elindításához, és éppen erre van szükségünk. Figyelmen kívül hagyjuk ezt a hangos figyelmeztetést (újra, ne futtassuk ezt éles környezetben!) és nézzük meg, tudunk-e podot indítani.
Először létrehozunk egy könyvtárat a statikus podok számára, és elindítjuk kubelet:
$ mkdir pods
$ sudo ./kubelet --pod-manifest-path=podsEzután egy másik terminálban/tmux ablakban/még valahol létrehozzuk a pod manifestet:
$ cat < pods/hello.yaml
apiVersion: v1
kind: Pod
metadata:
name: hello
spec:
containers:
- image: busybox
name: hello
command: ["echo", "hello world!"]
EOF kubelet Elkezdett figyelmeztetéseket írni, és úgy tűnik, hogy semmi sem történik. De ez nem igaz! Nézzük meg a Dockert:
$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c8a35e26663 busybox "echo 'hello world!'" 36 másodperce Leállítva (0) 36 másodperce k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
68f670c3c85f k8s.gcr.io/pause:3.2 " /pause" 2 perce Futtatva 2 perce k8s_POD_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_0
$ sudo docker logs k8s_hello_hello-mink8s_default_ab61ef0307c6e0dee2ab05dc1ff94812_4
hello world! kubelet Elolvastam a pod manifesztumot, és megadtam a Dockernek a parancsot, hogy indítsa el a konténereket a specifikációnk szerint. (Ha érdekli a "pause" konténer, az a Kubernetes trükkje - részletekért lásd a .) A Kubelet elindítja a konténereinket busybox a megadott paranccsal, és folyamatosan újraindítja, amíg a statikus pod el nem távolításra kerül.
Gratulálj magadnak. Éppen most találtuk ki az egyik legkényelmetlenebb módot a szöveg terminálba írására!
Indítjuk az etcd-t
A végső célunk a Kubernetes API indítása, de ehhez először el kell indítanunk . Indítsunk el egy minimalista etcd klasztert, a beállításokat a pods mappába helyezve (például, 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-dataHa valaha is dolgoztál Kubernetes-szel, akkor ezek a YAML fájlok ismerősek kell legyenek számodra. Itt csak két dolgot érdemes megemlíteni:
Monta a gazdagépet /var/lib/etcd a podba, hogy az etcd adatai megmaradjanak újraindítás után (ha ezt nem tesszük meg, a klaszter állapota törlődik a pod minden újraindítása során, ami még a Kubernetes minimális telepítése esetén is problémás lenne).
Beállítottuk hostNetwork: true. Ez a paraméter, ahogy várható volt, beállítja az etcd-t, hogy a gazdagép hálózatát használja a pod belső hálózata helyett (ez megkönnyíti az API szerver számára az etcd klaszter megtalálását).
Egy egyszerű ellenőrzés azt mutatja, hogy az etcd valóban a localhost-on fut és adatokat tárol a lemezen:
$ 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.walAPI szerver indítása
A Kubernetes API-szerver indítása még egyszerűbb. Az egyetlen paraméter, amit át kell adni, --etcd-servers, az pontosan azt csinálja, amit vársz:
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 Helyezd el ezt a YAML fájlt a pods, könyvtárba, és az API-szerver elindul. Ellenőrzés a curl megmutatja, hogy a Kubernetes API a 8080-as portot hallgatja, teljesen nyitott hozzáféréssel — nincs szükség hitelesítésre!
$ curl localhost:8080/healthz
ok
$ curl localhost:8080/api/v1/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/pods",
"resourceVersion": "59"
},
"items": []
}(Ismétlem, ne indítsd el ezt éles környezetben! Kicsit meglepett, hogy az alapértelmezett beállítások ennyire nem biztonságosak. De azt feltételezem, hogy ezt a fejlesztés és a tesztelés megkönnyítése érdekében tették.)
És, kellemes meglepetés, a kubectl dobozból működik, további beállítások nélkül!
$ ./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.Probléma
De ha kicsit mélyebbre ásunk, úgy tűnik, hogy valami nem stimmel:
$ ./kubectl get pod -n kube-system
No resources found in kube-system namespace.A statikus podok, amiket létrehoztunk, eltűntek! Valójában a kubelet csomópontunk egyáltalán nem észlelhető:
$ ./kubectl get nodes
No resources found in default namespace.Mi folyik itt? Ha emlékszel, néhány bekezdéssel ezelőtt a kubelet-et egy rendkívül egyszerű parancssori beállítással indítottuk, így a kubelet nem tudja, hogyan kell kapcsolatba lépni az API-szerverrel és értesíteni azt az állapotáról. A dokumentációtanulmányozásával megtaláljuk a megfelelő flag-et:
--kubeconfig string
Az API-szerverhez való kapcsolódást leíró fájl elérési útja. kubeconfigJelenléte --kubeconfig aktiválja az API-szerver módot, míg a hiánya --kubeconfig önálló módot aktivál.
Mialatt mi erről nem tudtunk, a kubelet-et «autonóm üzemmódban» futtattuk. (Ha pedánsak lennénk, akkor az autonóm kubelet üzemmódot tekinthetnénk mint «minimum életképes Kubernetes»-t, de ez nagyon unalmas lenne). Ahhoz, hogy a «valódi» konfiguráció működjön, át kell adnunk a kubeconfig fájlt a kubelet-nek, hogy tudja, hogyan kommunikáljon az API-szerverrel. Szerencsére ez elég egyszerű (mivel nincsenek hitelesítési vagy tanúsítványi problémáink):
apiVersion: v1
kind: Config
clusters:
- cluster:
server: http://127.0.0.1:8080
name: mink8s
contexts:
- context:
cluster: mink8s
name: mink8s
current-context: mink8s Mentse el ezt mint kubeconfig.yaml, állítsa le a folyamatot kubelet és indítsa újra a szükséges paraméterekkel:
$ sudo ./kubelet --pod-manifest-path=pods --kubeconfig=kubeconfig.yaml(Egyébként, ha megpróbálja megközelíteni az API-t curl-lel, amikor a kubelet nem fut, akkor rájön, hogy a kubelet még mindig működik! A kubelet nem a podjai «szülője», inkább hasonlít egy “kezelő démonra”. A kubelet által vezérelt konténerek működnek, amíg a kubelet nem állítja le őket.)
Néhány perc múlva kubectl látnunk kellene a podokat és a csomópontokat, ahogy várjuk:
$ ./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.6Most igazán gratuláljunk magunknak (tudom, már gratuláltam) — létrehoztuk a legkisebb «Kubernetes» klasztert, amely teljes funkciós API-val működik!
Indítunk egy podot
Most nézzük meg, mire képes az API. Kezdjük az nginx poddal:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginxItt egy meglehetősen érdekes hibát fogunk kapni:
$ ./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.Itt láthatjuk, mennyire borzasztóan hiányos a Kubernetes környezetünk — nincsenek szolgáltatásfiókjaink. Próbáljuk meg újra, és manuálisan hozzunk létre egy szolgáltatásfiókot, hogy lássuk, mi történik:
$ 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 accountMég akkor is, ha manuálisan létrehoztuk a szolgáltatásfiókot, az autentikációs token nem jön létre. Tovább kísérletezve minimalista „klaszterünkkel”, felfedezzük, hogy a legtöbb hasznos dolog, ami általában automatikusan történik, hiányozni fog. A Kubernetes API szerver meglehetősen minimalista, a legtöbb nehéz automatikus beállítás különféle vezérlőkben és háttérfeladatokban történik, amelyek még nem futnak.
Ezt a problémát megkerülhetjük azzal, hogy beállítjuk az opciót automountServiceAccountToken a szolgáltatásfiók számára (mivel úgysem fogjuk használni):
$ 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 13mVégre megjelent a pod! De valójában nem fog elindulni, mivel nincs (scheduler) — a Kubernetes egy másik fontos összetevője. Ismét csak azt látjuk, hogy a Kubernetes API meglepően „buta” — amikor egy podot létrehoz a API-ban, regisztrálja, de nem próbálja kideríteni, hogy melyik csomóponton kell futtatni.
Valójában az ütemező nem szükséges a pod elindításához. Kézzel csomópontot is hozzáadhat a manifesthez a következő paraméterrel: nodeName:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
nodeName: mink8s
(Cserélje a következőt: mink8s a csomópont nevére.) A delete és apply után azt látjuk, hogy az nginx elindult és figyeli a belső IP-címet:
$ .\/kubectl delete pod nginx
pod "nginx" törölve
$ .\/kubectl apply -f nginx.yaml
pod/nginx létrehozva
$ .\/kubectl get pods -owide
NÉV KÉSZ ÁLLAPOT ÚJRAINDÍTÁSOK KOR IP CSOMÓPONT JELÖLT CSOMÓPONT KÉSZÜLTSÉGI KAPUK
nginx 1\/1 Futtatás 0 30s 172.17.0.2 mink8s <none> <none>
$ curl -s 172.17.0.2 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Üdvözöljük az nginx-et!</title>Azt, hogy a podok közötti hálózat megfelelően működik, egy másik podból futtatott curl-lal tudjuk ellenőrizni:
$ cat <<EOS | .\/kubectl apply -f -\napiVersion: v1\nkind: Pod\nmetadata:\n name: curl\nspec:\n containers:\n - image: curlimages\/curl\n name: curl\n command: ["curl", "172.17.0.2"]\n nodeName: mink8s\nEOS\npod\/curl created\n$ .\/kubectl logs curl | head -6\n % Teljes % Fogadott % Átvitel Átlagos Sebesség Idő Idő Idő Aktuális\n Letöltés Feltöltés Összes Elköltött Balra Sebesség
<!DOCTYPE html>
<html>
<head>
<title>Üdvözöljük az nginx-et!</title>Eléggé érdekes ezen a környezetben turkálni és megnézni, mi működik, és mi nem. Felfedeztem, hogy a ConfigMap és a Secret a várakozásoknak megfelelően működik, míg a Service és a Deployment nem.
Siker!
Ez a bejegyzés meglehetősen hosszúra sikerült, ezért be fogom jelenteni a győzelmet, és azt állítom, hogy ez egy működőképes konfiguráció, amit „Kubernetes”-nek hívhatunk. Összefoglalva: négy bináris fájl, öt parancssori opció és „csak” 45 sor YAML (Kubernetes szabványok szerint nem túl sok), és már működik is néhány dolog:
- A podokat a normál Kubernetes API (néhány hackkel) kezeli.
- Publikus konténerképeket lehet feltölteni és kezelni.
- A podok életben maradnak és automatikusan újraindulnak.
- A podok közötti hálózat egy csomóponton belül elég jól működik.
- A ConfigMap, Secret és az egyszerű tárolók csatlakoztatása rendben működik.
De a Kubernetes valódi hasznosságához szükséges dolgok többsége még hiányzik, például:
- Pod ütemező.
- Hitelesítés / engedélyezés.
- Több csomópont.
- Szolgáltatások hálózata.
- Klaszterbeli belső DNS.
- Szolgáltatásfiókok, telepítések, felhőszolgáltatókkal való integráció és sok más 'kényelem' vezérlői, amelyet a Kubernetes hoz.
De mit is kaptunk valójában? A Kubernetes API, amely önállóan működik, valójában csak egy platform az konténerek automatizálásához.Nem sok mindent csinál — ez a különböző vezérlők és operátorok feladata, akik az API-t használják — de biztosít egy konzisztens környezetet az automatizáláshoz.
Olvass tovább:
Forrás: habr.com
