4. Services y DNS
Secciones
Ajustes de lectura
Ninguna voz para este idioma en este navegador.
Más voces
Código y términos técnicos en inglés
Desactivado: la voz de la página lo lee todo, sin pausa entre dos voces.
Ninguna voz para este idioma en este navegador.
Más voces
Más voces: Microsoft Edge ofrece voces naturales en línea, y Windows (Configuración › Hora e idioma › Voz), macOS y Android instalan otras.
Código completo: code/kubernetes/l04, con sus comandos en l04/run.sh. Como en las lecciones 2 y 3, los comandos se muestran tal como se ejecutan en Bash.
Cada pod tiene su propia dirección IP, y cada pod es temporal. En la lección 3, cada actualización sustituyó los tres pods de C# por otros nuevos, con nombres nuevos y direcciones nuevas. Un cliente no puede llevar una lista de ellos. Un Service es la parte estable: un nombre, una dirección IP virtual que no cambia durante la vida del Service, y un selector de etiquetas que decide, en cada momento, qué pods reciben el tráfico.
Preparación
Sección titulada «Preparación»La lección reutiliza los dos Deployments de la lección 3, y añade un pod para enviar peticiones desde dentro del clúster:
# Lección 4: un pod para enviar peticiones desde dentro del clúster. La imagen de curl ejecutaría curl y terminaría: sleep en su lugar.apiVersion: v1kind: Podmetadata: name: clientspec: terminationGracePeriodSeconds: 0 containers: - name: curl image: curlimages/curl:8.22.0 command: ["sleep", "infinity"]> kubectl create namespace l04namespace/l04 created> kubectl apply -n l04 -f l03/csharp-api.yaml -f l03/java-reactor-api.yaml -f l04/client.yamldeployment.apps/csharp-api createddeployment.apps/java-reactor-api createdpod/client createdClusterIP
Sección titulada «ClusterIP»l04/services.yaml pone un Service delante de cada Deployment:
# Lección 4: un nombre estable y una IP virtual delante de cada Deployment de la lección 3.apiVersion: v1kind: Servicemetadata: name: csharp-apispec: # ClusterIP es el tipo por defecto: accesible solo desde dentro del clúster type: ClusterIP selector: app: csharp-api ports: - name: http port: 80 targetPort: http---apiVersion: v1kind: Servicemetadata: name: java-reactor-apispec: selector: app: java-reactor-api ports: - name: http port: 80 targetPort: httpport es al que llaman los clientes; targetPort: http es el puerto de los pods llamado http en la lección 3, el 8080. Dar nombre al puerto en la plantilla del pod permite a la aplicación cambiar de puerto sin tocar el Service.
> kubectl apply -n l04 -f l04/services.yamlservice/csharp-api createdservice/java-reactor-api created> kubectl get -n l04 servicesNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEcsharp-api ClusterIP 10.96.34.184 <none> 80/TCP 0sjava-reactor-api ClusterIP 10.96.210.58 <none> 80/TCP 0s> kubectl exec -n l04 client -- curl -s http://csharp-api/{"app":"csharp-api","runtime":"<runtime>","os":"<os>","machine":"csharp-api-55b7fbb748-dn79k"}> kubectl exec -n l04 client -- curl -s http://java-reactor-api/{"app":"java-reactor-api","runtime":"<runtime>","os":"<os>","machine":"java-reactor-api-64bd9f4b94-xkbjc"}kubectl exec ejecuta curl dentro del pod client, como lo haría docker exec. El campo machine es el nombre de host del pod, que es su nombre: el Service eligió uno de los pods.
El script sustituye el runtime y el sistema operativo, que dependen de la construcción de la imagen, por marcadores. En la máquina del autor, la API de C# indicó ".NET 10.0.12" y "Ubuntu 24.04.5 LTS", la distribución de su imagen base, y la API de Java "Java 25.0.4+7-LTS" y "Linux 6.18.40.1-microsoft-standard-WSL2": os.name y os.version de Java describen el kernel, que es el kernel WSL 2 de Docker Desktop, compartido por todos los contenedores.
Una ClusterIP solo es accesible desde dentro del clúster. Ningún proceso escucha en ella: en cada nodo, kube-proxy programa el kernel para reescribir los paquetes enviados a la dirección y al puerto del Service hacia uno de los pods. En kind, kube-proxy usa iptables; su log dice "Using iptables Proxier". Un Service nuevo tarda un momento en programarse, y por eso el script espera a que el primer curl responda.
El nombre csharp-api lo resolvió el DNS del clúster, CoreDNS, que crea un registro para cada Service. Su nombre completo incluye el namespace:
> kubectl exec -n l04 client -- curl -s http://csharp-api.l04.svc.cluster.local/{"app":"csharp-api","runtime":"<runtime>","os":"<os>","machine":"csharp-api-55b7fbb748-9rj4s"}> kubectl exec -n l04 client -- cat /etc/resolv.confsearch l04.svc.cluster.local svc.cluster.local cluster.localnameserver 10.96.0.10options ndots:5> kubectl exec -n l04 client -- nslookup csharp-api.l04.svc.cluster.local.Server: 10.96.0.10Address: 10.96.0.10:53
Name: csharp-api.l04.svc.cluster.localAddress: 10.96.34.184El kubelet escribe el /etc/resolv.conf de cada pod:
nameserver 10.96.0.10es la ClusterIP del Servicekube-dnsenkube-system, delante de los pods de CoreDNS de la lección 1.searchhace que funcione un nombre corto:csharp-apise prueba primero comocsharp-api.l04.svc.cluster.local. Desde otro namespace, basta concsharp-api.l04.ndots:5significa que un nombre con menos de cinco puntos pasa por la lista de búsqueda antes de probarse tal cual.api.github.comtiene dos, así que un pod pregunta primero porapi.github.com.l04.svc.cluster.localy por otros dos nombres que no existen. Un punto final, como en elnslookupde arriba, marca un nombre como completo y se salta la lista.
La página DNS for Services and Pods enumera los registros; Debugging DNS resolution es la página que hay que abrir cuando los nombres no se resuelven.
EndpointSlices: ¿qué pods, y están listos?
Sección titulada «EndpointSlices: ¿qué pods, y están listos?»El selector del Service lo evalúa el controlador de EndpointSlice, que escribe las direcciones de los pods que coinciden en EndpointSlices. kube-proxy lee estos, no los pods.
> kubectl get -n l04 endpointslicesNAME ADDRESSTYPE PORTS ENDPOINTS AGEcsharp-api-<slice> IPv4 8080 10.244.0.241,10.244.0.239,10.244.0.240 3sjava-reactor-api-<slice> IPv4 8080 10.244.0.243,10.244.0.244 3s> kubectl get -n l04 endpoints csharp-apiWarning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSliceNAME ENDPOINTS AGEcsharp-api 10.244.0.239:8080,10.244.0.240:8080,10.244.0.241:8080 3sEl nombre de cada slice termina con cinco caracteres aleatorios, sustituidos aquí por <slice>. El objeto Endpoints, más antiguo, sigue existiendo, y kubectl avisa: guardaba todas las direcciones de un Service en un solo objeto, lo que no escalaba a miles de pods, y está obsoleto desde la 1.33. Los tutoriales que todavía usan kubectl get endpoints funcionan, por ahora.
La readiness, de la lección 2, importa aquí. l04/unready.yaml añade un cuarto pod con la etiqueta app: csharp-api y una sonda de readiness que siempre falla:
> kubectl apply -n l04 -f l04/unready.yamlpod/csharp-api-unready created> kubectl get -n l04 endpointslices -l kubernetes.io/service-name=csharp-api -o jsonpath='{range .items[*].endpoints[*]}{.targetRef.name} ready={.conditions.ready}{"\n"}{end}' | sortcsharp-api-55b7fbb748-9rj4s ready=truecsharp-api-55b7fbb748-dn79k ready=truecsharp-api-55b7fbb748-zw7ph ready=truecsharp-api-unready ready=falseEl selector coincide con él, así que el slice lo incluye, marcado ready=false. Treinta peticiones muestran que kube-proxy lo omite:
> kubectl exec -n l04 client -- sh -c 'for i in $(seq 30); do curl -s http://csharp-api/; echo; done' | …3 pods answered 30 requests; csharp-api-unready answered 0(La parte tras | cuenta los valores de machine; el comando completo está en run.sh.) También es una trampa: un Service selecciona cualquier pod con sus etiquetas, incluido uno de otro Deployment, o uno arrancado a mano para depurar. Esta vez, la readiness protegió a los clientes.
NodePort
Sección titulada «NodePort»Un Service NodePort abre además un puerto, entre 30000 y 32767, en cada nodo. l04/nodeport.yaml pide el 30080, que kind/cluster.yaml asocia a 127.0.0.1:30080 en tu máquina con extraPortMappings:
spec: type: NodePort selector: app: csharp-api ports: - name: http port: 80 targetPort: http nodePort: 30080> kubectl apply -n l04 -f l04/nodeport.yamlservice/csharp-api-nodeport created> kubectl get -n l04 service csharp-api-nodeportNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEcsharp-api-nodeport NodePort 10.96.80.124 <none> 80:30080/TCP 1s> curl -s http://localhost:30080/{"app":"csharp-api","runtime":"<runtime>","os":"<os>","machine":"csharp-api-55b7fbb748-dn79k"}El último curl se ejecuta en tu máquina, no en el clúster: en Windows, curl.exe en PowerShell. Un Service NodePort es también un Service ClusterIP. Es la forma más sencilla de entrar, pero los clientes tienen que conocer las direcciones de los nodos y un puerto poco habitual; el mapeo de puertos de kind debe declararse al crear el clúster.
LoadBalancer
Sección titulada «LoadBalancer»Un Service LoadBalancer pide a la infraestructura un balanceador de carga externo: en AKS, EKS o GKE, el controlador del proveedor de nube crea uno y escribe su dirección en el Service. kind no tiene nube, así que el curso ejecuta cloud-provider-kind v0.11.1, que cumple ese papel con un contenedor Envoy por balanceador. check.sh lo arranca como contenedor en la red Docker de kind, con acceso al socket de Docker para crear esos contenedores:
docker run -d --name learn-k8s-cloud-provider --network kind -v /var/run/docker.sock:/var/run/docker.sock \ registry.k8s.io/cloud-provider-kind/cloud-controller-manager:v0.11.1@sha256:40e18b9cd9c798cce40d39ff5c099a4f16a36c268d8e1dda469d73955a35e403En Git Bash, fija primero MSYS_NO_PATHCONV=1, como hace check.sh, o Git Bash reescribe /var/run/docker.sock como una ruta de Windows; /var/run/docker.sock es la ruta del socket dentro de la VM de Docker Desktop, no en Windows. Acceder al socket de Docker significa controlar Docker: ejecuta solo una imagen de confianza, fijada por digest como aquí.
# Lección 4: un Service LoadBalancer. En una nube, el proveedor crea un balanceador de carga; en kind, lo hace cloud-provider-kind.apiVersion: v1kind: Servicemetadata: name: java-reactor-api-lbspec: type: LoadBalancer selector: app: java-reactor-api ports: - name: http port: 80 targetPort: http> kubectl apply -n l04 -f l04/loadbalancer.yamlservice/java-reactor-api-lb created> kubectl get -n l04 service java-reactor-api-lbNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEjava-reactor-api-lb LoadBalancer 10.96.155.58 172.23.0.4 80:<node-port>/TCP 1s> kubectl exec -n l04 client -- curl -s http://172.23.0.4/{"app":"java-reactor-api","runtime":"<runtime>","os":"<os>","machine":"java-reactor-api-64bd9f4b94-g8wnk"}> docker ps --filter name=kindccm --format '{{.Names}} {{.Ports}}'kindccm-86739d9686d6 0.0.0.0:80->80/tcp, 0.0.0.0:52142->10000/tcp, [::]:52142->10000/tcpEXTERNAL-IP es la dirección del contenedor Envoy en la red kind. Un Service LoadBalancer es también un Service NodePort, en un puerto elegido al azar, y por tanto un Service ClusterIP: cada tipo añade una forma de entrar.
En Linux, esa dirección es accesible desde el host. En Windows y macOS, Docker se ejecuta en una VM y no lo es: desde Windows, curl a 172.23.0.4 agotó el tiempo de espera. El README de cloud-provider-kind describe la solución que aplica ahí, publicar el puerto del balanceador en el host. En la máquina del autor, el primer balanceador obtuvo el propio puerto 80, como muestra docker ps, y curl http://localhost/ desde Windows respondió; el Gateway de más abajo obtuvo en cambio un puerto de host aleatorio. Antes de contar con cualquiera de los dos, comprueba docker ps, y ten en cuenta que el puerto 80 de tu máquina puede estar ya ocupado.
Un único punto de entrada: la Gateway API
Sección titulada «Un único punto de entrada: la Gateway API»Con dos API, dos balanceadores de carga significan dos direcciones y, en una nube, dos facturas. Un enrutador HTTP puede enviar ambos nombres de host al Service adecuado desde una sola dirección. Kubernetes tiene dos API para eso. La más reciente, la Gateway API, reparte el trabajo en tres objetos:
| Objeto | Quién lo escribe | Qué dice |
|---|---|---|
| GatewayClass | la plataforma, con su controlador | qué implementación, como una StorageClass |
| Gateway | el operador del clúster | un punto de entrada: direcciones, puertos, protocolos, certificados TLS |
| HTTPRoute | el equipo de la aplicación | qué peticiones van a qué Service |
La Gateway API no viene integrada en Kubernetes: sus objetos son recursos personalizados (lección 13) que se instalan desde sus versiones publicadas. cloud-provider-kind instaló la versión 1.5.0 del canal estándar, y creó una GatewayClass y una IngressClass:
> kubectl get gatewayclass,ingressclassNAME CONTROLLER ACCEPTED AGEgatewayclass.gateway.networking.k8s.io/cloud-provider-kind kind.sigs.k8s.io/gateway-controller True 32m
NAME CONTROLLER PARAMETERS AGEingressclass.networking.k8s.io/cloud-provider-kind (default) kind.sigs.k8s.io/ingress-controller <none> 32ml04/gateway.yaml declara un Gateway y una ruta con una regla por host:
# Lección 4: un único punto de entrada para las dos API con la Gateway API, enrutado por nombre de host.apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: webspec: # La clase que proporciona cloud-provider-kind; una nube o un controlador de gateway proporciona la suya gatewayClassName: cloud-provider-kind listeners: - name: http protocol: HTTP port: 80---apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: apisspec: parentRefs: - name: web rules: - matches: - headers: - name: Host value: csharp.example.test backendRefs: - name: csharp-api port: 80 - matches: - headers: - name: Host value: java.example.test backendRefs: - name: java-reactor-api port: 80> kubectl apply -n l04 -f l04/gateway.yamlgateway.gateway.networking.k8s.io/web createdhttproute.gateway.networking.k8s.io/apis created> kubectl wait -n l04 --for=condition=Programmed gateway/web --timeout=120sgateway.gateway.networking.k8s.io/web condition met> kubectl get -n l04 gateway webNAME CLASS ADDRESS PROGRAMMED AGEweb cloud-provider-kind 172.23.0.5 True 1s> kubectl get -n l04 httproute apis -o jsonpath='{range .status.parents[*].conditions[*]}{.type}={.status} {.reason}{"\n"}{end}'Accepted=True AcceptedResolvedRefs=True ResolvedRefsLos estados son lo primero que hay que leer cuando una ruta no funciona: Programmed dice que el controlador del Gateway ha configurado el proxy, Accepted que el Gateway aceptó la ruta, y ResolvedRefs que existen los Services que nombra. Después, una sola dirección sirve a las dos API:
> kubectl exec -n l04 client -- curl -s -H "Host: csharp.example.test" http://172.23.0.5/{"app":"csharp-api","runtime":"<runtime>","os":"<os>","machine":"csharp-api-55b7fbb748-zw7ph"}> kubectl exec -n l04 client -- curl -s -H "Host: java.example.test" http://172.23.0.5/{"app":"java-reactor-api","runtime":"<runtime>","os":"<os>","machine":"java-reactor-api-64bd9f4b94-g8wnk"}> kubectl exec -n l04 client -- curl -s -o /dev/null -w '%{http_code} %header{server}\n' -H 'Host: other.example.test' http://172.23.0.5/404 envoy-H "Host: …" sustituye a los registros DNS que apuntarían ambos nombres al Gateway. Un host con el que no coincide ninguna regla recibe un 404 del propio Envoy, sin llegar a ningún pod.
Ingress
Sección titulada «Ingress»Ingress es la API más antigua para el mismo trabajo, un objeto con reglas de host y de ruta. Es estable y sigue teniendo soporte, pero está congelada: las funcionalidades nuevas van a la Gateway API. Su controlador más común, ingress-nginx, se retiró en marzo de 2026, y aún te lo encontrarás en clústeres existentes. l04/ingress.yaml:
# Lección 4: la API más antigua para el mismo trabajo que el Gateway. Sin ingressClassName, se aplica la IngressClass por defecto:# en kind, la que crea cloud-provider-kind.apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: apisspec: rules: - host: csharp.example.test http: paths: - path: / pathType: Prefix backend: service: name: csharp-api port: name: http - host: java.example.test http: paths: - path: / pathType: Prefix backend: service: name: java-reactor-api port: name: http> kubectl apply -n l04 -f l04/ingress.yamlingress.networking.k8s.io/apis created> kubectl get -n l04 ingress apis -o custom-columns=NAME:.metadata.name,CLASS:.spec.ingressClassName,HOSTS:.spec.rules[*].host,ADDRESS:.status.loadBalancer.ingress[0].ipNAME CLASS HOSTS ADDRESSapis cloud-provider-kind csharp.example.test,java.example.test 172.23.0.6> kubectl get -n l04 gateways,httproutesNAME CLASS ADDRESS PROGRAMMED AGEgateway.gateway.networking.k8s.io/kind-ingress-gateway cloud-provider-kind 172.23.0.6 True 2sgateway.gateway.networking.k8s.io/web cloud-provider-kind 172.23.0.5 True 4s
NAME HOSTNAMES AGEhttproute.gateway.networking.k8s.io/apis 4shttproute.gateway.networking.k8s.io/apis-57edfef398 ["java.example.test"] 2shttproute.gateway.networking.k8s.io/apis-f45dc871d2 ["csharp.example.test"] 2s> kubectl exec -n l04 client -- curl -s -H 'Host: java.example.test' http://172.23.0.6/{"app":"java-reactor-api","runtime":"<runtime>","os":"<os>","machine":"java-reactor-api-64bd9f4b94-xkbjc"}La clase la rellenó la IngressClass por defecto. cloud-provider-kind no implementa Ingress por separado: traduce el Ingress a un Gateway propio, kind-ingress-gateway, y a una HTTPRoute por host. Esas rutas usan el campo hostnames de la ruta, la forma habitual de enrutar por host, mientras que apis comprobaba la cabecera Host en sus reglas. La traducción resume bien la relación entre las dos API, y la herramienta ingress2gateway hace lo mismo para las migraciones.
¿Cuál usar?
Sección titulada «¿Cuál usar?»| Necesidad | Usa |
|---|---|
| Pods que se llaman entre sí dentro del clúster | ClusterIP, por nombre DNS |
| Un vistazo rápido desde tu máquina | kubectl port-forward, o un NodePort en un clúster local |
| Un servicio TCP o UDP expuesto fuera | LoadBalancer |
| Enrutamiento HTTP por host o por ruta, TLS, varios servicios tras una dirección | Gateway API (Ingress en clústeres existentes) |
> kubectl delete namespace l04 --wait=truenamespace "l04" deletedPuntos clave
Sección titulada «Puntos clave»- Un Service da a los pods un nombre y una IP virtual estables, y los elige por etiqueta en cada momento; su
targetPortpuede nombrar el puerto de los pods. - CoreDNS resuelve
name,name.namespaceyname.namespace.svc.cluster.local;ndots:5hace que los nombres externos pasen primero por la lista de búsqueda. - Los EndpointSlices listan los pods detrás de un Service con su readiness, y kube-proxy solo envía tráfico a los que están listos; la API Endpoints está obsoleta.
- NodePort añade un puerto en cada nodo, y LoadBalancer añade una dirección externa de la infraestructura; en kind la proporciona cloud-provider-kind, y en Windows y macOS se llega a la dirección por un puerto publicado en el host.
- La Gateway API reparte el enrutamiento en GatewayClass, Gateway y HTTPRoute, e informa de cada paso en sus estados; Ingress hace el mismo trabajo en una sola API congelada.
Ejercicios
Sección titulada «Ejercicios»1. Un Service con clusterIP: None es headless. Crea uno para la API de C# (l04/headless.yaml) mientras csharp-api-unready está en marcha, y resuelve su nombre. ¿Qué obtienes, y qué falta?
Solución
> kubectl apply -n l04 -f l04/headless.yamlservice/csharp-api-headless created> kubectl get -n l04 service csharp-api-headlessNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEcsharp-api-headless ClusterIP None <none> 80/TCP 1s> kubectl exec -n l04 client -- nslookup -type=a csharp-api-headless.l04.svc.cluster.local.Server: 10.96.0.10Address: 10.96.0.10:53
Name: csharp-api-headless.l04.svc.cluster.localAddress: 10.244.0.241Name: csharp-api-headless.l04.svc.cluster.localAddress: 10.244.0.239Name: csharp-api-headless.l04.svc.cluster.localAddress: 10.244.0.240
> kubectl get -n l04 pods -l app=csharp-api -o custom-columns='NAME:.metadata.name,IP:.status.podIP,READY:.status.conditions[?(@.type=="Ready")].status' --sort-by=.metadata.nameNAME IP READYcsharp-api-55b7fbb748-9rj4s 10.244.0.239 Truecsharp-api-55b7fbb748-dn79k 10.244.0.241 Truecsharp-api-55b7fbb748-zw7ph 10.244.0.240 Truecsharp-api-unready 10.244.0.245 FalseNo hay IP virtual: el nombre se resuelve a las direcciones de los propios pods listos, y el cliente elige una. Falta la 10.244.0.245 del pod no listo. Los Services headless sirven a los clientes que quieren ver cada instancia, como un driver de base de datos o un cliente gRPC que balancea por su cuenta, y dan a cada pod de un StatefulSet un nombre DNS estable (lección 6).
2. l04/wrong-selector.yaml tiene una errata en su selector: app: csharp_api. ¿Cómo falla, y cómo encontrarías la causa?
Solución
> kubectl apply -n l04 -f l04/wrong-selector.yamlservice/csharp-api-typo created> kubectl exec -n l04 client -- curl -sS -m 5 http://csharp-api-typo/curl: (7) Failed to connect to csharp-api-typo:80 after 0 ms: Could not connect to servercommand terminated with exit code 7> kubectl get -n l04 endpointslices -l kubernetes.io/service-name=csharp-api-typoNAME ADDRESSTYPE PORTS ENDPOINTS AGEcsharp-api-typo-<slice> IPv4 <unset> <unset> 1sEl Service se crea sin quejarse, su nombre se resuelve, y la conexión se rechaza de inmediato: kube-proxy rechaza el tráfico hacia un Service sin endpoints. Un EndpointSlice sin endpoints es la señal. Compara el selector con las etiquetas de los pods, kubectl get pods --show-labels. El mismo síntoma aparece cuando ninguno de los pods que coinciden está listo.
3. Todo clúster tiene un Service llamado kubernetes en el namespace default. ¿Qué hay detrás? Llámalo desde el pod client, en l04.
Solución
> kubectl get -n default service kubernetesNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9h> kubectl exec -n l04 client -- curl -sk https://kubernetes.default/version{ "major": "1", "minor": "37", "emulationMajor": "1", "emulationMinor": "37", "minCompatibilityMajor": "1", "minCompatibilityMinor": "36", "gitVersion": "v1.37.0", "gitCommit": "f54c212e3a2f75d674b717a9b29052b20b60aefc", "gitTreeState": "clean", "buildDate": "2026-08-26T10:44:25Z", "goVersion": "go1.26.6", "compiler": "gc", "platform": "linux/amd64"}El API server. kubernetes.default es un nombre de otro namespace, completado por la lista de búsqueda. /version se puede leer sin credenciales; -k se salta la comprobación del certificado, que un cliente real hace con el certificado de la CA del clúster, montado por defecto en cada pod junto con el token de su service account. Así es como los controladores y los operadores que se ejecutan en pods llegan a la API (la lección 10 les da permisos).
Fuentes
Sección titulada «Fuentes»- Documentación de Kubernetes: Service, Virtual IPs and service proxies, DNS for Services and Pods, Debugging DNS resolution, EndpointSlices, Ingress, Gateway API
- Blog de Kubernetes: obsolescencia de Endpoints, retirada de Ingress NGINX
- Gateway API, ingress2gateway
- kind: LoadBalancer, Ingress, mapeos de puertos adicionales; README de cloud-provider-kind en v0.11.1