Hogyan működik a DNS feloldás egy Kubernetes fürtön belül

A mai modern, mikroservice alapú alkalmazások világában a Kubernetes vált a konténer-orchestráció de facto szabványává. Egy ilyen dinamikus és elosztott rendszerben elengedhetetlen, hogy az egyes komponensek – a Podok – hatékonyan és megbízhatóan megtalálják egymást, valamint a külső erőforrásokat. Ennek a létfontosságú feladatnak a középpontjában áll a DNS (Domain Name System) feloldás. De hogyan is működik pontosan a DNS feloldás egy Kubernetes fürtön belül? Miért kritikus ez a rendszer stabilitása és teljesítménye szempontjából? Merüljünk el együtt a Kubernetes DNS feloldásának mélységeibe!

A Kubernetes nemcsak a konténerek futtatásáért felel, hanem egy kifinomult hálózati réteget is biztosít, amely lehetővé teszi a Podok közötti kommunikációt. Ennek a hálózati rétegnek a DNS feloldás az egyik legfontosabb sarokköve. Képzeljük el, hogy egy webalkalmazás (egy Pod) adatbázishoz (egy másik Podhoz) szeretne csatlakozni. A Podok IP-címei rendkívül dinamikusak lehetnek: egy Pod bármikor leállhat, újraindulhat, vagy átköltözhet egy másik Node-ra, miközben új IP-címet kap. Ahelyett, hogy az alkalmazások keményen kódolt IP-címeket használnának, egy stabil, emberi nyelven olvasható nevekkel operáló rendszerre van szükségük, ami képes ezeket a neveket dinamikusan IP-címekre fordítani. Ez a feladat a Kubernetes DNS-szolgáltatásáé.

A központi elem: CoreDNS

A Kubernetes kezdetben a kube-dns nevű szolgáltatást használta a DNS feloldásra, de mára a CoreDNS vált a szabványos és alapértelmezett megoldássá. A CoreDNS egy rugalmas, bővíthető DNS szerver, amelyet kifejezetten konténeres környezetekre optimalizáltak. A Kubernetesben a CoreDNS egy vagy több Pod formájában fut, általában a kube-system névtérben, és egy Service-en keresztül érhető el. Ez a Service garantálja, hogy a CoreDNS Podok meghibásodása esetén is folyamatosan elérhető marad a DNS szolgáltatás, mivel a Service automatikusan átirányítja a kéréseket az egészséges Podokhoz.

A CoreDNS konfigurációja egy ConfigMap objektumban található, amely a Corefile nevű fájlt tartalmazza. Ez a fájl határozza meg, hogy a CoreDNS hogyan dolgozza fel a DNS kéréseket, milyen zónákat felügyel, és hogyan továbbítja az ismeretlen kéréseket. Egy tipikus Corefile a Kubernetes fürtön belüli nevek feloldására vonatkozó szabályokat, valamint a külső nevek feloldására szolgáló továbbítási (forwarding) szabályokat is tartalmazza. Ez a rugalmasság lehetővé teszi a rendszergazdák számára, hogy finomhangolják a DNS viselkedését a fürt specifikus igényeihez, például belső privát zónák kezeléséhez vagy a külső DNS szerverek preferenciáihoz.

Hogyan oldják fel a Podok a belső szolgáltatásokat? (Szolgáltatásfelfedezés)

A Kubernetes DNS-szolgáltatásának egyik legfontosabb funkciója a szolgáltatásfelfedezés (Service Discovery) a fürtön belül. Amikor egy alkalmazás Pod egy másik szolgáltatást szeretne elérni, nem az adott szolgáltatást futtató Podok IP-címét használja közvetlenül, hanem a Kubernetes Service absztrakcióját. A Service egy stabil hálózati névvel és IP-címmel (a ClusterIP-vel) látja el a Podok egy csoportját, amelyek ugyanazt a funkciót látják el. Ez az absztrakció kritikus, mivel a Podok életciklusa rövid, IP-címeik dinamikusak, de a Service neve és ClusterIP-je stabil marad.

Minden egyes Kubernetes Service-hez a CoreDNS automatikusan létrehoz egy DNS bejegyzést. A leggyakoribb formátum a következő:

  • <service-name>.<namespace>.svc.cluster.local

