Difference between revisions of "Kubernetes"

(Network policy)
 
(74 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
[[Kubernetes alapok]]
  
 +
[[Google Kubernetes Engine]]
  
=Kubernetes felépítése=
+
[[Openshift basics]]
  
 +
[[Helm]]
  
==Logikai építőkockák==
+
[[Kubernetes parancsok]]
 
 
* Container:
 
* Pod:
 
* ReplicaSet:
 
* Deployment:
 
* Service:
 
* Endpoint:
 
* Namespace
 
* Network Policies
 
 
 
:[[File:ClipCapIt-190330-184913.PNG]]
 
 
 
 
 
 
 
 
 
=== Namespace ===
 
https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
 
 
 
==Infrastruktúra elemek==
 
 
 
 
 
:[[File:ClipCapIt-190330-193336.PNG]]
 
 
 
 
 
 
 
 
 
:[[File:ClipCapIt-190313-214212.PNG]]
 
 
 
=Telepítés=
 
 
 
 
 
'''kubectl'''
 
 
 
<pre>
 
$ 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
 
</pre>
 
 
 
<pre>
 
$ kubectl version --output=yaml
 
</pre>
 
 
 
 
 
'''Minikube'''
 
<pre>
 
$ 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
 
</pre>
 
 
 
'''kvm2 driver install'''
 
<pre>
 
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-kvm2 \
 
  && sudo install docker-machine-driver-kvm2 /usr/local/bin/
 
 
 
$ minikube version
 
</pre>
 
 
 
 
 
'''Minikube indítása'''
 
<pre>
 
$ 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) ...
 
</pre>
 
 
 
Letölti a minikube.iso image-et a /home/adam/.minikube/cache/iso/ mappába, és innen létrehoz egy kvm vm-et:
 
 
 
<pre>
 
# virsh list
 
Id    Name                          State
 
----------------------------------------------------
 
1    minikube                      running
 
</pre>
 
 
 
 
 
 
 
 
 
==Minikube parancsok==
 
<pre>
 
$ minikube dashboard
 
</pre>
 
 
 
 
 
 
 
A minikube itt mutatja meg, hogy egy adott service hol érhető el:
 
<pre>
 
# minikube service <service-name> --url
 
</pre>
 
 
 
 
 
Be lehet ssh-zni a vm-be mint a docker-machine ssh nál.
 
<pre>
 
# minikube ssh  -
 
</pre>
 
 
 
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.
 
<pre>
 
# kubectl config view
 
apiVersion: v1
 
clusters:
 
- cluster:
 
    certificate-authority: /root/.minikube/ca.crt
 
    server: https://192.168.42.224:8443
 
  name: minikube
 
</pre>
 
 
 
 
 
 
 
==Nodes==
 
 
 
Az összes node listázása.
 
<pre>
 
# kubectl get nodes
 
NAME      STATUS  ROLES    AGE  VERSION
 
minikube  Ready    master  11m  v1.13.4
 
</pre>
 
Megfelel a swarm-ban: docker node ls parancsnak.
 
 
 
=Pod=
 
 
 
:[[File:ClipCapIt-190331-000406.PNG]]
 
 
 
A POD-ot úgy kell elképzelni, mint egy egyedi image futtató környezet, tehát nem pusztán egy plusz réteg a docker konténer körül. Ha messziről nézzük, akkor a pod, ha csak egy konténer van benne megfelel egy natív docker konténernek. A docker konténer a Linux virtualizációs eszközökkel teremet egy izolált Linux futtató környezetet az image-nek. Az izolációhoz eszközei:
 
* chroot: fájl rendszer izoláció
 
* chgroup: erőforrás izoláció (CPU, network, IO..)
 
* namespace: process izoláció, a névteren belül futó processzek egy saját sub-tree-t fognak csak látni az eredeti process fából, aminek úgy fogják látni, hogy a gyökere az 1-es process, ami a valóságban egy ága az eredeti process fának.
 
 
 
