La lliçó anterior va deixar un cap solt deliberat: ExternalName funciona perquè CoreDNS retorna un CNAME, els serveis headless funcionen perquè CoreDNS publica una entrada A per pod, i api-reserves troba postgres-reserves perquè algú resol aquell nom. Portem tres mòduls escrivint postgres-reserves:5432 a la configuració sense haver explicat mai qui tradueix això a una adreça IP. Aquesta lliçó obre la caixa: què és CoreDNS, com es configura, quins noms genera per a cada tipus d'objecte, què hi ha realment al /etc/resolv.conf d'un pod, per què el paràmetre ndots: 5 pot multiplicar per cinc les consultes DNS quan api-reserves truca a la passarel·la de pagaments, i com diagnosticar les tres fallades de DNS que et trobaràs una vegada i una altra.
Contingut
- Per què el descobriment es fa per DNS
- CoreDNS: què és i on viu
- El
Corefile: la configuració del DNS del clúster - L'esquema de noms i les formes curtes
- Registres de Services, Services headless i pods
- Registres SRV i ports amb nom
- El
/etc/resolv.confdel pod i l'efecte d'ndots: 5 dnsPolicyidnsConfig- Les variables d'entorn heretades de Docker
- Diagnòstic: les tres fallades típiques
- Escala: NodeLocal DNSCache i rèpliques de CoreDNS
- Per què el descobriment es fa per DNS
L'alternativa seria configurar adreces IP, i no funciona: les IP dels pods són efímeres (02-05). Un rollout, un desallotjament o un reinici del node la canvien. Podríem fixar la IP del Service, que sí que és estable mentre el Service existeixi, però això tampoc no aguanta:
| Problema de configurar el ClusterIP | Conseqüència |
|---|---|
| S'assigna en crear el Service | El manifest d'api-reserves no es pot escriure fins que existeixi el de postgres-reserves |
| És diferent a cada entorn | El ConfigMap de dev, pre i pro divergeix sense necessitat |
| Es perd en esborrar i recrear el Service | Una reconstrucció del namespace trenca la plataforma |
| No sobreviu a un clúster nou | Recuperació davant de desastres impossible sense editar configuració |
Amb DNS, api-reserves porta escrit postgres-reserves al seu ConfigMap des de 03-01, i aquell nom és vàlid als tres entorns, en un clúster nou i després de recrear el Service: és l'única referència estable que existeix a Kubernetes. A més, el DNS és universal: no requereix biblioteca, ni SDK, ni saber que ets a Kubernetes.
- CoreDNS: què és i on viu
CoreDNS és un servidor DNS escrit en Go, modular a base de plugins, i és el DNS per defecte de Kubernetes des de la versió 1.13 (va substituir kube-dns). S'executa com un Deployment normal al namespace kube-system, exposat per un Service anomenat kube-dns (el nom es va conservar per compatibilitat).
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/coredns 1/1 1 1 21d
NAME TYPE CLUSTER-IP PORT(S) AGE
service/kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 21d
NAME READY STATUS RESTARTS AGE
pod/coredns-668d6bf9bc-hn2fk 1/1 Running 0 3dTres observacions que resolen molts dubtes:
- CoreDNS és una càrrega de treball com qualsevol altra. Pot caure, quedar-se sense recursos, ser desallotjada. Quan CoreDNS pateix, tota la plataforma sembla trencada simultàniament, i aquell símptoma global és el que t'ha de fer mirar aquí.
- La IP
10.96.0.10és la desena adreça delserviceCIDRper convenció, i és la que el kubelet injecta a cada pod. - El port
9153exposa mètriques Prometheus (07-03): taxa de consultes, latència, errors. És de les primeres coses que convé monitorar.
flowchart LR
POD["Pod api-reserves"] -->|"consulta a 10.96.0.10:53"| SVC["Service kube-dns"]
SVC -->|"kube-proxy DNAT"| CD["Pod CoreDNS"]
CD -->|"plugin kubernetes:<br/>watch de Services i EndpointSlices"| API["kube-apiserver"]
CD -->|"plugin forward:<br/>noms externs"| UP["Resolutor del node<br/>(/etc/resolv.conf de l'amfitrio)"]
UP --> INT["Internet:<br/>pagos.proveedorexterno.example"]
Fixa't en la circularitat aparent: els pods arriben a CoreDNS a través d'un ClusterIP, que necessita kube-proxy però no necessita DNS. No hi ha problema de l'ou i la gallina perquè la IP 10.96.0.10 va injectada literalment al resolv.conf.
- El
Corefile: la configuració del DNS del clúster
Corefile: la configuració del DNS del clústerCoreDNS es configura amb un fitxer anomenat Corefile, que viu en un ConfigMap i es munta al pod. El pots llegir tal qual:
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}Llegeix això com una cadena de plugins que s'avaluen en ordre per a tota consulta que arribi al port 53.
| Plugin | Què fa |
|---|---|
errors |
Registra els errors al log |
health / ready |
Punts per a les sondes del Deployment; lameduck espera 5 s abans de morir per no perdre consultes |
kubernetes cluster.local |
El cor. Observa Services i EndpointSlices a l'API i respon els noms del domini cluster.local |
pods insecure |
Habilita els registres de pods per IP (apartat 5) |
ttl 30 |
Vida de les respostes del clúster: 30 segons |
prometheus :9153 |
Exposa mètriques |
forward . /etc/resolv.conf |
Tot el que no sigui cluster.local es reenvia al DNS que faci servir el node. Així es resol pagos.proveedorexterno.example |
cache 30 |
Memòria cau de respostes, 30 s |
loop |
Detecta bucles de reenviament i avorta l'arrencada |
reload |
Recarrega el Corefile sense reiniciar el pod (triga ~2 min a detectar el canvi) |
loadbalance |
Barreja l'ordre dels registres A a cada resposta |
Un cas pràctic de Rutas Norte: l'oficina té un DNS intern a 10.20.30.5 que resol *.interno.rutasnorte.example, on viu la base de dades de facturació heretada. S'afegeix un bloc específic amb kubectl edit configmap coredns -n kube-system:
El plugin reload ho recull sol. Compte: és configuració de tot el clúster; un error de sintaxi deixa CoreDNS en CrashLoopBackOff i amb ell tota la plataforma. Revisa el log després de cada canvi.
- L'esquema de noms i les formes curtes
El nom canònic d'un Service té sempre aquesta estructura:
<servei>.<namespace>.svc.<domini-del-cluster>
postgres-reserves.rutas-norte-pro.svc.cluster.local
| | | |
| | | +-- domini del clúster (configurable)
| | +----------- tipus d'objecte: svc
| +---------------------- namespace
+---------------------------------------- nom del ServiceLes formes curtes funcionen gràcies a la llista search del resolv.conf (apartat 7). Des d'un pod de rutas-norte-pro:
| Escrius | Funciona? | Què resol |
|---|---|---|
postgres-reserves |
Sí | El del mateix namespace |
postgres-reserves.rutas-norte-pro |
Sí | Explícit; serveix entre namespaces |
postgres-reserves.rutas-norte-pro.svc |
Sí | Explícit |
postgres-reserves.rutas-norte-pro.svc.cluster.local |
Sí | Canònic i sense ambigüitat |
postgres-reserves.rutas-norte-dev |
Sí | Un altre namespace: els namespaces no aïllen la xarxa (02-06) |
Aquell últim cas mereix èmfasi. Un pod de rutas-norte-dev pot resoldre i connectar a postgres-reserves.rutas-norte-pro. La separació per namespace és organitzativa, no de seguretat. Només les NetworkPolicies de 04-06 ho impedeixen de debò.
Regla pràctica per a Rutas Norte:
- Dins del mateix entorn, fes servir el nom curt:
postgres-reserves,redis-cache. El mateix ConfigMap serveix per adev,preiprosense canvis. - Per creuar namespaces, fes servir sempre la forma completa amb
.svc.cluster.local. És explícita i, com veurem, més ràpida.
- Registres de Services, Services headless i pods
Service normal: una A amb el ClusterIP
kubectl run t --rm -it --restart=Never -n rutas-norte-pro \
--image=nicolaka/netshoot -- dig +short postgres-reserves.rutas-norte-pro.svc.cluster.localUna sola resposta: la IP virtual. El balanceig entre pods el fa kube-proxy després, com vas veure a 04-01. El DNS no intervé en el repartiment.
Service headless: una A per pod
$ dig +short postgres-reserves-headless.rutas-norte-pro.svc.cluster.local
10.244.0.14
10.244.0.18
10.244.0.23Tres registres A, un per pod llest (ready: true a l'EndpointSlice). Aquí el DNS sí que participa en el descobriment, i qui tria és el client. El plugin loadbalance barreja l'ordre a cada resposta perquè els clients que només miren el primer registre reparteixin alguna cosa.
Un pod que no està llest desapareix d'aquesta llista, tret que el Service tingui publishNotReadyAddresses: true (necessari perquè les rèpliques d'una base de dades es descobreixin entre si durant l'arrencada, cosa que veurem a 06-01).
Registres de pod
Amb pods insecure al Corefile, tot pod té un nom derivat de la seva IP amb els punts substituïts per guions: 10-244-0-14.rutas-norte-pro.pod.cluster.local resol a 10.244.0.14. Fixa't en pod en lloc de svc. És d'ús molt limitat: ningú no escriu això a mà. La seva importància real arriba amb els StatefulSets, on cada pod obté un nom estable i llegible dins d'un Service headless:
postgres-reserves-0.postgres-reserves-headless.rutas-norte-pro.svc.cluster.local
postgres-reserves-1.postgres-reserves-headless.rutas-norte-pro.svc.cluster.localAquesta és la identitat de xarxa que fa possible una base de dades en clúster, i arriba a 06-01.
| Objecte | Format | Retorna |
|---|---|---|
| Service normal | <svc>.<ns>.svc.cluster.local |
1 A: el ClusterIP |
| Service headless | <svc>.<ns>.svc.cluster.local |
N A: una per pod llest |
| Pod en headless | <pod>.<svc>.<ns>.svc.cluster.local |
1 A: la IP del pod |
| Pod per IP | <ip-amb-guions>.<ns>.pod.cluster.local |
1 A: aquella mateixa IP |
ExternalName |
<svc>.<ns>.svc.cluster.local |
CNAME al domini extern |
- Registres SRV i ports amb nom
Els registres SRV publiquen, a més de l'adreça, el port. Es generen per a tot port amb nom d'un Service, amb el format _<port>._<protocol>.<servei>.<ns>.svc.cluster.local.
Recuperant l'api-reserves multiport de 04-02, amb ports http (3000) i metrics (9090):
El format és prioritat pes port desti. Un client que sàpiga llegir SRV descobreix el port sense tenir-lo configurat. En un Service headless, un SRV retorna una línia per pod, amb el port de cadascun:
0 33 5432 10-244-0-14.postgres-reserves-headless.rutas-norte-pro.svc.cluster.local.
0 33 5432 10-244-0-18.postgres-reserves-headless.rutas-norte-pro.svc.cluster.local.
0 33 5432 10-244-0-23.postgres-reserves-headless.rutas-norte-pro.svc.cluster.local.Poques aplicacions consulten SRV; la majoria configura el port explícitament. Però és el mecanisme que fan servir diversos operadors i biblioteques de descobriment, i és la raó concreta per la qual insistim a anomenar sempre els ports.
- El
/etc/resolv.conf del pod i l'efecte d'ndots: 5
/etc/resolv.conf del pod i l'efecte d'ndots: 5El kubelet escriu aquest fitxer dins de cada contenidor:
nameserver 10.96.0.10
search rutas-norte-pro.svc.cluster.local svc.cluster.local cluster.local
options ndots:5Tres línies, tres decisions:
nameserver 10.96.0.10: el ClusterIP dekube-dns. És el que fa que les formes curtes es resolguin.search: els sufixos que el resolutor provarà. El primer és el namespace mateix: per aixòpostgres-reservesa seques funciona dins derutas-norte-pro.options ndots:5: aquí hi ha el parany.
Què significa ndots
ndots:5 diu al resolutor: "si el nom que et demanen té menys de 5 punts, prova'l primer amb cada sufix de search, i només al final tal qual".
Compta els punts de pagos.proveedorexterno.example: dos. Menys de cinc. Així que el resolutor fa això:
1. pagos.proveedorexterno.example.rutas-norte-pro.svc.cluster.local -> NXDOMAIN
2. pagos.proveedorexterno.example.svc.cluster.local -> NXDOMAIN
3. pagos.proveedorexterno.example.cluster.local -> NXDOMAIN
4. pagos.proveedorexterno.example -> 198.51.100.44 OKQuatre consultes, tres d'inútils. I pitjor: cadascuna es fa per a A i per a AAAA, així que a la pràctica són 8 consultes quan n'hi havia prou amb 2. Les tres primeres, a més, viatgen a CoreDNS, que consulta l'API i retorna NXDOMAIN.
Ara trasllada això a Rutas Norte en un pont d'agost: api-reserves truca a la passarel·la de pagaments a cada compra. Amb 2.000 compres per minut i sense memòria cau de resolució a l'aplicació, són 16.000 consultes per minut on n'haurien de ser 4.000. CoreDNS se satura, la latència de resolució puja, i tot el clúster comença a anar a poc a poc per una causa que ningú no relaciona amb el DNS.
La solució: el punt final
Un nom acabat en punt és un FQDN absolut: el resolutor no hi afegeix sufixos.
# ConfigMap d'api-reserves: fixa't en el punt final
PASSARELLA_PAGAMENTS_URL: "https://pagos.proveedorexterno.example./cobraments"Una consulta. Fi.
| Enfocament | Consultes per resolució | Quan fer-lo servir |
|---|---|---|
| Nom extern sense punt final | Fins a 4 (x2 amb AAAA) | Mai, si ho pots evitar |
| Nom extern amb punt final | 1 | Sempre per a dominis externs |
Nom intern curt (redis-cache) |
1 (encerta al primer sufix) | Dins del mateix namespace |
| Nom intern complet amb punt final | 1 | Entre namespaces, i en rutes crítiques |
dnsConfig amb ndots: 2 |
1 per als externs | Quan no pots tocar les URL |
Avís: si baixes ndots a 1, els noms curts com redis-cache (zero punts) continuen funcionant, però postgres-reserves.rutas-norte-pro (un punt) deixaria de resoldre's per cerca i necessitaria l'FQDN. Baixar a 2 és un compromís habitual i segur.
dnsPolicy i dnsConfig
dnsPolicy i dnsConfigdnsPolicy és un camp del spec del pod que decideix quin resolv.conf rep.
| Valor | Què fa | Quan fer-lo servir |
|---|---|---|
ClusterFirst |
Per defecte: apunta a CoreDNS, que reenvia allò extern | Pràcticament sempre |
ClusterFirstWithHostNet |
Igual, però per a pods amb hostNetwork: true |
Pods de xarxa d'amfitrió que necessitin DNS del clúster |
Default |
Hereta el resolv.conf del node. No resol noms del clúster |
Pods d'infraestructura que no parlen amb Services |
None |
Ignora tot i fa servir exclusivament el dnsConfig que escriguis |
Configuracions DNS molt específiques |
El cas de ClusterFirstWithHostNet és un parany clàssic: un pod amb hostNetwork: true i dnsPolicy: ClusterFirst (el valor per defecte) rep el resolv.conf del node i per tant no pot resoldre cap Service. Si poses xarxa d'amfitrió, has de canviar també la política.
dnsConfig permet ajustar el fitxer resultant:
# k8s/base/api-reserves-deployment.yaml (fragment)
spec:
template:
spec:
dnsPolicy: ClusterFirst
dnsConfig:
options:
- name: ndots
value: "2" # redueix les consultes inutils a la passarel-la
- name: single-request-open-tcp
searches:
- interno.rutasnorte.example # sufix addicional per al DNS d'oficinaAmb dnsPolicy: None és obligatori donar almenys un nameserver a dnsConfig, o el pod no arrenca.
- Les variables d'entorn heretades de Docker
Kubernetes injecta a cada contenidor variables d'entorn amb l'adreça i el port de tots els Services que existien al seu namespace en el moment de crear-se el pod. És un vestigi de l'enllaçat de contenidors de Docker.
BOTIGA_WEB_SERVICE_HOST=10.96.88.7
BOTIGA_WEB_SERVICE_PORT=80
POSTGRES_RESERVES_PORT_5432_TCP_ADDR=10.96.140.22
POSTGRES_RESERVES_PORT_5432_TCP_PORT=5432
POSTGRES_RESERVES_SERVICE_HOST=10.96.140.22
POSTGRES_RESERVES_SERVICE_PORT=5432
REDIS_CACHE_SERVICE_HOST=10.96.77.31
REDIS_CACHE_SERVICE_PORT=6379Semblen còmodes i no s'han de fer servir mai. Quatre raons:
- Només existeixen els Services creats ABANS que el pod. Si desplegues
api-reservesi desprésredis-cache, la variable no existeix. I l'ordre de creació no és una cosa que controlis de manera fiable. - Es congelen en arrencar el pod. Si el ClusterIP canvia (Service recreat), la variable continua amb el valor vell i el pod apunta a una IP morta fins que es reiniciï.
- Contaminen l'entorn. Amb 50 Services al namespace són centenars de variables per contenidor. Hi ha casos documentats de fallades en arrencar per excedir la mida de l'entorn.
- Trenquen la portabilitat. Aquell
POSTGRES_RESERVES_SERVICE_HOSTno significa res fora de Kubernetes.
Fes servir sempre el nom DNS, que no depèn de l'ordre, es resol fresc i funciona igual a qualsevol lloc. El soroll de variables s'elimina amb enableServiceLinks: false al spec del pod, recomanable a tots els Deployments de Rutas Norte.
- Diagnòstic: les tres fallades típiques
El pod de treball, com a 04-01:
kubectl run dnsdebug --rm -it --restart=Never -n rutas-norte-pro \
--image=nicolaka/netshoot -- bashComprovacions bàsiques a dins:
cat /etc/resolv.conf # nameserver, search, ndots
nslookup postgres-reserves # forma curta, mateix namespace
dig +search +short postgres-reserves # +search imita el comportament real
dig @10.96.0.10 postgres-reserves.rutas-norte-pro.svc.cluster.localFallada 1: nslookup no resol RES, ni intern ni extern
Causa: CoreDNS és caigut, saturat o no és accessible. És una fallada global, i la seva signatura és que tots els components fallen alhora.
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
kubectl get endpointslices -n kube-system -l kubernetes.io/service-name=kube-dnsSospitosos habituals: pods de CoreDNS en CrashLoopBackOff per un Corefile mal editat; el Service kube-dns sense endpoints; CoreDNS OOMKilled per manca de memòria sota càrrega; o —i això serà molt rellevant a 04-06— una NetworkPolicy d'egress que bloqueja el port 53. Aquest últim cas és tan freqüent que li dedicarem un apartat sencer.
Fallada 2: resol els noms externs però no els del clúster
$ nslookup pagos.proveedorexterno.example
Address: 198.51.100.44 # OK
$ nslookup postgres-reserves
** server can't find postgres-reserves: NXDOMAINCausa: el resolv.conf del pod no és el del clúster. Gairebé sempre és dnsPolicy: Default posat sense voler, o hostNetwork: true sense ClusterFirstWithHostNet. Comprova-ho:
kubectl get pod <pod> -n rutas-norte-pro \
-o jsonpath='{.spec.dnsPolicy}{" hostNetwork="}{.spec.hostNetwork}{"\n"}'Segona causa possible: el nom està malament. Un error tipogràfic, un Service en un altre namespace, o el Service simplement no existeix.
Fallada 3: resol però la connexió falla o va lentíssima
$ nslookup postgres-reserves
Address: 10.96.140.22 # resol bé
$ nc -zv postgres-reserves 5432
... es queda penjatEl DNS no és el problema. Ja has demostrat que la resolució funciona; la fallada és al Service (endpoints buits, 02-05), al CNI o en una política de xarxa. Aquest és el cas més mal interpretat: es culpa el DNS perquè "no connecta pel nom", quan nslookup ja ha respost correctament.
La variant de lentitud sí que pot ser DNS: si la resolució triga segons, mira ndots i els dominis externs sense punt final (apartat 7), o busca saturació a les mètriques de CoreDNS.
| Símptoma | Resolució interna | Resolució externa | Causa probable |
|---|---|---|---|
| No resol res | Falla | Falla | CoreDNS caigut / port 53 bloquejat |
| Només falla allò del clúster | Falla | Funciona | dnsPolicy o hostNetwork malament |
| Resol però no connecta | Funciona | Funciona | No és DNS: Service, CNI o NetworkPolicy |
| Tot va lent | Lent | Molt lent | ndots:5 sense punt final; CoreDNS saturat |
- Escala: NodeLocal DNSCache i rèpliques de CoreDNS
En clústers amb càrrega alta el DNS es converteix en coll d'ampolla. Dues mesures estàndard:
Rèpliques de CoreDNS. Per defecte són 2 (1 a minikube). S'escala amb la mida del clúster, vigilant-ne les mètriques abans que faci mal: kubectl scale deployment coredns -n kube-system --replicas=3. Existeix cluster-proportional-autoscaler, que ajusta les rèpliques segons el nombre de nodes i nuclis, i és el que fan servir les distribucions gestionades.
NodeLocal DNSCache. Un DaemonSet que posa una memòria cau DNS a cada node. Els pods consulten aquella memòria cau local (per una IP d'enllaç, típicament 169.254.20.10) en lloc de creuar la xarxa fins a CoreDNS.
| Benefici | Detall |
|---|---|
| Menys latència | La consulta no surt del node si és a la memòria cau |
| Menys càrrega a CoreDNS | Només hi arriben les fallades de memòria cau |
Menys problemes de conntrack |
Fa servir TCP cap a CoreDNS, evitant la coneguda fallada de curses amb UDP |
| Aïlla incidents | Un CoreDNS que es reinicia no interromp les resolucions a la memòria cau |
Per a Rutas Norte, amb els seus pics de ponts, és la mesura que es plantejaria juntament amb l'autoescalat de 09-01.
Errors Comuns i Consells
- Culpar el DNS quan
nslookuprespon bé. Si resol, el DNS ha fet la seva feina. Continua pel Service i els seus endpoints. - Editar el
Corefilesense revisar el log. Un error de sintaxi tomba CoreDNS i amb ell tot el clúster. Després de cadakubectl edit configmap coredns, mirakubectl logs -n kube-system -l k8s-app=kube-dns. - Dominis externs sense punt final. Multipliquen per quatre (o vuit) les consultes. A Rutas Norte, l'URL de la passarel·la de pagaments ha de portar el punt.
- Fer servir
hostNetwork: truesensednsPolicy: ClusterFirstWithHostNet. El pod perd la capacitat de resoldre Services i l'error és desconcertant. - Fer servir les variables
*_SERVICE_HOST. Depenen de l'ordre de creació i es congelen. Fes servir noms DNS i desactiva-les ambenableServiceLinks: false. - Guardar resolucions per sempre a la memòria cau de l'aplicació. Alguns entorns (la JVM amb la configuració per defecte històrica) les guarden sense caducitat i continuen fent servir una IP morta. Ajusta el TTL del resolutor del teu llenguatge.
- Suposar que el namespace aïlla. Un pod de
devresol i connecta apostgres-reserves.rutas-norte-pro. Això només ho talla 04-06. - Consell: davant de qualsevol dubte, executa
dig +searchi nodiga seques. Sense+searchno s'apliquen els sufixos i estaràs provant una cosa diferent del que fa la teva aplicació. - Consell: vigila
coredns_dns_request_duration_secondsi la taxa d'NXDOMAIN. Un pic d'NXDOMAINsol significar que algú ha desplegat una aplicació amb noms externs sense punt final.
Exercicis
Exercici 1: Cartografiar els noms de la plataforma
Des d'un pod efímer a rutas-norte-pro, resol postgres-reserves en les seves quatre formes (curta, amb namespace, amb .svc, completa) i comprova que totes donen la mateixa IP. Després resol postgres-reserves.rutas-norte-dev i explica què demostra el resultat.
Exercici 2: Mesurar el cost d'ndots: 5
Des d'un pod efímer, compta quantes consultes provoca resoldre pagos.proveedorexterno.example sense punt final i amb punt final. Calcula l'estalvi per a 2.000 compres per minut i proposa dues maneres d'arreglar-ho al manifest d'api-reserves.
Exercici 3: Diagnosticar tres pods amb DNS trencat
Es despleguen tres pods de prova: A amb hostNetwork: true i dnsPolicy per defecte; B normal però consultant un Service inexistent; C normal, amb el Service correcte però el Deployment del qual està escalat a zero. Prediu el símptoma de cadascun i verifica'l.
Solucions
Exercici 1
kubectl run t --rm -it --restart=Never -n rutas-norte-pro \
--image=nicolaka/netshoot -- sh -c '
for n in postgres-reserves \
postgres-reserves.rutas-norte-pro \
postgres-reserves.rutas-norte-pro.svc \
postgres-reserves.rutas-norte-pro.svc.cluster.local \
postgres-reserves.rutas-norte-dev; do
printf "%-56s %s\n" "$n" "$(dig +search +short $n | head -1)"
done'postgres-reserves 10.96.140.22
postgres-reserves.rutas-norte-pro 10.96.140.22
postgres-reserves.rutas-norte-pro.svc 10.96.140.22
postgres-reserves.rutas-norte-pro.svc.cluster.local 10.96.140.22
postgres-reserves.rutas-norte-dev 10.96.19.88Les quatre primeres són la mateixa IP: les formes curtes es completen amb la llista search. La cinquena demostra que des de producció es resol el Service de desenvolupament, amb una IP diferent: els namespaces no aïllen la xarxa. I si a més proves nc -zv postgres-reserves.rutas-norte-dev 5432, connectarà.
Exercici 2
kubectl run t --rm -it --restart=Never -n rutas-norte-pro --image=nicolaka/netshoot -- sh -c '
dig +search pagos.proveedorexterno.example | grep -c "^;.*IN.*A" # sense punt
dig pagos.proveedorexterno.example. | grep -c "^;.*IN.*A"' # amb puntSense punt: 4 intents (3 NXDOMAIN + 1 encert), per 2 en comptar AAAA = 8 consultes. Amb punt: 2. Estalvi del 75 %.
A 2.000 compres per minut: 16.000 consultes/min davant de 4.000. Dotze mil consultes inútils cada minut contra CoreDNS.
Dos arreglaments al manifest:
# Opcio A (preferida): punt final a l'URL del ConfigMap
PASSARELLA_PAGAMENTS_URL: "https://pagos.proveedorexterno.example./cobraments"
# Opcio B: baixar ndots per a tot el pod
spec:
dnsConfig:
options:
- name: ndots
value: "2"L'A és quirúrgica i no afecta res més; la B serveix quan no pots tocar les URL, però recorda que trenca les formes curtes amb un punt.
Exercici 3
| Pod | Símptoma | Causa |
|---|---|---|
A (hostNetwork) |
Resol pagos.proveedorexterno.example però dona NXDOMAIN a postgres-reserves |
Fa servir el resolv.conf del node; necessita dnsPolicy: ClusterFirstWithHostNet |
| B (Service inexistent) | NXDOMAIN només en aquell nom; la resta resol |
El nom no existeix: error tipogràfic o namespace equivocat |
| C (Deployment a zero) | Resol correctament al ClusterIP, però la connexió esgota el temps d'espera | El DNS funciona; el Service no té endpoints. No és un problema de DNS |
# Verificacio del C: la clau es als endpoints, no al DNS
kubectl get endpointslices -n rutas-norte-pro \
-l kubernetes.io/service-name=api-reserves
# ENDPOINTS: <none>El cas C és la lliçó més valuosa de les tres: resoldre no és connectar.
Conclusió
Ara saps qui tradueix postgres-reserves a una adreça IP. CoreDNS és un Deployment normal de kube-system, exposat pel Service kube-dns a 10.96.0.10, configurat per un Corefile el plugin kubernetes del qual observa Services i EndpointSlices per respondre el domini cluster.local, i el plugin forward del qual envia tota la resta al resolutor del node. Que sigui una càrrega de treball corrent té una conseqüència operativa: pot caure, saturar-se o quedar-se sense memòria, i quan això passa tota la plataforma sembla trencada alhora.
Domines l'esquema de noms <servei>.<namespace>.svc.cluster.local i saps que les formes curtes funcionen gràcies a la llista search del resolv.conf, no per màgia. Coneixes els registres que genera cada objecte: una A amb el ClusterIP per a un Service normal, una A per pod llest per a un de headless, noms de pod derivats de la IP, i registres SRV que publiquen el port dels ports amb nom. I entens el que la resolució no fa: no reparteix càrrega en un Service normal (això és kube-proxy) i no garanteix connectivitat.
L'apartat que més t'estalviarà és ndots: 5. Un domini extern amb menys de cinc punts provoca quatre intents de resolució, vuit consultes comptant AAAA, i als pics de ponts de Rutas Norte això són milers de consultes inútils per minut contra CoreDNS. El punt final a pagos.proveedorexterno.example. ho redueix a una. Saps ajustar dnsPolicy i dnsConfig, has vist per què hostNetwork: true sense ClusterFirstWithHostNet deixa el pod sense accés al DNS del clúster, i per què les variables *_SERVICE_HOST heretades de Docker no s'han de fer servir mai —depenen de l'ordre de creació i es congelen— fins al punt de desactivar-les amb enableServiceLinks: false. Tens també les tres fallades típiques amb la seva signatura inconfusible, i a l'horitzó NodeLocal DNSCache i l'escalat de CoreDNS per quan la càrrega estrenyi.
Amb la xarxa entesa (04-01), els tipus de Service dominats (04-02) i el descobriment resolt, ja no queda cap excusa: és hora d'obrir la plataforma al món. A 04-04 desplegarem un controlador d'Ingress i publicarem per fi www.rutasnorte.example contra botiga-web i api.rutasnorte.example contra api-reserves, amb un únic punt d'entrada, encaminat per domini i per ruta. Els clients de Rutas Norte podran, per primera vegada al curs, comprar un bitllet.
Curs de Kubernetes
Mòdul 1: Introducció a Kubernetes
- Què és Kubernetes?
- Arquitectura de Kubernetes
- Conceptes i Terminologia Clau
- Configuració d'un Clúster de Kubernetes
- La CLI de Kubernetes: kubectl
- Objectes, Manifests YAML i el Model Declaratiu
- El Projecte del Curs: la Plataforma Rutas Norte
Mòdul 2: Components Principals de Kubernetes
- Pods
- ReplicaSets
- Deployments
- Actualitzacions, Rollbacks i Estratègies de Desplegament
- Serveis
- Namespaces
- Etiquetes, Selectors i Anotacions
Mòdul 3: Gestió de Configuració i Secrets
- ConfigMaps
- Secrets
- Variables d'Entorn
- Quotes i Límits de Recursos
- LimitRanges i Classes de Qualitat de Servei (QoS)
- ServiceAccounts i Accés a l'API des dels Pods
Mòdul 4: Xarxes a Kubernetes
- Xarxes de Clúster
- Tipus de Serveis
- DNS Intern i Descobriment de Serveis
- Controladors d'Ingress
- TLS i Gestió de Certificats amb cert-manager
- Polítiques de Xarxa
Mòdul 5: Emmagatzematge a Kubernetes
- Volums
- Volums Persistents
- Reclamacions de Volums Persistents
- Classes d'Emmagatzematge
- Aprovisionament Dinàmic, Expansió i Snapshots
- Còpies de Seguretat i Restauració de Dades
Mòdul 6: Conceptes Avançats de Kubernetes
- StatefulSets
- DaemonSets
- Treballs i CronJobs
- Init Containers, Sidecars i Patrons Multicontenidor
- Planificació: Afinitat, Taints i Toleracions
- Definicions de Recursos Personalitzats (CRDs)
- Operadors i el Patró Controlador
Mòdul 7: Monitoratge i Registre
- Verificacions de Salut i Sondes
- Servidor de Mètriques i kubectl top
- Monitoratge amb Prometheus
- Visualització i Alertes amb Grafana i Alertmanager
- Registre Centralitzat amb Elasticsearch, Fluentd i Kibana (EFK)
- Depuració d'Aplicacions i Esdeveniments del Clúster
Mòdul 8: Seguretat a Kubernetes
- Control d'Accés Basat en Rols (RBAC)
- Contextos de Seguretat i Enduriment del Contenidor
- Polítiques de Seguretat de Pods i Pod Security Standards
- Seguretat de Xarxa
- Seguretat d'Imatges
- Auditoria, Escaneig i Gestió de Vulnerabilitats
Mòdul 9: Escalat i Rendiment
- Autoescalat Horitzontal de Pods
- Autoescalat Vertical de Pods
- Autoescalat de Clúster
- Escalat per Esdeveniments i Mètriques Personalitzades amb KEDA
- Alta Disponibilitat: PodDisruptionBudgets i Topologia
- Ajust de Rendiment
Mòdul 10: Ecosistema i Eines de Kubernetes
- Minikube i Entorns Locals amb kind
- Kubeadm
- Helm
- Kustomize
- GitOps amb Argo CD i Flux
- Kubernetes Gestionat: EKS, AKS i GKE
Mòdul 11: Estudis de Cas i Aplicacions del Món Real
- Desplegament d'una Aplicació Web
- Execució d'Aplicacions amb Estat
- CI/CD amb Kubernetes
- Estratègies de Desplegament: Blue-Green i Canary
- Gestió Multi-Clúster
- Operació en Producció: Incidències, Runbooks i Costos
