Kubernetes

From berki WIKI
Revision as of 15:05, 5 May 2019 by Adam (talk | contribs) (Logikai építőkockák)

Jump to: navigation, search


Kubernetes felépítése

Logikai építőkockák

  • Container:
  • Pod:
  • ReplicaSet:
  • Deployment:
  • Service:
  • Endpoint:
  • Namespace
  • Network Policies
ClipCapIt-190330-184913.PNG



Namespace

https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/

Infrastruktúra elemek

ClipCapIt-190330-193336.PNG



ClipCapIt-190313-214212.PNG

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

ClipCapIt-190331-000406.PNG

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

ClipCapIt-190331-231800.PNG


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.
TipIcon.png

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.

ImportantIcon.png

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.

  1. 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:

  1. 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