Sa totoo lang, hindi ako 100% sigurado. Ngunit sa tingin ko ito ay kagiliw-giliw na bungkalin ang mga panloob at makita kung ano talaga ang nangyayari sa Kubernetes sa ilalim ng maraming mga layer ng abstraction nito. Kaya para lang masaya, tingnan natin kung ano talaga ang hitsura ng minimal na βKubernetes clusterβ. (Ito ay magiging mas madali kaysa sa Kubernetes Ang Mahirap na Daan.)
Ipinapalagay ko na mayroon kang pangunahing kaalaman sa Kubernetes, Linux, at mga lalagyan. Lahat ng pinag-uusapan natin dito ay para sa pananaliksik/pag-aaral lamang, huwag ilagay ang alinman sa mga ito sa produksyon!
Repasuhin
Ang Kubernetes ay naglalaman ng maraming bahagi. Ayon kay Wikipedia, ganito ang hitsura ng arkitektura:
Mayroong hindi bababa sa walong bahagi na ipinapakita dito, ngunit hindi namin papansinin ang karamihan sa mga ito. Gusto kong sabihin na ang pinakamababang bagay na maaaring makatwirang tawaging Kubernetes ay binubuo ng tatlong pangunahing bahagi:
kubelet
kube-apiserver (na nakasalalay sa etcd - database nito)
runtime ng container (Docker sa kasong ito)
Tingnan natin kung ano ang sinasabi ng dokumentasyon tungkol sa bawat isa sa kanila (rus., Ingles.). Sa simula kubelet:
Isang ahente na tumatakbo sa bawat node sa cluster. Tinitiyak nito na ang mga lalagyan ay tumatakbo sa pod.
Parang simple lang. Paano kung mga runtime ng container (runtime ng container)?
Ang container runtime ay isang program na idinisenyo upang magpatakbo ng mga container.
Napaka informative. Ngunit kung pamilyar ka sa Docker, dapat ay mayroon kang pangkalahatang ideya kung ano ang ginagawa nito. (Ang mga detalye ng paghihiwalay ng mga responsibilidad sa pagitan ng runtime ng container at ng kubelet ay talagang banayad at hindi ko ito sasagutin dito.)
Π API server?
Ang API Server ay ang Kubernetes control panel component na naglalantad sa Kubernetes API. Ang API server ay ang client side ng Kubernetes control panel
Ang sinumang nakagawa ng anumang bagay sa Kubernetes ay kailangang makipag-ugnayan sa API nang direkta o sa pamamagitan ng kubectl. Ito ang puso kung bakit ang Kubernetes Kubernetes - ang utak na ginagawang gumaganang imprastraktura ang mga bundok ng YAML na kilala at mahal nating lahat (?). Mukhang halata na ang API ay dapat naroroon sa aming minimal na configuration.
Preconditions
Linux virtual o pisikal na makina na may root access (Gumagamit ako ng Ubuntu 18.04 sa isang virtual machine).
At lahat na!
Nakakainip na pag-install
Kailangan nating i-install ang Docker sa machine na gagamitin natin. (Hindi ko na idedetalye kung paano gumagana ang Docker at mga container; kung interesado ka, mayroong kahanga-hangang mga artikulo). I-install na lang natin apt:
Pagkatapos nito, kailangan nating makuha ang mga binary ng Kubernetes. Sa katunayan, para sa paunang paglulunsad ng aming "kumpol" kailangan lang namin kubelet, dahil upang magpatakbo ng iba pang mga bahagi ng server na magagamit namin kubelet. Para makipag-ugnayan sa aming cluster pagkatapos itong tumakbo, gagamitin din namin kubectl.
Wow, napakaraming pagpipilian! Sa kabutihang-palad, kailangan lang namin ng isang pares ng mga ito. Narito ang isa sa mga parameter na interesado kami:
--pod-manifest-path string
Path sa direktoryo na naglalaman ng mga file para sa mga static na pod, o path sa isang file na naglalarawan ng mga static na pod. Binabalewala ang mga file na nagsisimula sa mga tuldok. (DEPRECATED: Dapat itakda ang opsyong ito sa configuration file na ipinasa sa Kubelet sa pamamagitan ng --config na opsyon. Para sa higit pang impormasyon, tingnan ang kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file .)
Ang pagpipiliang ito ay nagpapahintulot sa amin na tumakbo mga static na pod β mga pod na hindi pinamamahalaan sa pamamagitan ng Kubernetes API. Ang mga static na pod ay bihirang ginagamit, ngunit ang mga ito ay napaka-maginhawa para sa mabilis na pagpapalaki ng isang kumpol, at ito mismo ang kailangan namin. Hindi namin papansinin ang malaking babala na ito (muli, huwag itong patakbuhin sa produksyon!) at tingnan kung mapapatakbo namin ang pod.
Una, gagawa kami ng isang direktoryo para sa mga static na pod at tatakbo kubelet:
kubelet nagsimulang magsulat ng ilang babala at parang walang nangyayari. Ngunit hindi iyon totoo! Tingnan natin ang 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 Binasa ko ang pod manifest at binigyan si Docker ng utos na maglunsad ng ilang container ayon sa aming mga detalye. (Kung nagtataka ka tungkol sa container na "pause", isa itong hack ng Kubernetes - tingnan mo ang blog na ito.) Ilulunsad ng Kubelet ang aming lalagyan busybox gamit ang tinukoy na utos at i-restart ito nang walang katiyakan hanggang sa matanggal ang static na pod.
Batiin ang iyong sarili. Nakaisip lang kami ng isa sa mga pinakanakalilitong paraan para mag-output ng text sa terminal!
Ilunsad atbp
Ang aming pinakalayunin ay patakbuhin ang Kubernetes API, ngunit para magawa iyon kailangan muna naming tumakbo atbp. Magsimula tayo ng kaunting etcd cluster sa pamamagitan ng paglalagay ng mga setting nito sa direktoryo ng pods (halimbawa, pods/etcd.yaml):
Kung nakatrabaho mo na ang Kubernetes, dapat na pamilyar sa iyo ang mga YAML file na ito. Mayroon lamang dalawang puntos na dapat tandaan dito:
Na-mount namin ang folder ng host /var/lib/etcd sa pod upang ang etcd data ay mapangalagaan pagkatapos ng pag-restart (kung hindi ito nagawa, ang estado ng cluster ay mabubura sa tuwing magre-restart ang pod, na hindi magiging maganda para sa kahit kaunting pag-install ng Kubernetes).
Na-install na namin hostNetwork: true. Ang setting na ito, hindi nakakagulat, ay nagko-configure ng etcd upang gamitin ang host network sa halip na ang panloob na network ng pod (ito ay magiging mas madali para sa API server na mahanap ang etcd cluster).
Ang isang simpleng pagsusuri ay nagpapakita na ang etcd ay talagang tumatakbo sa localhost at nagse-save ng data sa 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.wal
Pagsisimula ng API server
Ang pagpapatakbo ng isang Kubernetes API server ay mas madali. Ang tanging parameter na kailangang ipasa ay --etcd-servers, ginagawa ang iyong inaasahan:
Ilagay ang YAML file na ito sa direktoryo pods, at magsisimula ang API server. Sinusuri gamit ang curl nagpapakita na ang Kubernetes API ay nakikinig sa port 8080 na may ganap na bukas na access - walang kinakailangang pagpapatunay!
(Muli, huwag patakbuhin ito sa produksyon! Medyo nagulat ako na ang default na setting ay napaka-insecure. Ngunit sa palagay ko ito ay para gawing mas madali ang pag-develop at pagsubok.)
At, nakakatuwang sorpresa, gumagana ang kubectl sa labas ng kahon nang walang anumang karagdagang mga setting!
$ ./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.
problema
Ngunit kung maghuhukay ka ng kaunti pa, tila may mali:
$ ./kubectl get pod -n kube-system
No resources found in kube-system namespace.
Wala na ang mga static na pod na ginawa namin! Sa katunayan, ang aming kubelet node ay hindi natuklasan:
$ ./kubectl get nodes
No resources found in default namespace.
Anong problema? Kung naaalala mo ang ilang talata na nakalipas, sinimulan namin ang kubelet gamit ang napakasimpleng hanay ng mga parameter ng command line, kaya hindi alam ng kubelet kung paano makipag-ugnayan sa API server at ipaalam ito sa estado nito. Pagkatapos pag-aralan ang dokumentasyon, nakita namin ang kaukulang bandila:
--kubeconfig string
Ang landas sa file kubeconfig, na tumutukoy kung paano kumonekta sa API server. Availability --kubeconfig pinapagana ang mode ng server ng API, hindi --kubeconfig pinapagana ang offline mode.
Sa lahat ng oras na ito, nang hindi nalalaman, pinapatakbo namin ang kubelet sa "offline mode." (Kung tayo ay nagiging pedantic, maaari nating isipin ang isang standalone na kubelet bilang "minimum viable Kubernetes", ngunit iyon ay magiging napakaboring). Para gumana ang "totoong" configuration, kailangan nating ipasa ang kubeconfig file sa kubelet para malaman nito kung paano makipag-usap sa API server. Sa kabutihang palad ito ay medyo simple (dahil wala kaming anumang mga isyu sa pagpapatunay o sertipiko):
(Nga pala, kung susubukan mong i-access ang API sa pamamagitan ng curl kapag ang kubelet ay hindi tumatakbo, makikita mo na ito ay tumatakbo pa rin! Kubelet ay hindi isang "magulang" ng mga pod nito tulad ng Docker, ito ay mas katulad ng isang "kontrol". daemon.β Ang mga lalagyan na pinamamahalaan ng isang kubelet ay patuloy na tatakbo hanggang sa mapahinto sila ng kubelet.)
Sa ilang minuto kubectl dapat ipakita sa amin ang mga pod at node gaya ng inaasahan namin:
$ ./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
Talagang batiin natin ang ating mga sarili sa pagkakataong ito (alam kong binati ko na ang ating mga sarili) - mayroon tayong kaunting Kubernetes na "cluster" na tumatakbo na may fully functional na API!
Inilunsad namin sa ilalim
Ngayon tingnan natin kung ano ang kaya ng API. Magsimula tayo sa nginx pod:
Dito nakakakuha kami ng isang medyo kawili-wiling error:
$ ./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.
Dito natin makikita kung gaano kahirap ang ating kapaligiran sa Kubernetes - wala tayong mga account para sa mga serbisyo. Subukan nating muli sa pamamagitan ng manu-manong paggawa ng account ng serbisyo at tingnan kung ano ang mangyayari:
$ 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
Kahit na ginawa namin nang manu-mano ang account ng serbisyo, hindi nabuo ang token ng pagpapatunay. Habang patuloy kaming nag-eeksperimento sa aming minimalistic na "cluster", makikita namin na ang karamihan sa mga kapaki-pakinabang na bagay na karaniwang nangyayari ay awtomatikong mawawala. Ang server ng Kubernetes API ay medyo minimalistic, na ang karamihan sa mabigat na pag-angat at awtomatikong pagsasaayos ay nangyayari sa iba't ibang mga controller at mga trabaho sa background na hindi pa tumatakbo.
Maaari naming lutasin ang problemang ito sa pamamagitan ng pagtatakda ng opsyon automountServiceAccountToken para sa account ng serbisyo (dahil hindi na namin ito kailangang gamitin pa rin):
$ 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
Sa wakas, lumitaw na ang pod! Pero sa totoo lang hindi magsisimula dahil wala naman kami tagaplano (scheduler) ay isa pang mahalagang bahagi ng Kubernetes. Muli, nakita namin na ang Kubernetes API ay nakakagulat na "pipi" - kapag gumawa ka ng Pod sa API, nirerehistro ito, ngunit hindi sinusubukang alamin kung saang node ito tatakbo.
Sa katunayan, hindi mo kailangan ng scheduler para magpatakbo ng pod. Maaari kang manu-manong magdagdag ng node sa manifest sa parameter nodeName:
(Palitan mink8s sa pangalan ng node.) Pagkatapos tanggalin at ilapat, nakita namin na ang nginx ay nagsimula at nakikinig sa panloob na IP address:
$ ./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>
Upang matiyak na gumagana nang tama ang network sa pagitan ng mga pod, maaari naming patakbuhin ang curl mula sa isa pang pod:
$ 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>
Medyo kawili-wiling maghukay sa kapaligirang ito at makita kung ano ang gumagana at kung ano ang hindi. Nalaman kong gumagana ang ConfigMap at Secret gaya ng inaasahan, ngunit hindi gumagana ang Serbisyo at Pag-deploy.
Tagumpay!
Ang post na ito ay humahaba, kaya't ako ay magdedeklara ng tagumpay at sasabihin na ito ay isang mabubuhay na pagsasaayos na maaaring tawaging "Kubernetes". Upang ibuod: apat na binary, limang mga parameter ng command line at "lamang" 45 na linya ng YAML (hindi na magkano ayon sa mga pamantayan ng Kubernetes) at mayroon kaming ilang bagay na gumagana:
Ang mga pod ay pinamamahalaan gamit ang regular na Kubernetes API (na may ilang mga hack)
Maaari kang mag-upload at mamahala ng mga pampublikong larawan ng lalagyan
Nananatiling buhay ang mga pod at awtomatikong magre-restart
Ang networking sa pagitan ng mga pod sa loob ng parehong node ay gumagana nang maayos
ConfigMap, Secret at simpleng storage mounting work gaya ng inaasahan
Ngunit karamihan sa kung bakit tunay na kapaki-pakinabang ang Kubernetes ay nawawala pa rin, tulad ng:
Pod Scheduler
Authentication/authorization
Maramihang node
Network ng mga serbisyo
Naka-cluster na panloob na DNS
Mga controller para sa mga service account, deployment, integration sa cloud providers at karamihan sa iba pang goodies na hatid ng Kubernetes
Kaya ano talaga ang nakuha natin? Ang Kubernetes API, na tumatakbo sa sarili nitong, ay talagang isang platform para sa automation ng lalagyan. Wala itong gaanong nagagawa - ito ay isang trabaho para sa iba't ibang mga controller at operator na gumagamit ng API - ngunit nagbibigay ito ng pare-parehong kapaligiran para sa automation.