A POD ezen izolációs eszközökkel részben újra gombolja a natív docker konténert, részben meg meghagyja a natív docker funkciókat. Az egy POD-ban futó konténerek közös hálózati névtérbe kerülnek, vagyis osztoznak a hálózati erőforrásokon, viszont minden egyes konténer saját fájlrendszerrel rendelkezik, tehát a fájlrendszer izoláció megegyezik a natív docker konténer futtatással.
 
:[[File:ClipCapIt-190506-194509.PNG]]
 
Ebből következik, hogy a localhost-on az egy POD-ba futó konténerek elérik egymást a megfelelő portokon, minden további hálózati beállítás nélkül tudnak a localhost-on kommunikálni egymással, viszont egymás fájlrendszerét nem tudják olvasni.
 
 
 
Az ipari standard szerint egy pod-ba csak egy konténert szokás rakni, így a valóságban általában elmosódik a POD és a natív docker konténer között a különbség, mivel a POD-ban futó egy szem konténer mind hálózati mind fájlrendszer szinten teljesen izolálva fut a külvilágtól.
 
 
 
 
 
==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.
 
<pre>
 
$ kubectl run db --image mongo
 
</pre>
 
 
 
 
 
===Deklaratív megközelítés===
 
 
 
 
 
<source lang="C++">
 
apiVersion: v1
 
kind: Pod
 
metadata:
 
  name: go-demo-2
 
  labels:
 
    app: myapp
 
spec:
 
  containers:
 
  - name: db
 
    image: mongo:3.3
 
 
 
</source>
 
 
 
 
 
<pre>
 
# 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
 
</pre>
 
 
 
 
 
 
 
==Pod-ok kezelése==
 
 
 
 
 
Pod-ok listázása
 
<pre>
 
# kubectl get pods
 
NAME                  READY  STATUS              RESTARTS  AGE
 
db-7fdd878ff9-7v66g  0/1    ContainerCreating  0          66s
 
</pre>
 
 
 
Belépés a pod-ban futó konténerekbe:
 
<pre>
 
# kubectl exec -it <pod név> /bin/bash
 
</pre>
 
 
 
Ha több konténer is van a pod-ban, akkor a -c vel meg kell adni a konténer nevét:
 
<pre>
 
# kubectl exec -it -c db dbstack /bin/bash
 
</pre>
 
 
 
Ha több konténer is van a pod-ban, akkor a pod neve után meg kell adni a konténer nevét.
 
<pre>
 
# kubectl logs dbstack -c db
 
</pre>
 
 
 
 
 
Minden kubernetes elem listázása:
 
<pre>
 
# 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
 
</pre>
 
 
 
 
 
 
 
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.
 
<source lang="Python" highlight="13-19">
 
[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
 
</source>
 
 
 
A '''get''' paranccsal is ugyan ezt a részletességet érhetjük el a '''-o json''' kapcsolóval.
 
<source lang="xml">
 
# 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
 
                    }
 
...
 
</source>
 
 
 
 
 
 
 
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.
 
<pre>
 
# 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
 
</pre>
 
 
 
 
 
===-o kapcsoló használata===
 
