Směrování externího HTTP provozu do aplikace

Poslední aktualizace 4. 9. 2023


Úvod

Poznámka: Pro pochopení tohoto návodu, je důležité mít alespoň základní povědomí o jednotlivých Kubernetes objektech. Více v článku Kubernetes objekty.

Jedním z nejčastěji řešených úkolů na začátku bude návrh komunikace aplikací v Kubernetes. Některé aplikace chceme mít dostupné pouze uvnitř clusteru, další zase chceme vystavit veřejně na HTTP, případně na jiném portu. Po prvotním určení, zda má být naše služba dostupná zvenku, na nás čekají další rozhodnutí s ohledem na cenu celého návrhu, bezpečnost provozu, správu a rozšiřitelnost námi navrhovaného řešení. Pokud jsme již za fází vlastního návrhu a víme, jak má komunikace probíhat, tak nezbývá než provést konfiguraci v K8s infrastruktuře.

Komunikace v rámci podu

Existuje několik metod, jak směrovat provoz zvenku až přímo do běžící aplikace v K8s. Pojďme společně projít vše postupně opačným směrem od úplného základu, tedy stavebního kamene služby, kterou chceme mít dostupnou zvenku – kontejneru. Názorně si projdeme nastavení přes manifesty jednotlivých objektů.

Naším cílem je přístup do aplikace Hello world, která běží na portu 8080 přes HTTP url http://helloworld.masterinter.net/.

Každý kontejner je v K8s zabalen v podu. Přitom víme, že v každém podu může těchto kontejnerů běžet hned několik naráz. Komunikaci kontejnerů na úrovni podu lze snadno přirovnat ke komunikaci na úrovni klasického serveru – jednotlivé kontejnery společně mohou komunikovat přes localhost na určitém portu a síťovém namespace.

Ukázka manifestu Deploymentu, který zahrnuje 2 pody obsahující kontejner s ukázkovou aplikací „Hello World“.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-hello-world
spec:
  selector:
    matchLabels:
      app: helloworld-connect-to-service
  replicas: 2
  template:
    metadata:
      labels:
        app: helloworld-connect-to-service
    spec:
      containers:
        - name: hello-world
          image: gcr.io/google-samples/node-hello:1.0
          ports:
            - containerPort: 8080
              protocol: TCP

Komunikace v rámci podu je tedy již jasná. Naší snahou je ovšem mít dostupnou aplikaci a mít k ní přístup i mimo kontejnery. Jak tedy postupovat dál?

Komunikace mezi pody

Pro přístup k aplikacím nám slouží service. Pro propojení mezi service a aplikací slouží jednoduchý Label selektor. Ten se stanoví na úrovni podu a následně nastaví v service:

apiVersion: v1
kind: Service
metadata:
  name: service-helloworld
spec:
  selector:
    app: helloworld-connect-to-service
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Schválně jsme zvolili dost krkolomný label a selektor app: helloworld-connect-to-service. Tímto triviálním nastavením jsme docílili zpřístupnění naši aplikace, která běží ve dvou podech. Aplikace přitom poslouchá na TCP portu 8080 a nyní je již dostupná na service IP portu 80. Navíc dochází automaticky bez našeho zásahu k balancingu provozu mezi 2 pody, které jsou definovány v Deploymentu. Pokud bychom nastavili počet replik např. na 100 (replicas: 100), tak se nám naspawnuje 100 podů s naší aplikací a bez zásahu v service se nám bude při přístupu přes Cluster IP Service automaticky provoz balancovat mezi všemi 100 pody.

Ingress

Již jsme v bodě, kdy k aplikaci můžeme přistoupit v rámci našeho K8s clusteru. Připomínám, že provádíme deploy webové aplikace, kterou chceme mít dostupnou přes HTTP. Pokud bychom chtěli zpřístupnit jiný service než HTTP/HTTPS, tak by bylo nutné použít service typu NodePort nebo LoadBalancer. Zpět ovšem k našemu příkladu.

Jelikož se jedná o HTTP service, tak můžeme do provozu zahrnout ingress, který nám poskytne další možnosti konfiguraci a zejména virtual name based nebo path směrování, tj. směrování dle jmenných názvů nebo url provozovaných HTTP/S služeb. Pro vytvoření ingressu je nutné mít v clusteru nakonfigurovaný samotný Ingress Controller. Jako příklad můžeme uvést ingress-nginx, který používáme standardně i v našich instalacích. Pojďme si opět uvést příklad manifestu jednoduchého Ingress Resource.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-helloworld
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: helloworld.masterinter.net
    http:
      paths:
      - path: /
        backend:
          serviceName: service-helloworld
          servicePort: 80

V tomto manifestu je v pravidlech nastaveno následující:

  • jako virtual host budou pravidla aplikována pro hosta helloworld.masterinter.net (pokud bychom vynechali „host“, tak se nám pravidla budou aplikovat na veškerý HTTP provoz, který přijde na ingress).
  • cesta (url), která odpovídá příchozímu požadavku (http://helloworld.masterinter.net/). Pokud bychom stanovili specifičtější cestu, tak ingress bude v rámci pravidel zpracovávat pouze požadavky pro hosta s danou cestou (http://helloworld.masterinter.net/morespecificpath).
  • backend určuje návaznost mezi ingress<>service. V tomto případě definujeme název služby service-helloworld a port, na kterém service poslouchá (80).

Máme hotovo! Aktuálně je naše jednoduchá web aplikace, která běží ve 2 podech, dostupná na veřejně dostupné adrese http://helloworld.masterinter.net/.

Závěr

Možná si říkáte, na jakou veřejnou adresu máme tedy svou doménu směrovat? Odpovědí je zpravidla vám přidělená externí adresa clusteru. O finální vystavení Ingress Controlleru (IC) a nasměrování z Internetu směrem do námi definovaného Ingress Resource se stará již load balancer, který je mimo téma tohoto článku. Samozřejmě pro vystavení IC lze použít zmíněný service typu LoadBalanceru. Každý poskytovatel toto řeší svým způsobem. O tom, jakým způsobem používáme a nasazujeme LoadBalancer on-premise u nás v MasterDC se plánujeme podělit v některém z dalších článků o Kubernetes.


Máte nejasnosti nebo nápad na zlepšení článku?

Napište nám