Például, ha van egy my-app nevű Service a default névtérben, akkor az a my-app.default.svc.cluster.local néven érhető el. A Podok többsége azonban egyszerűbben is hivatkozhat ezekre a nevekre, köszönhetően a kubelet által konfigurált search tartományoknak.

Amikor egy Pod elindul, a kubelet – a Node-on futó ügynök – beállítja a Pod resolv.conf fájlját. Ez a fájl tartalmazza a DNS szerverek IP-címét (amely a CoreDNS Service ClusterIP-je), valamint a keresési tartományokat (search domains). Egy tipikus resolv.conf fájl így nézhet ki egy Podban:

nameserver 10.96.0.10  # A CoreDNS Service ClusterIP-je
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Ez a konfiguráció lehetővé teszi, hogy a Podok rövid nevekkel is hivatkozhassanak Service-ekre:

  • my-app: Ezt a nevet a search tartományok kiegészítik, így próbálja feloldani a my-app.default.svc.cluster.local nevet. Ha a Pod és a Service ugyanabban a névtérben vannak, ez elegendő.
  • my-app.other-namespace: Ezt a nevet a search tartományok kiegészítik, így próbálja feloldani a my-app.other-namespace.svc.cluster.local nevet.

Amikor egy Pod DNS kérést indít (pl. ping my-app), a kérés a nameserver bejegyzésben megadott IP-címre, azaz a CoreDNS Service-re kerül. A CoreDNS ekkor kikeresi a hozzá tartozó Service-t és annak Endpoints objektumát. Az Endpoints objektum tartalmazza azoknak a Podoknak az IP-címeit, amelyek az adott Service mögött állnak. A CoreDNS visszaküldi a kérésre az egyik Endpoints Pod IP-címét, és a Pod felépítheti a kapcsolatot.

Különleges Service típusok és DNS bejegyzéseik

A Kubernetes különböző típusú Service-eket kínál, amelyek mindegyike eltérő DNS viselkedéssel bír:

  1. ClusterIP Services: Ahogy fentebb említettük, ezekhez a Service-ekhez egy stabil ClusterIP és egy A-rekord tartozik:
    • <service-name>.<namespace>.svc.cluster.local -> ClusterIP (A record)

    A CoreDNS általában terheli meg a forgalmat (round-robin) az Endpoints Podok között, de a tényleges terheléselosztást a kube-proxy végzi a Node-okon.

  2. Headless Services: Ez egy különleges Service típus, amely nem kap ClusterIP-t. Ehelyett, amikor egy Headless Service-re hivatkoznak, a CoreDNS közvetlenül az összes mögöttes Pod IP-címét visszaadja. Ez különösen hasznos, ha az alkalmazásnak közvetlen hozzáférésre van szüksége az egyes Podokhoz (pl. állapotfüggő (stateful) alkalmazások, mint az adatbázisok). A Headless Service-ekhez a következő DNS rekordok generálódnak:
    • <service-name>.<namespace>.svc.cluster.local -> Több A-rekord, minden mögöttes Pod IP-címével.
    • <pod-name>.<service-name>.<namespace>.svc.cluster.local -> Egy A-rekord, az adott Pod IP-címével (ha a Pod neve be van állítva a hostname mezőben, ami gyakori a StatefulSet-eknél).

    Ez utóbbi lehetővé teszi az egyes állapotfüggő Podok egyedi, stabil nevekkel történő elérését, ami kritikus lehet például egy StatefulSet által kezelt adatbázis klaszter tagjainak azonosításánál.

  3. ExternalName Services: Ezek a Service-ek nem mutatnak Podokra a fürtön belül, hanem egy külső DNS névre (CNAME). Amikor egy Pod egy ilyen Service-re hivatkozik, a CoreDNS egyszerűen visszaadja az ExternalName értékét CNAME rekordként, átirányítva a kérést egy külső DNS feloldóhoz.
    • <service-name>.<namespace>.svc.cluster.local -> <external-name> (CNAME record)

    Ez hasznos lehet, ha egy külső adatbázist, vagy más szolgáltatást szeretnénk elérni egy stabil, belső Kubernetes néven keresztül.

Hogyan oldják fel a Podok a külső DNS neveket?

