Kubernetes ingress

 ( akoscomp | 2019. június 11., kedd - 14:42 )

Terraform és matchbox segítségével telepítettem CoreOS alapokon egy Kubernetes klasztert (1 controller, 2 node).
Minden tökéletesen működik addig a pillanatig, hogy ingress segítségével 80/443-as porton elérhetővé akarok tenni egy service-t.
A probléma szerintem ott van, hogy nem rendel IP-t a rendszer az ingress-hez, és foglalmam sincs, hogy ezt hogy tudom konfigurálni.
Ugyanezekkel a lépésekkel minkube esetén minden tökéletesen működik. A DNS IP/névfeloldás oda-vissza működik.

Ez a terraform konfigfájlom:

module "cluster" {
source = "git::https://github.com/poseidon/typhoon//bare-metal/container-linux/kubernetes?ref=v1.14.1"

providers = {
local = "local.default"
null = "null.default"
template = "template.default"
tls = "tls.default"
}

# bare-metal
cluster_name = "cskube2"
matchbox_http_endpoint = "${var.matchbox_http_endpoint}"
os_channel = "coreos-stable"
os_version = "2079.3.0"

# default iPXE firmware (used in dnsmasq image) doesn't offer https
download_protocol = "http"

# configuration
k8s_domain_name = "ks10.valami.com"
ssh_authorized_key = "${var.ssh_authorized_key}"
asset_dir = "assets"
cached_install = "true"

# machines
controller_names = ["ks11"]
controller_macs = ["00:50:56:87:4d:fe"]
controller_domains = ["ks11.valami.com"]

worker_names = ["ks12","ks13",]

worker_macs = ["00:50:56:87:0a:b7","00:50:56:87:07:5c"]

worker_domains = ["ks12.valami.com","ks13.valami.com"]
}

Valakinek van ötlete mit hagyok ki vagy hogy kell IPket rendelni az ingress-hez?

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Nem ismerem pontosan ezt a typhoon-os kubernetes telepítési módot, de nem lehetséges, hogy alapból nincs benne Ingress Controller?

Azt tudni kell, hogy kubernetes-ben az Ingress az csak egy metaadat. Attól, hogy felveszel egy Ingress-t, még nem történik semmi. Kell hozzá egy működő Ingress Controller, ami kiolvassa a definiált Ingress-eket, és az alapján fogja ténylegesen megcsinálni a bejövő kérések továbbirányítását.

Én ezt nézném meg:
https://github.com/poseidon/typhoon/blob/master/docs/addons/ingress.md

Az ingress-t "telepítettem":
git clone https://github.com/nginxinc/kubernetes-ingress.git
kubectl apply -f common/ns-and-sa.yaml
kubectl apply -f common/default-server-secret.yaml
kubectl apply -f common/nginx-config.yaml
kubectl apply -f rbac/rbac.yaml
kubectl apply -f deployment/nginx-ingress.yaml
kubectl apply -f daemon-set/nginx-ingress.yaml
kubectl create -f service/nodeport.yaml

kubectl get pods --namespace=nginx-ingress
NAME READY STATUS RESTARTS AGE
nginx-ingress-4z7fm 1/1 Running 0 8d
nginx-ingress-6957586bf6-9s4wv 1/1 Running 4 8d
nginx-ingress-lkcw2 1/1 Running 0 8d

és fut is minden node-on

Nekem egy kicsit fura, hogy deployment-ként és daemon-set-ként is szerepel. Ez nem lehet gond?

Kitöröltem a deploymentet, de semmi változás.

Létrehoztam a Typhoon féle ingress-t is de itt sem rendel hozzá külső IP-t illetve látszik, hogy a nodeokon nem nyitja meg a 80 és 443 portokat.

Mit értesz az alatt, hogy "külső IP-t rendel hozzá"? Ilyen esetben az ingress és az ingress controller nem szokott semmiféle külső IP-t hozzárendelni, hanem minden node-nak a normál IP címén a 80-as és a 443-as porton érhető el az ingress controller. Van valami külső (kubernetes-től független) load balancer-ed? Mert a leírás alapján eddig ezt nem láttam.

Rosszul foglamaztam, külső IP alatt a node-ok ip-jét értettem.

Találtam egy furcsaságot, ami okozhatja a problémát:

kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION EXTERNAL-IP
ks11.valami.com Ready controller,master 11d v1.14.1 none
ks12.valami.com Ready node 11d v1.14.1 none
ks13.valami.com Ready node 11d v1.14.1 none

Az EXTERNAL-IP none, tehát a kubernetes nem tudja milyen külső IP címei vannak, és ez lehet egy oka annak, hogy nem tudja bindolni a 80as portot egy IP-hez.

A kérdés adott, vajon hol kellene ezt az IP-t definiálni a kubernetes-nek, vagy miért nem jön rá a kubernetes magától?

Elnéztem, másoknál is csak az internal ip jelenik meg az external szintén none.

Azt tippelem, hogy szükséged van egy metallb-re, ami egy általad definiált IP tartományból tud kiosztani ip címeket.

Up! Itt a megoldás a problémádra :)

Nem, a metallbnek semmi köze az ingressekhez. Az ingresst az ingresst controller szolgálja ki (ami tipikusan egy vagy több nginx példány), ami attól függően érhető el, hogy az hogy van bekonfigolva:
Lehet host networkinges pod, akkor azokon a gépeken, amiken fut a pod (ha daemonset, akkor gyakorlatilag az összes worker node-on) közvetlenül elérhető lesz az nginx (tehát az összes ingressben beállított URL).
Ha nem host networkinggel van definiálva a pod, akkor az ingress controllernek kell egy service definíció, amin keresztül elérhető lesz. Itt már szóba jöhet a metallb, ha LoadBalancer típusú service-t szeretnél (gyak ez is olyan mint az ingressnél, hogy a LoadBalancer típusú service igazából önmagában nem sokat ér, kell hozzá egy Load Balancer, ami kezeli azt, ez lehet akár a metallb is).
És amúgy amiről eddig nem esett szó, hogy a DNSt is kezelni kell, hogy a klienseken az ingressnél megadott URL úgy oldódjon fel, hogy eltalálni a kérés az ingress controllerbe. Ez is nyilván attól függ, hogy az ingress controller milyen módon érhető el.

Én még most ismerkedem ezzel az egésszel de úgy olvastam mindenütt hogy a service-t expose-olni kell és utánna tudod ingress-el szabályozni a működését és ha jól értem akkor kapna külső ipt is. Ha:
kubectl describe services "my-service"
kiadod neked van ott load-balancer ip?

Expose megvolt.
kubectl describe service nginx-deploy-main
Name: nginx-deploy-main
Namespace: default
Labels: run=nginx
Annotations:
Selector: run=nginx-main
Type: ClusterIP
IP: 10.3.101.153
Port: 80/TCP
TargetPort: 80/TCP
Endpoints: 10.2.232.13:80
Session Affinity: None
Events:

A node ip cime 10.10.128 osztály.

szokjunk mar le errol az osztalyrol, kurvareg ota CIDR van...

Kifejtenéd bővebben.
Minden IP-t a kubernetes osztott ki, és semmit nem állítottam be.

Arra celzott, hogy ne azt ird, hogy A, B, 10.10.128 osztalyos a cim, hanem add meg a cidr 10.10.128.0/28

-
First impressions of the new Cloud Native programming language Ballerina

Oké, tehát ha arra az ipre curl vagy akármit futtatsz a 80/443-as portra akkor nem történik semmi , még az nginx sem válaszol?

Nem semmi nem jön be.
A két node-on nincs nyitva a 80-as port, tehát nincs is hogy bejöjjön bármi.

A fenti ip címek azok clusteren belüli címek, nem is fogod elérni kivülről. A konténerek közötti hálózat valójában. Neked a metallb-re van szükséged vagy azt mondod a service-nek, hogy nodeport-on legyen kinyitva. Ekkor egy 32xxx nagyságrendű porton tudod majd elérni a szolgáltatásodat.

Ahogy látom az ingress is ugyanazt csinálja mint a metallb, csak más layer-ne.
Metallb-vel amúgy 8080 porton elértem az nginx-et.
Ezt gondolom könnyen átteszem 80-as portra, de így minden szolgáltatást külön IP-n kell kezelni, az ingress pedig meg tudja oldani 1 IP-n.

Igen meg tudja oldani az ingress, ha van olyan clusteren kivülről is elérhető ip, amit "oda tudsz adni" az ingressnek. Ennek a megvalósításában segít neked a metallb. Ezért is javasoltam, hogy használd.