{| class="wikitable"
 
! scope="col"| Név
 
! scope="col"| 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.
 
<pre>
 
# kubectl get -f pod-db.yaml -o json
 
{
 
    "apiVersion": "v1",
 
    "kind": "Pod",
 
    "metadata": {
 
        "creationTimestamp": "2019-03-13T19:49:30Z",
 
        "labels": {
 
            "type": "db",
 
            "vendor": "MongoLabs"
 
        },
 
...
 
</pre>
 
 
 
 
 
Részletes pod lista. A lényeg itt az IP cím.
 
<pre>
 
# 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>
 
</pre>
 
 
 
 
 
első pod a listáról:
 
<pre>
 
# kubectl get pods -o name | tail -1
 
</pre>
 
 
 
<br>
 
===Szűrés===
 
Listázzuk ki JSON-ban a pod részleteket.
 
<source lang="json">
 
    "status": {
 
        ...
 
        "hostIP": "192.168.122.228",
 
...
 
</source>
 
 
 
Szűrni a '''-o jsonpath''' -al lehet. <br>
 
Mindig úgy kell szűrni, hogy a legfelsőbb szintű elem elé teszünk egy .-ot. Majd megadjuk a path-t.
 
<pre>
 
# kubectl get -f pod-db.yaml -o jsonpath="{.status.hostIP}"
 
192.168.122.228
 
</pre>
 
 
 
 
 
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]<br>
 
Pl. az összes konténer nevét így listázhatjuk:
 
<pre>
 
# kubectl get -f pod-db.yaml -o jsonpath="{.spec.containers[*].name}"
 
db api
 
</pre>
 
 
 
<br>
 
===Címkék===
 
A selector-ok címék alapján működnek.
 
 
 
Címke hozzáadása egy node-hoz:
 
<pre>
 
# kubectl get node
 
NAME      STATUS  ROLES    AGE  VERSION
 
minikube  Ready    master  22d  v1.13.4
 
</pre>
 
<pre>
 
# kubectl label node minikube disktype=ssd
 
node/minikube labeled
 
</pre>
 
<source lang="java" highlight="6">
 
# kubectl describe node minikube
 
Name:              minikube
 
Roles:              master
 
Labels:            beta.kubernetes.io/arch=amd64
 
                    beta.kubernetes.io/os=linux
 
                    disktype=ssd 
 
...
 
</source>
 
<source>
 
# 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,..
 
</source>
 
 
 
Szintaxis:
 
<pre>
 
# kubectl label <resource type: node, pod, ...> <resource név> <címke neve>=<címke értéke>
 
</pre>
 
 
 
 
 
nodeSelector:
 
  labelName: labelvalue
 
 
 
 
 
Címke felrakása pod-ra:
 
<pre>
 
# kubectl label pod go-demo-2 type=example
 
pod/go-demo-2 labeled
 
</pre>
 
<pre>
 
# kubectl get pod --show-labels
 
NAME        READY  STATUS    RESTARTS  AGE  LABELS
 
go-demo-2  1/1    Running  1          23h  app=myapp,type=example
 
</pre>
 
 
 
 
 
Címke törlése
 
<pre>
 
# 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
 
</pre>
 
 
 
<br>
 
 
 
===Health check===
 
<br>
 
* '''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
 
 
 
<source lang="C++">
 
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
 
</source>
 
 
 
<br>
 
 
 
 
 
Három változatuk van.
 
* command futtatása
 
* http rest hívás
 
* tcpSocket
 
 
 
<br>
 
'''Command'''<br>
 
<pre>
 
livenessProbe:
 
  exec:
 
    command:
 
    - cat
 
    - /tmp/healthy
 
</pre>
 
 
 
<br>
 
'''Http'''<br>
 
* path
 
* port
 
* httpHeaders
 
<pre>
 
    livenessProbe:
 
      httpGet:
 
        path: /healthz
 
        port: 8080
 
        httpHeaders:
 
        - name: Custom-Header
 
          value: Awesome
 
      initialDelaySeconds: 3
 
      periodSeconds: 3
 
</pre>
 
 
 
<br>
 
'''Socket'''<br>
 
<pre>
 
livenessProbe:
 
  tcpSocket:
 
    port: 8080
 
</pre> 
 
 
 
<br>
 
{| class="wikitable"
 
! scope="col"| Név
 
! scope="col"| 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.
 
|}
 
 
 
<br>
 
 
 
=ReplicaSets=
 
 
 
==Áttekintés==
 
:[[File: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:
 
<pre>
 
  selector:
 
    matchExpressions:
 
      - {key: app, operator: In, values: [soaktestrs, soaktestrs, soaktest]}
 
      - {key: teir, operator: NotIn, values: [production]}
 
</pre>
 
 
 
A pod-hoz hasonlóan a dekleratív megközelítés szellemében, a replicaSet-et is yaml fájllal kell definiálni:
 
<source lang="C++">
 
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
 
</source>
 
 
 
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:
 
<pre>
 
environment in (production, qa)
 
tier notin (frontend, backend)
 
partition
 
!partition
 
</pre>
 
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:
 
<pre>
 
# kubectl get pod -l app=myapp,type=example
 
NAME        READY  STATUS    RESTARTS  AGE
 
go-demo-2  1/1    Running  3          8d
 
</pre>
 
 
 
 
 
===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.
 
<source lang="C++" highlight="9-11">
 
apiVersion: v1
 
kind: Service
 
metadata:
 
  name: db-svc
 
spec:
 
  type: ClusterIP
 
  ports:
 
    - port: 27017
 
  selector:
 
    type: db
 
    service: mongo-db
 
</source>
 
 
 
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.
 
<source lang="C++">
 
apiVersion: apps/v1
 
kind: ReplicaSet
 
metadata:
 
  name: rs-db
 
spec:
 
  replicas: 1
 
  selector:
 
    matchLabels:
 
      type: db
 
      service: mongo-db
 
  template:
 
</source>
 
 
 
 
 
<br>
 
<br>
 
 
 
==ReplicaSet kezelése==
 
 
 
A '''get''' parancsban ReplicaSet esetén az '''rs'''-t kell megadni a '''pod''' helyett:
 
<pre>
 
# 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
 
</pre>
 
 
 
 
 
Ugyan úgy használhatjuk a '''describe''' parancsot is az rs-el mint a pod esetében:
 
<pre>
 
# 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
 
</pre>
 
 
 
 
 
<pre>
 
# 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
 
</pre>
 
 
 
 
 
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.
 
<pre>
 
# kubectl delete -f rs/go-demo-2.yml --cascade=false
 
</pre>
 
 
 
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.
 
<pre>
 
# kubectl create --save-config
 
</pre>
 
 
 
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:
 
<pre>
 
# kubectl get rs go-demo-2 -o yaml
 
</pre>
 
 
 
<br>
 
 
 
 
 
=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...
 
 
 
TODO: Alapértelmezetten minden pod minden erőforrással kommunikál. Ezt a network policy-val lehet szűkíteni.
 
TODO: namespace: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
 
 
 
===Konténerek egy pod-ban===
 
... 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.
 
 
 
<source lang="C++">
 
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"]
 
</source>
 
A network-utils image-ből készülő konténernek végtelen ciklusban adtunk munkát, hogyne álljon le, ahogy létrejön.
 
 
 
<pre>
 
# kubectl create -f pod-db.yaml
 
pod/go-demo-2 created
 
</pre>
 
 
 
 
 
Lépjünk be a nettsest konténerbe:
 
<pre>
 
# kubectl exec -it -c nettest go-demo-2 /bin/sh
 
#
 
</pre>
 
 
 
Majd a localhost-on nézzük meg mit találunk a 80-as porton:
 
<pre>
 
# curl localhost:80
 
<!DOCTYPE html>
 
<html>
 
<head>
 
<title>Welcome to nginx!</title>
 
</pre>
 
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)}}
 
 
 
 
 
Linux-ban a névterekben lévő virtuális hálózatokat össze lehet kötni a host root hálózatával úgynevezett '''Veth''' (Virtual Ethernet Device) hálózati csatolókkal. Minden pod és a host root hálózata között létrejön egy Veth pár. A Veth párok pedig hálózati híddal (bridge) vannak összekötve a root hálózatban. Ezeket a hálózati beállításokat automatikusan létrehozza a Kubernetes egy cluster-en  belül. Ezért éri el minden pod a host gép hálózati interfészeit és viszont.
 
:[[File:ClipCapIt-190506-232813.PNG]]
 
A veth interfészek a root hálózati névtérben Linux Ethernet bridge-el vannak összekötve (Layer 2  kapcsolat). Ezért tud minden pod az összes többi pod-al kommunikálni. 
 
A Pod-to-pod kommunikáció node-ok között is működik, de az már hálózatfüggő hogy pontosan hogyan van megvalósítva. Pl. AWS-en erre több lehetőség is van.
 
 
 
 
 
 
 
 
 
Hozzunk létre egy nginx pod-ot a kubectl run paranccsal (A run parancs a pod-on kívül létre fog hozni egy ReplicaSet-et és egy Deploymenet-et is. ).
 
<pre>
 
# kubectl run webserver --image nginx
 
deployment.apps/webserver created
 
</pre>
 
Keressük meg az IP címét:
 
<pre>
 
# 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>
 
</pre>
 
 
 
 
 
Hozzunk létre szintén 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, ahogy létrejön a pod a konténer belsejében futó sh shell-hez fogunk kapcsolódni. Ehhez a kubernetes itt is alapértelmezetten létre fog hozni egy deployment-et és egy replicaSet-et. De ez most nem fontos.
 
<pre>
 
$ kubectl run -it netpod --image amouat/network-utils -- sh
 
#
 
</pre>
 
Keressük meg a pod IP címét.
 
<pre>
 
# ifconfig
 
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:06 
 
          inet addr:172.17.0.6
 
</pre>
 
 
 
Most a netpod belsejéből kérjük le a webserver pod index.html oldalát:
 
<pre>
 
# curl 172.17.0.7
 
<!DOCTYPE html>
 
<html>
 
<head>
 
<title>Welcome to nginx!</title>
 
</pre>
 
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:
 
<pre>
 
# minikube ssh
 
                        _            _           
 
            _        _ ( )          ( )         
 
  ___ ___  (_)  ___  (_)| |/')  _  _ | |_      __ 
 
/' _ ` _ `\| |/' _ `\| || , <  ( ) ( )| '_`\  /'__`\
 
| ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )(  ___/
 
(_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____)
 
 
 
$
 
</pre>
 
<pre>
 
$ curl 172.17.0.7
 
<!DOCTYPE html>
 
<html>
 
<head>
 
<title>Welcome to nginx!</title>
 
</pre>
 
Látható hogy a node is elérte a pod-ban futó konténert.
 
 
 
===Network policy===
 
https://kubernetes.io/docs/concepts/services-networking/network-policies/
 
 
 
A network policy segítségével lehet korlátozni a pod-ok közötti kommunikációt, ami alapesetben minden pod között adott.
 
 
 
<source lang="C++">
 
apiVersion: networking.k8s.io/v1
 
kind: NetworkPolicy
 
metadata:
 
  name: test-network-policy
 
  namespace: default
 
spec:
 
  podSelector:
 
    matchLabels:
 
      role: db
 
  policyTypes:
 
  - Ingress
 
  - Egress
 
  ingress:
 
  - from:
 
    - ipBlock:
 
        cidr: 172.17.0.0/16
 
        except:
 
        - 172.17.1.0/24
 
    - namespaceSelector:
 
        matchLabels:
 
          project: myproject
 
    - podSelector:
 
        matchLabels:
 
          role: frontend
 
    ports:
 
    - protocol: TCP
 
      port: 6379
 
  egress:
 
  - to:
 
    - ipBlock:
 
        cidr: 10.0.0.0/24
 
    ports:
 
    - protocol: TCP
 
      port: 5978
 
</source>
 
 
 
<br>
 
 
 
=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.
 
<pre>
 
# kubectl expose rs nginx-rs --name=http --port=80 --type=NodePort --target-port=80
 
</pre>
 
 
 
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.
 
 
 
<pre>
 
# 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
 
</pre>
 
 
 
 
 
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ő.
 
 
 
 
 
<pre>
 
# 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
 
                                                  ^^^^^^
 
</pre>
 
 
 
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:
 
<pre>
 
# 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
 
</pre>
 
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.
 
 
 
<pre>
 
# 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
 
</pre>
 
 
 
------------------------------
 
 
 
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.
 
 
 
<pre>
 
# 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
 
</pre>
 
 
 
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:
 
<pre>
 
kind: Endpoints
 
apiVersion: v1
 
metadata:
 
  name: my-service
 
subsets:
 
  - addresses:
 
      - ip: 1.2.3.4
 
    ports:
 
      - port: 9376
 
</pre>
 

Latest revision as of 19:15, 18 January 2020