Difference between revisions of "Kubernetes"
(→Pod-ok közötti kommunikáció) |
(→Logikai építőkockák) |
||
Line 12: | Line 12: | ||
* Service: | * Service: | ||
* Endpoint: | * Endpoint: | ||
+ | * Namespace | ||
+ | * Network Policies | ||
:[[File:ClipCapIt-190330-184913.PNG]] | :[[File:ClipCapIt-190330-184913.PNG]] | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | === Namespace === | ||
+ | https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ | ||
==Infrastruktúra elemek== | ==Infrastruktúra elemek== |
Revision as of 15:05, 5 May 2019
Kubernetes felépítése
Logikai építőkockák
- Container:
- Pod:
- ReplicaSet:
- Deployment:
- Service:
- Endpoint:
- Namespace
- Network Policies
Namespace
https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
Infrastruktúra elemek
Telepítés
kubectl
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl $ chmod +x ./kubectl $ ln -s /home/adam/Programs/Kubernetes/kubectl /usr/local/bin/kubectl
$ kubectl version --output=yaml
Minikube
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-"linux-amd64 && $ chmod +x minikube $ ln -s /home/adam/Programs/Kubernetes/minikube /usr/local/bin/minikube
kvm2 driver install
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-kvm2 \ && sudo install docker-machine-driver-kvm2 /usr/local/bin/ $ minikube version
Minikube indítása
$ minikube start --vm-driver=kvm2 Creating kvm VM (CPUs=2, Memory=2048MB, Disk=20000MB) ... - docker - kubernetes master - kubernetes node: kublet 😄 minikube v0.35.0 on linux (amd64) 🔥 Creating virtualbox VM (CPUs=2, Memory=2048MB, Disk=20000MB) ...
Letölti a minikube.iso image-et a /home/adam/.minikube/cache/iso/ mappába, és innen létrehoz egy kvm vm-et:
# virsh list Id Name State ---------------------------------------------------- 1 minikube running
Minikube parancsok
$ minikube dashboard
A minikube itt mutatja meg, hogy egy adott service hol érhető el:
# minikube service <service-name> --url
Be lehet ssh-zni a vm-be mint a docker-machine ssh nál.
# minikube ssh -
A minikube telepítő beállította a kubectl-t is, hogy a minikube-ban futó cluster-re csatlakozzon. Ha listázzuk a kubectl beállításait, láthatjuk a minikube VPN IP címét.
# kubectl config view apiVersion: v1 clusters: - cluster: certificate-authority: /root/.minikube/ca.crt server: https://192.168.42.224:8443 name: minikube
Nodes
Az összes node listázása.
# kubectl get nodes NAME STATUS ROLES AGE VERSION minikube Ready master 11m v1.13.4
Megfelel a swarm-ban: docker node ls parancsnak.
Pod
Podok készítése
Imperative megközelítés
Konténert a legegyszerűbben a kubectl run paranccsal futtathatunk. Létre fog hozni egy pod-ot és benne el fogja indítani az image-et.
$ kubectl run db --image mongo
Deklaratív megközelítés
apiVersion: v1
kind: Pod
metadata:
name: go-demo-2
labels:
app: myapp
spec:
containers:
- name: db
image: mongo:3.3
# kubectl create -f pod-db.yaml pod/go-demo-2 created # kubectl get pod NAME READY STATUS RESTARTS AGE go-demo-2 1/1 Running 0 50s
Pod-ok kezelése
Pod-ok listázása
# kubectl get pods NAME READY STATUS RESTARTS AGE db-7fdd878ff9-7v66g 0/1 ContainerCreating 0 66s
Belépés a pod-ban futó konténerekbe:
# kubectl exec -it <pod név> /bin/bash
Ha több konténer is van a pod-ban, akkor a -c vel meg kell adni a konténer nevét:
# kubectl exec -it -c db dbstack /bin/bash
Ha több konténer is van a pod-ban, akkor a pod neve után meg kell adni a konténer nevét.
# kubectl logs dbstack -c db
Minden kubernetes elem listázása:
# kubectl get all NAME READY STATUS RESTARTS AGE pod/db-6b5c96c65f-9lxnb 1/1 Running 0 2m46s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/db 1/1 1 1 2m46s NAME DESIRED CURRENT READY AGE replicaset.apps/db-6b5c96c65f 1 1 1 2m46s
Egy pod összes adatának listázása. Itt külön listában láthatjuk a POD-ban futó összes konténert. Látható, hogy az alábbi POD-ban két konténer is fut: db és api néven.
[root@adamDell2 ~]# kubectl describe pod dbstack
Name: dbstack
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: minikube/192.168.122.228
Start Time: Wed, 13 Mar 2019 21:51:19 +0100
Labels: type=stack
Annotations: <none>
Status: Running
IP: 172.17.0.5
Containers:
db:
Container ID: docker://c371653e62b4bb1f8a7fb7de4d88452b6de623cf02caa41df9728df15d080481
Image: mongo:3.3
...
api:
Container ID: docker://6b64c392a77347ce5e7b36ddfd80f2ef320a0e31d25985f813294d08cacf76b3
Image: vfarcic/go-demo-2
A get paranccsal is ugyan ezt a részletességet érhetjük el a -o json kapcsolóval.
# kubectl get pod go-demo-2 -o json
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"creationTimestamp": "2019-03-31T21:13:34Z",
"labels": {
"app": "myapp",
"type": "example"
},
"name": "go-demo-2",
"namespace": "default",
"resourceVersion": "133741",
"selfLink": "/api/v1/namespaces/default/pods/go-demo-2",
"uid": "d7d61cac-53f9-11e9-bdbb-5254008eeeec"
},
"spec": {
"containers": [
{
"image": "mongo:3.3",
"imagePullPolicy": "IfNotPresent",
"name": "db",
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
"name": "default-token-zj4tp",
"readOnly": true
}
...
A -f -el meg lehet adni a leíró fájlt a describe parancsban. Ez minden Kubernetes elemre működik. Ha nem adunk meg a formátumra paramétert, akkor egy szimpla felsorolást kapunk. A végén pedig egy esemény történet van az adott pod-ról.
# kubectl describe -f pod-db.yaml Name: db Namespace: default Priority: 0 PriorityClassName: <none> Node: minikube/192.168.122.228 Start Time: Wed, 13 Mar 2019 20:49:30 +0100 Labels: type=db ... .. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 21h default-scheduler Successfully assigned default/go-demo-2 to minikube Normal Pulled 21h kubelet, minikube Container image "mongo:3.3" already present on machine Normal Created 21h kubelet, minikube Created container Normal Started 21h kubelet, minikube Started container
-o kapcsoló használata
Név | Leírás |
---|---|
-o custom-columns=<spec> | Print a table using a comma separated list of custom columns |
-o custom-columns-file=<filename> | Print a table using the custom columns template in the <filename> file |
-o json | Output a JSON formatted API object |
-o jsonpath=<template> | Print the fields defined in a jsonpath expression |
-o jsonpath-file=<filename> | Print the fields defined by the jsonpath expression in the <filename> file |
-o name | Print only the resource name and nothing else |
-o wide | Output in the plain-text format with any additional information, and for pods, the node name is included |
-o yaml | Output a YAML formatted API object |
A -o json kapcsolóval írhatjuk ki JSON -ban a pod infókat.
# kubectl get -f pod-db.yaml -o json { "apiVersion": "v1", "kind": "Pod", "metadata": { "creationTimestamp": "2019-03-13T19:49:30Z", "labels": { "type": "db", "vendor": "MongoLabs" }, ...
Részletes pod lista. A lényeg itt az IP cím.
# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES db 1/1 Running 0 2m39s 172.17.0.2 minikube <none> <none>
első pod a listáról:
# kubectl get pods -o name | tail -1
Szűrés
Listázzuk ki JSON-ban a pod részleteket.
"status": {
...
"hostIP": "192.168.122.228",
...
Szűrni a -o jsonpath -al lehet.
Mindig úgy kell szűrni, hogy a legfelsőbb szintű elem elé teszünk egy .-ot. Majd megadjuk a path-t.
# kubectl get -f pod-db.yaml -o jsonpath="{.status.hostIP}" 192.168.122.228
Ha egy lista összes elemére akarjuk hogy illeszkedjen a keresés, akkor [*] -ot kell használni. Ha egy konkrét lista elemet akarunk, akkor azt adjuk meg így [1]
Pl. az összes konténer nevét így listázhatjuk:
# kubectl get -f pod-db.yaml -o jsonpath="{.spec.containers[*].name}" db api
Címkék
A selector-ok címék alapján működnek.
Címke hozzáadása egy node-hoz:
# kubectl get node NAME STATUS ROLES AGE VERSION minikube Ready master 22d v1.13.4
# kubectl label node minikube disktype=ssd node/minikube labeled
# kubectl describe node minikube
Name: minikube
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
disktype=ssd
...
# kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
minikube Ready master 22d v1.13.4 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,..
Szintaxis:
# kubectl label <resource type: node, pod, ...> <resource név> <címke neve>=<címke értéke>
nodeSelector:
labelName: labelvalue
Címke felrakása pod-ra:
# kubectl label pod go-demo-2 type=example pod/go-demo-2 labeled
# kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS go-demo-2 1/1 Running 1 23h app=myapp,type=example
Címke törlése
# kubectl label pod go-demo-2 type- pod/go-demo-2 labeled # kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS go-demo-2 1/1 Running 1 23h app=myapp
Health check
- readinessProbe: ezt addig fogja futtatni amíg nem lesz egyszer sikeres, ez után fogja ready-re állítani a konténert.
- livenessProbe: Ezzel pedig a konténer egészségét fogja ellenőrizni
apiVersion: v1
kind: Pod
...
spec:
containers:
- name: liveness
image: k8s.gcr.io/busybox
...
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
Három változatuk van.
- command futtatása
- http rest hívás
- tcpSocket
Command
livenessProbe: exec: command: - cat - /tmp/healthy
Http
- path
- port
- httpHeaders
livenessProbe: httpGet: path: /healthz port: 8080 httpHeaders: - name: Custom-Header value: Awesome initialDelaySeconds: 3 periodSeconds: 3
Socket
livenessProbe: tcpSocket: port: 8080
Név | Leírás |
---|---|
initialDelaySeconds | ennyi után fogja elkezdeni a próbálkozást |
periodSeconds | Ilyen sűrűn fogja megpróbálni |
timeoutSeconds | Ennyi idő után fogja feladni |
failureTreshold | Ennyi negatív válasz után fogja feladni. |
ReplicaSets
Áttekintés
Arra szolgál, hogy a benne definiált pod lehetőleg mindig annyi példányban fusson, amit defináltunk. Tehát ez továbbra is egy pod-ra vonatkozik, csak annak vezérelni tudjuk most már az életciklusát.
A ReplicaSet és a ReplicaController között a selector-ban van a különbség. A Controller-ben csak a = b-vel selector-okat lehet megadni, míg a Set-ben meg lehet adni összetett kifejezéseket is:
selector: matchExpressions: - {key: app, operator: In, values: [soaktestrs, soaktestrs, soaktest]} - {key: teir, operator: NotIn, values: [production]}
A pod-hoz hasonlóan a dekleratív megközelítés szellemében, a replicaSet-et is yaml fájllal kell definiálni:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-rs
spec:
replicas: 2
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
A ReplicaSet leírásában 3 fontos rész van a spec szekción belül:
- replicas: megmondja, hogy hány példány kell hogy fusson a pod-ból
- selector: megmondja, hogy milyen címkékkel kell hogy a pod rendelkezzen, amire a replicaSet vonatkozik. Mivel a pod és a replicaSet csak lazán csatolt kapcsolatban van, a ReplicaSet csak annyit figyel, hogy minden fusson a replicas részben megadott számú pod, ami rendelkezik olyan címkékkel amiket a selector szekcióba megadtunk (itt tagadni is lehet)
- template: Itt definiáljuk a pod-ot. Ez a rész megegyezik a pod yaml fájlnál leírtakkal. A metadata részben adjuk meg a pod címkéit, a spec részbe pedig a konténereket.
Tip
Furcsa hogy ezt a két egymástól független entitást egy fájlban definiáljuk. Simán megcsinálhatjuk, hogy a tempalte szekcióban olyan pod-ot adunk meg, aminek nincs egy olyan címkéje sem, ami illeszkedne a selector részben megadott címkékre, így a replicaSet sosem tudna elindulni.
Selectorok és címkék
A ReplicaSet és majd a Service is a label-ek alapján találnak rá a Pod-okra. A selektorokonak két nagy családja van:
- egyenlő, nem egyenlő kifejezések: key=value illetve key!=value
- halmaz kifejezések: key in (v1, v2..), key notin (v1,v2..) illetve felírhatunk pusztán a kulcs létezésére ill nem létezésére feltételeket a kulcs értékétől függetlenül:
environment in (production, qa) tier notin (frontend, backend) partition !partition
A példában az utolsó két sor a kulcsra vonatkozik, hogy legyen olyan kulcs amit partition-nek hívnak ill ne legyen olyan kulcs amit partition-nek hívnak.
Egy kifejezésben vesszővel lehet AND kapcsolatba hozni a kulcs kifejezéseket. A kubectl parancsokban a -l -el vagy hosszan label paraméterben kell megadni a kulcsokat:
# kubectl get pod -l app=myapp,type=example NAME READY STATUS RESTARTS AGE go-demo-2 1/1 Running 3 8d
Selector
A Service definíciójában illetve a ReplicaSet elődjében a ReplicationController-ben még a hagyományos selector megadást kell használni, a halmazos megadást itt nem szabad használni.
apiVersion: v1
kind: Service
metadata:
name: db-svc
spec:
type: ClusterIP
ports:
- port: 27017
selector:
type: db
service: mongo-db
A selector-ok után fel kell sorolni a címéket, amik ÉS kapcsolatban vannak.
matchLabels
A deployment-ben ill. a ReplicaSet-ben már a matchLabels ill a vele ekvivalens matchExpressions -t kell a címke megadásnál használni. A matchLabels-ben meg lehet adni egyenlőség és set alapú címke definíciókat is. Viszont a selector kulcsszó után kötelező a matchLabels használata.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-db
spec:
replicas: 1
selector:
matchLabels:
type: db
service: mongo-db
template:
ReplicaSet kezelése
A get parancsban ReplicaSet esetén az rs-t kell megadni a pod helyett:
# kubectl get rs -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR go-demo-2 2 2 2 23s db,api mongo:3.3,vfarcic/go-demo-2 service=go-demo-2,type=backend
Ugyan úgy használhatjuk a describe parancsot is az rs-el mint a pod esetében:
# kubectl describe rs go-demo-2 Name: go-demo-2 Namespace: default Selector: service=go-demo-2,type=backend Labels: <none> Annotations: <none> Replicas: 2 current / 2 desired Pods Status: 2 Running / 0 Waiting / 0 Succeeded / 0 Failed Pod Template: Labels: db=mongo language=go service=go-demo-2 type=backend Containers: db: Image: mongo:3.3 Port: <none> Host Port: <none> Environment: <none> Mounts: <none> api: Image: vfarcic/go-demo-2 ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 112s replicaset-controller Created pod: go-demo-2-6nq9h Normal SuccessfulCreate 112s replicaset-controller Created pod: go-demo-2-5c2sk
# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS go-demo-2-5c2sk 2/2 Running 0 5m41s db=mongo,language=go,service=go-demo-2,type=backend go-demo-2-6nq9h 2/2 Running 0 5m41s db=mongo,language=go,service=go-demo-2,type=backend
A pod-ok és az RS között csak lazán csatolt kapcsolat van. Ha --cascade=false kapcsolóval töröljük az RS-t akkor a podokat meg fogja hagyni. És ha újra létrehozzuk az RS-t ezeket a pod-okat fogja felhasználni.
# kubectl delete -f rs/go-demo-2.yml --cascade=false
kubectl apply --> frissíti a konfigurációt. Rárak egy annotációt, és később az alapjén dönti el, hogy mi válozott. Csak akkor lehet használni, ha eleve apply-al hoztuk létre, vagy create --save-confg kapcsolóval.
# kubectl create --save-config
kubectl edit: egyenlő azzal, mint ha describe -o yaml -el elmentenénk a konfigot, átírnánk, majd nyomnánk rá egy applay-t.
A -o yaml-el meg tudjuk szeretni az eredeti konfigurációs fájlt:
# kubectl get rs go-demo-2 -o yaml
Networking
Pod szintű kommunikáció
A pod hálózati szempontból nem egy plusz réteg a konténer körül, nem úgy kell elképzelni, mint ha egy konténerben futtatnánk egy másik konténert, sokkal inkább úgy, hogy a POD egy interfésze a konténernek, újra csomagolja a docker konténert és csinál belőle egy "kubernetes konténert". A POD IP címe megegyezik a POD belsejében futó konténer IP címével, amit a Kubernetes oszt ki véletlenszerűen minden egyes POD-nak. A POD-nak akkor is csak egy IP címe van, ha több konténer fut benne. ... TODO rajz...
Konténerek közötti kommunikáció
... TODO rajz...
Ha egy POD belsejében több konténer van, akkor azok osztoznak a hálózati névtérben, tehát ez nem egyenlő azzal, mint ha a lokális gépünkön két konténert elindítanánk egymás mellett, mert ott mind a két konténernek saját hálózati névtere lenne, és alap esetben nem tudnak egymással kommunikálni. Tehát ebből is látszik, hogy a POD a konténer újra csomagolása a hagyományos docker-hez képest, vagyis ha több konténer van egy POD-ban, akkor az olyan mint ha a két image-et egy konténerben "csomagoltuk" volna. A közös POD-ban futó konténerek a localhost-on úgy látják egymást, de ugyan azokon a portokon nem hallgatózhat két konténer, mert akkor port ütközés lesz. A POD tudni fogja a közös névtér ellenére, hogy melyik konténer melyik porton figyel, és a külső kéréseket a megfelelő konténernek fogja továbbítani.
apiVersion: v1
kind: Pod
metadata:
name: go-demo-2
labels:
app: myapp
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
- name: nettest
image: amouat/network-utils
command: [ "bin/bash" ]
args: ["-c", "while true; do echo hello; sleep 10;done"]
A network-utils image-ből készülő konténernek végtelen ciklusban adtunk munkát, hogyne álljon le, ahogy létrejön.
# kubectl create -f pod-db.yaml pod/go-demo-2 created
Lépjünk be a nettsest konténerbe:
# kubectl exec -it -c nettest go-demo-2 /bin/sh #
Majd a localhost-on nézzük meg mit találunk a 80-as porton:
# curl localhost:80 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title>
Láthatjuk, hogy annak ellenére választ kapott, hogy valójában a másik konténer hallgatózik a 80-as porton.
Pod-ok közötti kommunikáció
Egy Kubernetes cluster-ben minden pod automatikusan tud minden másik POD-al kommunikálni a POD IP címén keresztül. Ez igaz a node-okra is. Minden node elér minden POD-ot és minden POD eléri az összes node-ot a node IP címén annak ellenére, hogy a pod-ok és a node-ok más hálózatban vannak.
Note
Ez a koncepció megfelel a docker swarm overlay hálózatának, amit a swarm-ban implicit definiálni kell, két swarm service csak akkor látja egymást, ha ugyan azon az overlay hálózaton vannak. (swarm-ban a service egy replicaSet-nek felel meg, nem egyenlő a Kubernetes service objektummal)
Hozzunk létre egy nginx pod-ot (deployment is létre fog hozzá jönni).
# kubectl run webserver --image nginx deployment.apps/webserver created
Keressük meg az IP címét:
# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES webserver-786f555565-gv4m6 1/1 Running 0 103s 172.17.0.7 minikube <none> <none>
Hozzunk létre a run paranccsal egy pod-ot amiben a network-utils hálózat tesztelő konténer fog futni. Ezt interaktív üzemmódban fogjuk elindítani, így ahogy létrejön a pod a konténer belsejében futó sh shell-hez fogunk kapcsolódni. Ehhez a kubernetes alapértelmezetten létre fog hozni egy deployment-et és egy replicaSet-et. De ez most nem fontos.
$ kubectl run -it netpod --image amouat/network-utils -- sh #
Keressük meg a pod IP címét.
# ifconfig eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:06 inet addr:172.17.0.6
Most a netpod belsejéből kérjük le a webserver pod index.html oldalát:
# curl 172.17.0.7 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title>
Láthatjuk hogy a két pod valóban tud egymással kommunikálni.
Most ssh-val lépjünk be a minikube node-ra majd onnan szintén kérjük le ezt az oldalt:
# minikube ssh _ _ _ _ ( ) ( ) ___ ___ (_) ___ (_)| |/') _ _ | |_ __ /' _ ` _ `\| |/' _ `\| || , < ( ) ( )| '_`\ /'__`\ | ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )( ___/ (_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____) $
$ curl 172.17.0.7 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title>
Látható hogy a node is elérte a pod-ban futó konténert.
Service
https://sookocheff.com/post/kubernetes/understanding-kubernetes-networking-model/
A containerPort csak informatív jellegű a konténer definícióban. Ettől függetlenül bármilyen porot-ot expose-álni lehet később, olyat is ami itt nincs megadva. Ha az expose parancsban nem adunk meg --target-port-ot akkor a -containerPort-al megadott portot fogja megosztani.
containers: - name: my-nginx image: nginx ports: - containerPort: 80
Az expose paranccsal lehet egy Pod vagy ReplicSet vagy Deployment-hez service-t készíteni implicit (tehát nem dekleratív módon). Meg kell mondani, hogy miből indulunk ki. Mi most egy replicaSet-ből, ezért az rs után megadtuk a ReplicaSet nevét. Utána meg kell adni a service nevét, a portot, amit ki akarunk nyitni, valamint a típust.
# kubectl expose rs nginx-rs --name=http --port=80 --type=NodePort --target-port=80
Típusok:
- NodePort: a külvilágból is elérhető lesz, minden egyes node-on --> clientIP típust is létrehoz, így a többi node is eléri ezt automatikusan
- ClusterIP: csak a cluster-en belülről
- ExternalName: ehhez cloud szolgáltató kell, pl aws
- LoadBalancer
Háromféle port érdekes a NodePort típusú service esetetén, amiből az expose paranccsal csak kettőt lehet megadni:
- port: ezen a porton érhető el a service a cluster-en belül. Ennek nincs köze ahhoz hogy a cluster-n kivül hol érhető el a szolgáltatás. Ha nem adjuk meg, akkor ugyan az lesz mint a target-port
- target-port: ez azt mondja meg, hogy a pod-on/container-en belül hol hallgatózik a service. Ha nem adjuk meg külön, akkor a -containerPort -ból szedni.
- nodePort: na ezt nem lehet itt megadni. Azt mondja meg, hogy a cluster-en kívül hol lesz elérhető a szolgálatás. Ha nem adjuk meg akkor random választ.
# kubectl get svc http -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR http NodePort 10.98.187.168 <none> 80:32730/TCP 8m3s run=my-nginx
Az itt mutatott IP cím a belső virtuális cím ami csak a Kubernetes cluster-en belül érvényes. A konténernek sincs ilyen 10.X.X.X-es tartományú IP címe, ez egy Kubernetes belső dolog.
Láthatjuk, hogy a service belső IP címe 80 (ezt adtuk meg a --port -nál, bármi lehetett volna, szabadon választható) és ehhez rendelte hozzá a külső portot: 32730 Ez a port az összes node publikus IP -én elérhető.
# kubectl get node -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME minikube Ready master 7d1h v1.13.4 192.168.122.228 <none> Buildroot 2018.05 4.15.0 docker://18.6.2 ^^^^^^
Az expose autómatikusan legyártja a service definíciót a ReplicaSet-ből, amiből kiindultunk. A végerdmény az alábbi:
# kubectl get svc http -o yaml apiVersion: v1 kind: Service metadata: name: http spec: ports: - nodePort: 32730 port: 80 protocol: TCP targetPort: 80 selector: run: my-nginx type: NodePort
A service és a ReplicaSet semmilyen kapcsolatban nincsenek egymással. Mind a kettő a selector-okkal találják meg a POD-okat.
A pod-ok úgynevezett Endpoint-okon keresztül ajálják ki a portokat a service-ek számára. Rövidítése ep. Tehát itt a 80-as port megegyezik a target-port-nál megadott értékkel.
- kubectl get ep
NAME ENDPOINTS AGE http 172.17.0.7:80 23m
Ha megnézzük az ep definícoját, akkor ott fel van sorolva az összes pod aki részt vesz a service-ben. Látható, hogy két pod van jelenleg . Az is ki van listázva, hogy mi a belső IP címük és hogy melyik node-on vannak.
# kubectl get ep http -o yaml apiVersion: v1 kind: Endpoints metadata: creationTimestamp: "2019-03-17T19:49:12Z" name: http namespace: default resourceVersion: "84822" selfLink: /api/v1/namespaces/default/endpoints/http uid: bd23a709-48ed-11e9-8d39-5254008eeeec subsets: - addresses: - ip: 172.17.0.7 nodeName: minikube targetRef: kind: Pod name: nginx-rs-wtzmm namespace: default resourceVersion: "73593" uid: 1820549d-48d9-11e9-8d39-5254008eeeec notReadyAddresses: - ip: 172.17.0.8 nodeName: minikube targetRef: kind: Pod name: nginx-rs-jkvx7 namespace: default resourceVersion: "84820" uid: 1c547797-48ee-11e9-8d39-5254008eeeec ports: - port: 80
A service-ek neve bekerül a DNS-be, és feloldja a Kubernetes a konténerek számára a belső virtuális IP címmel. Ha van egy ClusterIP típusú service-ünk a db-svc névvel, akkor a cluster-ben minden egyes konténerben ezt fel fogja oldani a service IP címére: 10.111.222.165. A service meg a felsorolt Enpoints-okon éri el a konténert.
# kubectl describe svc db-svc Name: db-svc Namespace: default Labels: <none> Annotations: <none> Selector: service=mongo-db,type=db Type: ClusterIP IP: 10.111.222.165 Port: <unset> 27017/TCP TargetPort: 27017/TCP Endpoints: 172.17.0.2:27017
A service round-rubin módon választ a végpontok között. De csak azoknak küld csomagot, amiben a livenessProbe. sikeresen futott le. Korábban userpase-el ment a kommunikácó, most már iptabels szabályokkal, ami sokkal gyorsabb, viszont nem tudja deketálni ha egy pod kiesett. Erre kell a livenessProbe
Lépjünk be egy harmadik konténerbe, amire nincs rákötve a service:
- kubectl exec -it rs-db-api-m6hkf /bin/sh
/ # nslookup db-svc Name: db-svc Address 1: 10.111.222.165 db-svc.default.svc.cluster.local
/ # nc -vz db-svc 27017 db-svc (10.111.222.165:27017) open
Publikus port lekrédezése:
PORT=$(kubectl get svc svc-api -o jsonpath="{.spec.ports[0].nodePort}"
Tehát nem kell a -o json ahhoz hogy tudjunk szűrni.
Nem muszáj hogy selector-a legyen egy szolgáltatásnak. Készíthetünk serlector nélküli service-t, ami automatikusan egyik pod-ra sem fog ezért rákerülni, majd készíthetünk hozzá manuálisan egy endpoint-ot:
kind: Endpoints apiVersion: v1 metadata: name: my-service subsets: - addresses: - ip: 1.2.3.4 ports: - port: 9376