Amikor egy Pod olyan tartománynevet próbál feloldani, amely nem tartozik a Kubernetes belső tartományai közé (pl. google.com, api.example.com), a CoreDNS Corefile-jában található továbbítási (forwarding) szabályok lépnek életbe. Ezek a szabályok általában a CoreDNS-t arra utasítják, hogy a külső kéréseket továbbítsa a Node-ok resolv.conf fájljában megadott DNS szerverekre, vagy előre definiált, külső DNS szerverekre (pl. Google DNS: 8.8.8.8, 8.8.4.4).
Ez biztosítja, hogy a Podok ne csak a fürtön belüli erőforrásokat, hanem az interneten elérhető szolgáltatásokat is képesek legyenek elérni. A CoreDNS képes intelligensen kezelni ezeket a kéréseket, optimalizálva a teljesítményt a válaszidők csökkentésével és a megbízhatóság növelésével.

Pod szintű DNS konfiguráció: DNSPolicy és dnsConfig

A Kubernetes rendkívül rugalmas a Podok DNS konfigurációjában. Bár a kubelet alapértelmezetten beállítja a resolv.conf fájlt, ezt felül lehet írni a Pod definíciójában a dnsPolicy és dnsConfig mezők segítségével. Ez a rugalmasság lehetővé teszi, hogy egyedi hálózati igényekkel rendelkező Podok is hatékonyan működjenek a fürtön belül.

  • dnsPolicy: Meghatározza, hogyan kezeli a Pod a DNS feloldást.
    • ClusterFirst (alapértelmezett): A Pod először a fürt DNS-ére (CoreDNS) küldi a kéréseket. Ha nem találja a nevet, továbbítja a Node-on beállított DNS szerverek felé. Ez a leggyakoribb és ajánlott beállítás a legtöbb alkalmazáshoz.
    • Default: A Pod közvetlenül a Node resolv.conf fájljában szereplő DNS szervereket használja. Ez ritkán használt a legtöbb alkalmazásnál, mivel elveszíti a Kubernetes belső szolgáltatásfelfedezési képességeit, és nem tudja feloldani a fürtön belüli Service neveket.
    • None: Ez a házirend lehetővé teszi a teljesen egyedi DNS konfigurációt a dnsConfig mező segítségével. A Kubernetes figyelmen kívül hagyja a Node alapértelmezett DNS beállításait, és a dnsConfig által megadott beállításokat alkalmazza. Ez a leghatékonyabb módja a finomhangolásnak.
    • ClusterFirstWithHostNet: Hasznos, ha a Pod a Host hálózati névteret használja (hostNetwork: true). Ebben az esetben a Pod a CoreDNS-t fogja használni a fürtön belüli nevekhez, majd a Node DNS-ét a külső nevekhez, ugyanúgy, mint a ClusterFirst, de a Host hálózati beállításokat figyelembe véve.
  • dnsConfig: Csak akkor használható, ha a dnsPolicy értéke None. Lehetővé teszi, hogy expliciten megadjuk a nameservers, searches és options beállításokat a Pod resolv.conf fájljához. Ez rendkívül hasznos lehet speciális esetekben, például ha egy Podnak egy adott DNS szervert kell használnia egy belső hálózaton belül, amely nem része a Kubernetes fürtnek, vagy ha egyedi keresési tartományokra van szükség.

Példa dnsConfig használatára:

apiVersion: v1
kind: Pod
metadata:
  name: my-custom-dns-pod
spec:
  containers:
    - name: my-container
      image: nginx
  dnsPolicy: None
  dnsConfig:
    nameservers:
      - 192.168.1.100  # Egyedi DNS szerver
      - 8.8.8.8
    searches:
      - mydomain.local
      - default.svc.cluster.local
    options:
      - name: ndots
        value: "2"
      - name: edns0

Ez a konfiguráció felülírja a Pod alapértelmezett DNS beállításait, és a megadott szervereket, keresési tartományokat és opciókat használja. Fontos megjegyezni, hogy az ndots opció befolyásolja, hogy hány pontot kell tartalmaznia egy névnek ahhoz, hogy abszolút névnek tekintsék, mielőtt a keresési tartományokat hozzáadva próbálnák feloldani. Egy túl magas ndots érték lassíthatja a feloldást, mivel a DNS kliensnek több felesleges lekérdezést kell indítania a keresési tartományokkal, mielőtt a globális DNS-hez fordulna. Az alapértelmezett érték 5 Kubernetesben.

