Překlad článku byl vyhotoven před začátkem kurzu .

Pokud to čtete, pravděpodobně jste už něco slyšeli o Kubernetes (a pokud ne, jak jste se sem dostali?). Ale co vlastně Kubernetes je? To je ? Или ? Что вообще это значит?
Upřímně řečeno, nejsem si tím úplně jistý. Ale myslím, že je zajímavé nahlédnout pod pokličku a podívat se, co se vlastně děje v Kubernetes pod jeho mnoha vrstvami abstrakce. Takže pro zajímavost, pojďme se podívat, jak vlastně vypadá minimální "Kubernetes cluster". (Bude to mnohem jednodušší než .)
Předpokládám, že máte základní znalosti o Kubernetes, Linuxu a kontejnerech. Vše, co zde budeme řešit, je určeno pouze k exploraci / studiu, nespouštějte to v produkci!
Přehled
Kubernetes obsahuje mnoho komponent. Podle , architektura vypadá takto:

Zde je zobrazeno minimálně osm komponent, ale většinu z nich ignorujeme. Chci prohlásit, že minimální věc, kterou lze rozumně nazvat Kubernetes, se skládá ze tří hlavních komponent:
- kubelet
- kube-apiserver (který závisí na etcd — jeho databázi)
- runtime kontejnerů (v tomto případě Docker)
Podívejme se, co říká dokumentace o každém z nich (., .). Nejprve kubelet:
Agent běžící na každém uzlu v clusteru. Sleduje, aby byly kontejnery spuštěny v podu.
Zní to docela jednoduše. Co říkáte na runtime kontejnerů (container runtime)?
Runtime kontejnerů je program určený k provádění kontejnerů.
Velmi informativní. Ale pokud znáte Docker, měli byste mít obecnou představu o tom, co dělá. (Detaily rozdělení zodpovědností mezi runtime kontejnerů a kubelet jsou ve skutečnosti docela jemné a zde se do nich nebudu hlouběji pouštět.)
A API server?
API server je komponenta ovládacího panelu Kubernetes, která představuje API Kubernetes. API server je klientská část ovládacího panelu Kubernetes.
Každý, kdo někdy pracoval s Kubernetes, musel interagovat s API buď přímo, nebo prostřednictvím kubectl. To je srdce toho, co dělá Kubernetes Kubernetes – mozek, který převádí hory YAML, které všichni známe a máme rádi (?), na fungující infrastrukturu. Zdá se samozřejmé, že API by mělo být součástí naší minimální konfigurace.
Předpoklady
- Virtuální nebo fyzický stroj s Linuxem s root přístupem (používám Ubuntu 18.04 na virtuálním stroji).
- A to je vše!
Nudná instalace
Na stroj, který budeme používat, je potřeba nainstalovat Docker. (Nebudu podrobně vysvětlovat, jak Docker a kontejnery fungují; pokud vás to zajímá, existují ). Pojďme jej prostě nainstalovat pomocí apt:
$ sudo apt install docker.io
$ sudo systemctl start docker Poté potřebujeme získat binární soubory Kubernetes. Ve skutečnosti pro počáteční spuštění našeho "clusteru" potřebujeme pouze kubelet, protože pro spuštění dalších serverových komponent budeme moci použít kubelet. Pro interakci s naším clusterem, jakmile začne fungovat, také použijeme 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 Co se stane, když jednoduše spustíme kubelet?
$ ./kubelet
F0609 04:03:29.105194 4583 server.go:254] mkdir /var/lib/kubelet: permission denied kubelet musí běžet jako root. To dává smysl, protože musí ovládat celý uzel. Podívejme se na jeho parametry:
$ ./kubelet -h
$ ./kubelet -h | wc -l
284
Wow, kolik možností! Naštěstí budeme potřebovat pouze pár z nich. Zde je jeden z parametrů, který nás zajímá:
--pod-manifest-path stringCesta k adresáři obsahujícímu soubory pro statické pody, nebo cesta k souboru s popisem statických podů. Soubory začínající tečkami jsou ignorovány. (ZASTARALÉ: tento parametr by měl být nastaven v konfiguračním souboru, který je předáván Kubeletu prostřednictvím parametru —config. Pro další informace viz. .)
Tento parametr nám umožňuje spouštět — pody, které nejsou spravovány prostřednictvím Kubernetes API. Statické pody se používají zřídka, ale jsou velmi užitečné pro rychlou konfiguraci klastru, což je přesně to, co potřebujeme. To hlučné varování ignorujeme (opět, nespouštějte to v produkci!) a podíváme se, zda dokážeme spustit pod.
Nejprve vytvoříme adresář pro statické pody a spustíme kubelet:
$ mkdir pods
$ sudo ./kubelet --pod-manifest-path=podsPoté v jiném terminálu/okně tmux/někde jinde vytvoříme manifest podu:
$ cat < pods/hello.yaml
apiVersion: v1
kind: Pod
metadata:
name: hello
spec:
containers:
- image: busybox
name: hello
command: ["echo", "hello world!"]
EOF kubelet začne psát nějaká varování a zdá se, že se nic neděje. Ale to není pravda! Podívejme se na 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 přečetl manifest podu a dal Dockeru příkaz spustit pár kontejnerů v souladu s naší specifikací. (Pokud vás zajímají kontejner “pause”, je to hack Kubernetes — podrobnosti najdete v .) Kubelet spustí náš kontejner busybox s uvedeným příkazem a bude jej neustále restartovat, dokud nebude statický pod odstraněn.
Pogratulujte si. Právě jsme vymysleli jeden z nejzmatečnějších způsobů, jak zobrazit text v terminálu!
Spouštíme etcd
Naším konečným cílem je spustit Kubernetes API, ale pro to nejprve musíme spustit . Pojďme spustit minimální klastr etcd tím, že jeho konfiguraci umístíme do adresáře pods (např., 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-dataPokud jste někdy pracovali s Kubernetes, měly by vám být podobné YAML soubory známé. Zde je třeba zdůraznit pouze dvě věci:
Připojili jsme složku hostitele /var/lib/etcd v podu, aby data etcd byla uložena po restartu (pokud to neuděláte, stav klastru bude vymazán při každém restartu podu, což není dobré ani pro minimální instalaci Kubernetes).
Nainstalovali jsme hostNetwork: true. Tento parametr, jak se dalo očekávat, nastavuje etcd pro použití sítě hostitele místo vnitřní sítě podu (usnadní to API serveru vyhledávání klastru etcd).
Jednoduchá kontrola ukazuje, že etcd skutečně běží na localhost a ukládá data na disk:
$ 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.walSpuštění API serveru
Spustit API server Kubernetes je ještě jednodušší. Jediný parametr, který musíte zadat, --etcd-servers, dělá to, co očekáváte:
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 Umístěte tento YAML soubor do adresáře pods, a API server se spustí. Ověření pomocí curl ukazuje, že Kubernetes API naslouchá na portu 8080 s plným přístupem — autentizace není vyžadována!
$ curl localhost:8080/healthz
ok
$ curl localhost:8080/api/v1/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/pods",
"resourceVersion": "59"
},
"items": []
}(Opět, nespouštějte to v produkčním prostředí! Byl jsem trochu překvapen, že výchozí nastavení je tak nebezpečné. Ale předpokládám, že to bylo uděláno pro usnadnění vývoje a testování.)
A, příjemné překvapení, kubectl funguje ihned bez jakýchkoliv dalších nastavení!
$ ./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ém
Ale pokud se podíváte hlouběji, vypadá to, že něco není v pořádku:
$ ./kubectl get pod -n kube-system
No resources found in kube-system namespace.Statické pody, které jsme vytvořili, zmizely! Ve skutečnosti náš kubelet uzel vůbec není detekován:
$ ./kubectl get nodes
No resources found in default namespace.Co se děje? Pokud si vzpomenete, před několika odstavci jsme spouštěli kubelet s velmi jednoduchou sadou parametrů příkazového řádku, takže kubelet neví, jak se připojit k API serveru a informovat ho o svém stavu. Po prostudování dokumentace nacházíme příslušnou vlajku:
--kubeconfig string
Cesta k souboru kubeconfig, ve kterém je uvedeno, jak se připojit k API serveru. Mít --kubeconfig zapíná mód API serveru, absence --kubeconfig zapíná autonomní mód.
Celou dobu jsme, aniž bychom to tušili, spouštěli kubelet v "autonomním režimu". (Pokud bychom byli pedanti, mohli bychom považovat autonomní režim kubeletu za "minimálně životaschopný Kubernetes", ale to by bylo velmi nudné). Aby „opravdová“ konfigurace fungovala, musíme předat soubor kubeconfig kubeletu, aby věděl, jak komunikovat s API serverem. Naštěstí je to docela jednoduché (protože nemáme problémy s autentizací nebo certifikáty):
apiVersion: v1
kind: Config
clusters:
- cluster:
server: http://127.0.0.1:8080
name: mink8s
contexts:
- context:
cluster: mink8s
name: mink8s
current-context: mink8s Uložte to jako kubeconfig.yaml, zabijte proces kubelet a restartujte s požadovanými parametry:
$ sudo ./kubelet --pod-manifest-path=pods --kubeconfig=kubeconfig.yaml(Mimochodem, pokud se pokusíte přistupovat k API přes curl, když kubelet neběží, zjistíte, že stále funguje! Kubelet není „rodičem“ svých podů, podobně jako Docker; spíše připomíná "demon správce". Kontejnery řízené kubelet budou fungovat, dokud je kubelet nezastaví.)
Za několik minut kubectl by měl ukázat naše pody a uzly, jak očekáváme:
$ ./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.6Tentokrát se skutečně pochváleme (vím, že už jsem to udělal) — máme minimální "klastr" Kubernetes běžící s plnohodnotným API!
Spouštíme pod
Nyní se podíváme, co API dokáže. Začneme s bodem nginx:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginxZde dostaneme docela zajímavou chybu:
$ .\/kubectl apply -f nginx.yaml
Chyba ze serveru (Forbidden): chyba při vytváření "nginx.yaml": pods "nginx" je
zakázán: chyba při hledání účtu služby default\/default: serviceaccount
"default" nenalezen
$ .\/kubectl get serviceaccounts
Žádné zdroje nenalezeny v výchozím prostoru.Zde vidíme, jak strašně neúplné je naše prostředí Kubernetes — nemáme žádné účty pro služby. Zkusme to znovu a vytvořme účet služby manuálně, abychom zjistili, co se stane:
$ cat <<EOS | .\/kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
EOS
serviceaccount\/default vytvořen
$ .\/kubectl apply -f nginx.yaml
Chyba ze serveru (ServerTimeout): chyba při vytváření "nginx.yaml": Žádný API
token nenalezen pro účet služby "default", zkuste to znovu poté, co bude token
automaticky vytvořen a přidán k účtu služby.I když jsme účet služby vytvořili manuálně, autentizační token se nevytváří. Pokračováním v experimentování s naším minimalistickým „klastrem“ zjistíme, že většina užitečných věcí, které se obvykle dějí automaticky, chybí. Server Kubernetes API je poměrně minimalistický, většina těžkých automatických konfigurací se provádí v různých ovladačích a na pozadí, které zatím nejsou spuštěny.
Můžeme toto řešení obejít nastavením možnosti automountServiceAccountToken pro účet služby (protože jej stejně nebudeme potřebovat):
$ cat <<EOS | .\/kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: default
automountServiceAccountToken: false
EOS
serviceaccount\/default nakonfigurován
$ .\/kubectl apply -f nginx.yaml
pod\/nginx vytvořen
$ .\/kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 0\/1 Pending 0 13mNakonec se pod objevil! Ale ve skutečnosti se nespustí, protože nemáme (scheduler) — další důležitou součást Kubernetes. Znovu vidíme, že API Kubernetes je překvapivě "hloupé" — když vytvoříte pod v API, zaregistruje ho, ale nepokouší se zjistit, na kterém uzlu jej spustit.
Ve skutečnosti pro spuštění podu plánovač není potřeba. Můžeme ručně přidat uzel do manifestu v parametru nodeName:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
nodeName: mink8s
(Nahraďte mink8s názvem uzlu.) Po delete a apply vidíme, že nginx běží a naslouchá na interní IP adrese:
$ .\/kubectl delete pod nginx
pod "nginx" byl smazán
$ .\/kubectl apply -f nginx.yaml
pod/nginx byl vytvořen
$ .\/kubectl get pods -owide
JMÉNO PŘIPRAVENO STAV RESTARTY VĚK IP NOD NOMINOVANÝ NOD BRÁNY PŘIPRAVENOSTI
nginx 1\/1 Běžící 0 30s 172.17.0.2 mink8s <none> <none>
$ curl -s 172.17.0.2 | head -4
<!DOCTYPE html>
<html>
<head>
<title>Vítejte na nginx!</title>Abychom se ujistili, že síť mezi podmi funguje správně, můžeme spustit curl z jiného podu:
$ 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>Vítejte na nginx!</title>Je docela zajímavé prozkoumat toto prostředí a zjistit, co funguje a co ne. Zjistil jsem, že ConfigMap a Secret fungují, jak se očekávalo, zatímco Service a Deployment ne.
Úspěch!
Tento příspěvek se stává obsáhlým, proto chci vyhlásit vítěze a uvést, že to je životaschopná konfigurace, kterou lze nazvat "Kubernetes". Stručně řečeno: čtyři binární soubory, pět příkazových parametrů a "pouze" 45 řádků YAML (ne tak mnoho podle standardů Kubernetes) a máme v chodu několik věcí:
- Pody jsou spravovány pomocí běžného API Kubernetes (s několika hacky)
- Lze nahrávat veřejné obrazy kontejnerů a spravovat je
- Pody zůstávají naživu a automaticky se restartují
- Síť mezi podmi v rámci jednoho uzlu funguje docela dobře
- ConfigMap, Secret a nejjednodušší montování úložišť fungují, jak mají
Ale většina toho, co dělá Kubernetes skutečně užitečné, stále chybí, například:
- Plánovač podů
- Autentizace / autorizace
- Více uzlů
- Síť služeb
- Klastrální interní DNS
- Kontroléry pro účty služeb, nasazení, integraci s cloudovými poskytovateli a většinu dalších "vychytávek", které přináší Kubernetes
Co tedy skutečně máme? API Kubernetes, které funguje samostatně, je ve skutečnosti jen platformou pro automatizaci kontejnerů. Nedělá toho mnoho – to je práce pro různé kontroléry a operátory, kteří používají API – ale poskytuje konzistentní prostředí pro automatizaci.
Číst více:
Zdroj: habr.com