Na várj.. Szerintem kicsit keversz 1-2 dolgot.. Ha expose-olni akarsz valamit, akkor ahhoz kell egy service-t definiálnod, aminek a label selectora az adott deploymentre / POD-ra mutat, majd a service-t kell expose-olnod.. Expose-ra viszont több lehetőség is adott:
- ClusterIP: A cluster CNI pluginja által létrehozott virtuális SDN hálón belülről kapsz egy IP-t és azon keresztül tudod elérni a szolgáltatásod.. Kifelé ezzel nem expose-olsz
- Node Port: Minden Kubernetes worker csinál egy iptables szabályt magának, ami majd aztán a megfelelő irányba forwardolja a bejövő csomagot. Amennyiben a workerek rendelkeznek külsős IP-vel, úgy ezzel a megoldással lényegében kívülről elérhető szolgáltatást kapsz..
- Load Balancer: Egy külsős LB-re bízod a forgalom irányítását, és majd az forwardolja be kívülről az adatot

Az így létrehozott expose fölé tudsz még egy Ingress controller-t definiálni (alapból Nginx Ingress), ami alapból HTTP/HTTPS kapcsolatokat képes Load balance-olni, úgy hogy az eredményt a cluster fő elérési útja fogja majd kiszolgálni (amolyan virtualhost jeleggel).
Tehát ha van egy k8s clustered, amit elérsz a server.mydomain.com-on, akkor az ingress controller ez fölé tud neked felhúzni egy szabályt, ami aztán halgat mondjuk a http://server.mydomain.com/testapp, vagy a http://testapp.server.mydomain.com/ -ra..

Itt egy jó példa arra, hogy ez hogy is áll össze (mi mire mutat): https://medium.com/@dwdraju/how-deployment-service-ingress-are-related-in-their-manifest-a2e553cf0ffb

Ami viszont fontos: Olyan külsőleg elérhető plusz IP-t nem tud neked adni, amivel már most nem rendelkezel.. Szóval vagy a Kubernetes node-jaid 1ik IP-jére tudod ráaggatni a szolgáltatásod, vagy megelégszel a belsős CNI network-ből kapott IP-vel, az viszont csak belsőleg használható

Edit: Lehet Nginx Ingress-el HTTP/HTTPS-en kívüli expose-t is csinálni, viszont az egy-az-egy kapcsolat lesz, tehát az így expose-olt portot nem tudod elosztani több deployment között, mivel a selector 1 adott service-re fog mindig mutatni (szemben a virtualhost-os mókával, aminél a path vagy a host írja le, hogy melyik service-re kell forwardolni a bejövő adatot.
Egy viszonylag érthető példa: https://gist.github.com/superseb/ba6becd1a5e9c74ca17996aa59bcc67e
____________________________________
Az embert 2 éven át arra tanítják hogyan álljon meg a 2 lábán, és hogyan beszéljen... Aztán azt mondják neki: -"Ülj le és kuss legyen!"..

Megcsináltam végig a folyamatot, létrehoztam egy Deploymentet (sima alap nginx), létrehoztam egy servcie-t hozzá NodePort típusút, és egy Ingress szabályt. Evvel a folyamattal (fix ezekkel a ymlkel) pl egy minikube klaszterben 80-as porton elértem az nginx-et, a több node-os, vasra telepített k8s klaszterben viszont nem érem el a node-ok IP címein.
10.10.128.111-113 IP-n érhetőek el a node-ok, és egyik IP-n sem érhető el a 80-as port (eleve nem hallgat semmi a 80-as porton).

A gond valahol ott lehet, hogy a kubernetes nem tudja, hogy a 10.10.128.xxx IP-n kellene kitegye az ingress 80-as portját.

Ami még közben eszembe jutott, hogy a docker nem települt rendesen, elvégre a kubernetes csak egy orchestrator de a hálózatra a dolgokat a docker köti rá.
Így a dockert elemezve már látszik is a probléma:
docker network inspect bridge
- látszik, hogy az ingress pod-ja nincs benne a bridge hálózatban, tehát nincs is, hogy elérhető legyen a 10.10.128.x ip-n

docker ps-nél pedig nincs PORT hozzárendelve:
5a4e8027b36a k8s.gcr.io/pause:3.1 "/pause" 24 hours ago Up 24 hours k8s_POD_nginx-ingress-pvnnt_nginx-ingress_a321a30d-8cd6-11e9-b8aa-005056874dfe_0

minikube esetén:
9d729d3324aa k8s.gcr.io/pause:3.1 "/pause" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:18080->18080/tcp k8s_POD_nginx-ingress-controller-586cdc477c-q59qr_kube-system_c4e44647-8694-11e9-8399-0800276ec518_1

Vajon nálam van valami egyedi bug (3x újrahúztam a kalsztert, 2x terraforms-al, egyszer kézzel), vagy valahol kihagyok valamit a kubernetes vagy ingress konfigból?

Egyrészt a kubernetesben sok különböző networking használható, szinte biztos, hogy a te installációd nem az alap docker networking módszerrel megy. Ezért is lehet, hogy ott nem fogsz sok mindent látni.

Másrészt még mindig nem értem, hogy miért a 10.10.128.xxx IP-n akarod látni az Ingress Controllert. Azt tipikus esetben a node-ok valódi (nem kubernetesen belüli) IP címén kell látnod.

Valószínüleg összekeveredtél a rétegek és a protokollok között. Szóval az első lépés, hogy az ingress controller elérhető legyen kívülről (szerintem ez az a lépés, ami nem sikerült):

A legegyszerűbb megoldás, ha DaemonSet-ként deployolod az ingress controllert, és host networkingre definiálod a podot, így a pod közvetlenül a host VM hálózati eszközét tudja használni, szóval az nginx közvetlenül megnyitja a host VM 80/443-as portját. Ez esetben nincs szükséged service definícióra, mert a pod közvetlenül elérhető kívülről.

Egy picit bonyolultabb eset, ha sima deploymentként deployolod és NodePortos service-ként teszed elérhetőve az ingress controllert. Ekkor hogy a NodePort porton az összes node-on (még a mastereken is (még konkrétabban ahol kube-proxy pod fut)) elérhetővé válik az ingress controller. De ez a port nem a 80-as port lesz, hanem egy random port valahol a 30000-32767 tartományban (megintcsak ez csak a default, amit persze át lehet állítani) Ahhoz, hogy ez működni tudjon értelmesen (azaz a 80/443-as porton) szükséged van egy kubernetesen kívüli loadbalancerre, ami akár lehet metallb, mint ahogy fentebb szerepelt, de ez esetben nem NodePortos servicet kell definiálni, hanem LoadBalancerest (megjegyeznem amúgy, hogy a különböző service típusok egymásra építenek, tehát ClusterIP<-NodePort<-LoadBalancer, szóval a LoadBalanceres service egyben NodePortot is és ClusterIP-t is definiál), de akár az is működhet, hogy vagy ipvsadm-mel vagy iptables-szel forwardolod azokon a node-okon ahol a pod fut (vagy akár mindegyikeről, vagy külső VM-ekről, vagy igazából bárhonnan) a forgalmat a 80(/443)-as portról a NodePort port(ok)ra (szóval igazából ez ilyen szegény ember load balancere).

(kicsit több részlet itt: https://kubernetes.github.io/ingress-nginx/deploy/ )

Ha ez megvan, akkor jársz ott, hogy elérhető az ingress controller kívülről. Ezt természetesen tudod ellenőrizni egy curl-lel konkrét IP címet megadva. De amíg ez nem működik, addig nincs értelme létrehozni azokat a podokat, amiket amúgy tesztelni akarsz.

Szóval nem hinném, hogy a clustered vagy a docker lenne rosszul telepítve, nagyobb a valószínüsége, hogy valamit nem sikerült rendesen beállítani. Minikube egy nagyon leegyszerűsített cluster, sok minden nem úgy történik benne, mint az igaziban, szóval nem biztos, hogy van jelentőssége azzal összehasonlítani.

Amúgy megjegyezném, hogy ClusterIP-s servicenek is elégnek kell lennie az ingress mögött, nem kell NodePortosnak lennie.

MEGOLDÁS
A problémát a LoadBalancer hiánya okozata.
Hozzáadtam a klaszterhez egy metallb-t a következő konfiggal:


apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: my-ip-space
protocol: layer2
addresses:
- 10.10.128.128/28

és az ingress a megadott tartományból kapott egy external IP-t, amin keresztül már a 80/443 porton elérhetőek voltak a kipakolt aplikációk.