A DNS feloldás teljesítménye és hibaelhárítása

A DNS feloldás kritikus fontosságú a Kubernetes alkalmazások teljesítménye szempontjából. Lassú DNS feloldás jelentősen növelheti a kérések késleltetését (latency), ami az alkalmazás lassulásához vagy akár hibáihoz vezethet. A CoreDNS konfigurációjának optimalizálása, a megfelelő caching beállítások és elegendő erőforrás (CPU, memória) biztosítása a CoreDNS Podok számára elengedhetetlen a jó teljesítményhez. A CoreDNS több plugin-t is kínál, amelyekkel a teljesítmény tovább növelhető, például a cache plugin bekapcsolásával.

Gyakori DNS hibaelhárítási tippek Kubernetesben:

  1. Ellenőrizd a CoreDNS Podokat: Győződj meg róla, hogy a CoreDNS Podok futnak és egészségesek (kubectl get pods -n kube-system -l k8s-app=kube-dns). Ellenőrizd a logokat (kubectl logs -n kube-system -l k8s-app=kube-dns) a lehetséges hibákért.
  2. Ellenőrizd a CoreDNS Service-t: Győződj meg róla, hogy a CoreDNS Service létezik és a megfelelő ClusterIP-vel rendelkezik (kubectl get svc -n kube-system -l k8s-app=kube-dns). Győződj meg arról is, hogy a Service Endpoints-jei a CoreDNS Podokra mutatnak.
  3. Teszteld a DNS feloldást egy Podból: Indíts egy debug Podot (pl. busybox vagy alpine image-el) és próbálj meg feloldani belső és külső neveket a nslookup vagy dig parancsokkal.
    • kubectl run -it --rm --image=busybox:1.28 dns-test -- nslookup kubernetes.default
    • kubectl run -it --rm --image=busybox:1.28 dns-test -- nslookup my-app.default.svc.cluster.local (cseréld le a Service nevet és névtért)
    • kubectl run -it --rm --image=busybox:1.28 dns-test -- nslookup google.com

    Ezek a tesztek segítenek elkülöníteni, hogy a probléma a belső vagy a külső DNS feloldással van-e.

  4. Ellenőrizd a Pod resolv.conf fájlját: Lépj be egy Podba (kubectl exec -it <pod-name> -- sh) és nézd meg a /etc/resolv.conf tartalmát. Győződj meg róla, hogy a nameserver a CoreDNS Service IP-jére mutat, és a search tartományok helyesek a Pod névtér beállításai szerint.
  5. Hálózati szabályok és tűzfalak: Győződj meg róla, hogy nincsenek olyan hálózati szabályok (pl. NetworkPolicy vagy külső tűzfalak), amelyek blokkolják a DNS kéréseket a Podok és a CoreDNS Service között.

Következtetés

A DNS feloldás egy Kubernetes fürtön belül sokkal több, mint egyszerű névtől IP-címre fordítás. Ez a rendszer lelke, amely lehetővé teszi a szolgáltatásfelfedezést, a dinamikus komponensek közötti kommunikációt és az alkalmazások robusztus működését. A CoreDNS, mint központi szolgáltatás, a Service-ekkel és Endpoints-okkal együtt egy kifinomult mechanizmust biztosít, amely a Podok számára átlátszóan kezeli a hálózati topológia változásait.

A dnsPolicy és dnsConfig révén a fejlesztők és üzemeltetők finomhangolhatják a DNS viselkedést, biztosítva az optimális teljesítményt és a speciális igények kielégítését. A Kubernetes DNS megértése kulcsfontosságú ahhoz, hogy hatékonyan diagnosztizálhassuk a hálózati problémákat és stabil, nagy teljesítményű alkalmazásokat futtathassunk ebben a komplex környezetben. A megfelelő konfiguráció és a rendszeres ellenőrzés garantálja, hogy a szolgáltatások mindig megtalálják egymást, és az alkalmazások zökkenőmentesen működjenek, hozzájárulva a modern, elosztott architektúrák sikeréhez.

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük