DNS en Kubernetes
¿Qué nombres son asignados para qué objetos? ¿Cuáles son los registros DNS asignados a los services? ¿Cuáles son los registros DNS asignados a los pods?
Los nodos son creados antes del cluster Kubernetes y probablemente registrados en el DNS de tu organización y asignados algún IP dentro de la red de tu organización. Cómo son gestionados no es motivo de preocupación dentro del cluster.
Cuando hacemos el setup del cluster, Kubernetes despliega un servidor DNS llamado CoreDNS. Si haces el setup manualmente tendrás que hacerlo por cuenta propia.
k get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-76f75df574-7d75t 1/1 Running 1 (21h ago) 40h 10.40.0.3 cka-cluster-worker <none> <none>
coredns-76f75df574-99kmh 1/1 Running 1 (21h ago) 40h 10.40.0.2 cka-cluster-worker <none> <none>
etcd-cka-cluster-control-plane 1/1 Running 0 21h 172.18.0.5 cka-cluster-control-plane <none> <none>
kube-apiserver-cka-cluster-control-plane 1/1 Running 0 21h 172.18.0.5 cka-cluster-control-plane <none> <none>
kube-controller-manager-cka-cluster-control-plane 1/1 Running 1 (21h ago) 40h 172.18.0.5 cka-cluster-control-plane <none> <none>
kube-proxy-6gk2j 1/1 Running 1 (21h ago) 40h 172.18.0.3 cka-cluster-worker2 <none> <none>
kube-proxy-bgpzr 1/1 Running 1 (21h ago) 40h 172.18.0.2 cka-cluster-worker <none> <none>
kube-proxy-l8xxj 1/1 Running 1 (21h ago) 40h 172.18.0.4 cka-cluster-worker3 <none> <none>
kube-proxy-vg8mb 1/1 Running 1 (21h ago) 40h 172.18.0.5 cka-cluster-control-plane <none> <none>
kube-scheduler-cka-cluster-control-plane 1/1 Running 1 (21h ago) 40h 172.18.0.5 cka-cluster-control-plane <none> <none>
node-shell-0bdf1591-55c6-47fa-acc6-58c934eb2096 0/1 Completed 0 9h 172.18.0.3 cka-cluster-worker2 <none> <none>
weave-net-29ffl 2/2 Running 4 (21h ago) 40h 172.18.0.2 cka-cluster-worker <none> <none>
weave-net-4q8kr 2/2 Running 4 (21h ago) 40h 172.18.0.4 cka-cluster-worker3 <none> <none>
weave-net-8zxbw 2/2 Running 5 (21h ago) 40h 172.18.0.3 cka-cluster-worker2 <none> <none>
weave-net-phbz8 2/2 Running 4 (21h ago) 40h 172.18.0.5 cka-cluster-control-plane <none> <none>
k get deploy -n kube-system -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
coredns 2/2 2 2 40h coredns registry.k8s.io/coredns/coredns:v1.11.1 k8s-app=kube-dns
kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 40h
Observe que el CoreDNS aquí es un deployment con dos réplicas y no un DaemonSet. También tenemos un service creado.
Antiguamente kubernetes usaba el kube-dns, ahora usa coredns. coredns y kube-dns son todo lo mismo en este momento.
Cada vez que un service o pod es creado, el kube-dns/coredns, depende de la configuración del cluster, es responsable de crear una entrada en la tabla de registros. Lo hace monitoreando el kube-apiserver.
Como cualquier service y pod es accesible en todo el cluster, solo hacer el mapeo de hostname para ip es suficiente.

Los pods pueden referenciar otros pods o services en el mismo namespace solo por el nombre. Si un pod quiere acceder a otro pod en otro namespace debe referenciar el namespace también.

Aún podemos pasar el grupo y el dominio del cluster que funcionaría.

El registro DNS para pods no es creado por defecto, pero puede hacerse. El registro usará el ip del pod y sustituirá los . por -.

Cada vez que un pod es creado, su /etc/resolv.conf utiliza el nameserver apuntando al coredns.

Explorando un poco cómo el coredns es desplegado.
kubectl get deploy -n kube-system coredns -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: "2024-02-29T18:15:52Z"
generation: 1
labels:
k8s-app: kube-dns
name: coredns
namespace: kube-system
resourceVersion: "113296"
uid: 9a958820-df9c-46b6-bbed-2b1858bd1008
spec:
progressDeadlineSeconds: 600
# Dos replicas para una cuestión de redundancia y strategy para que al menos 1 esté activo
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: kube-dns
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
k8s-app: kube-dns
spec:
# Para evitar que estén en el mismo hostname
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values:
- kube-dns
topologyKey: kubernetes.io/hostname
weight: 100
containers:
# El entrypoint es el binario coredns y la configuración pasada estará en ese /etc/core/CoreFile
- args:
- -conf
- /etc/coredns/Corefile
image: registry.k8s.io/coredns/coredns:v1.11.1
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 5
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: coredns
# UTILIZA EL PUERTO 53
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9153
name: metrics
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /ready
port: 8181
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- ALL
readOnlyRootFilesystem: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/coredns
name: config-volume
readOnly: true
dnsPolicy: Default
nodeSelector:
kubernetes.io/os: linux
priorityClassName: system-cluster-critical
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: coredns
serviceAccountName: coredns
terminationGracePeriodSeconds: 30
tolerations:
- key: CriticalAddonsOnly
operator: Exists
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
volumes: # Podemos observar que usamos un configmap para la configuración del coredns
- configMap:
defaultMode: 420
items:
- key: Corefile
path: Corefile
name: coredns
name: config-volume
...
Si exploramos el configmap podemos ver que tenemos varios plugins configurados:
- errors
- health
- kubernetes (este es el plugin que hace que coredns trabaje con kubernetes)
- Prometheus
- cache
- reload
Todo esto son plugins y las configuraciones pasadas para ellos. Si quieres explorar más plugins puedes visitar https://coredns.io/plugins/
kubectl describe cm -n kube-system coredns
Name: coredns
Namespace: kube-system
Labels: <none>
Annotations: <none>
Data
====
Corefile:
----
.: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
}
BinaryData
====
Events: <none>
Vamos a concentrarnos en el plugin kubernetes. Para activar el registro DNS para pods es solo una entrada aquí.
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
Pero ¿cómo el pod recibe esa entrada para usar el coredns para resolver los nombres? Kubelet
Si analizamos el archivo de configuración del kubelet podemos ver.
root@cka-cluster-worker:/var/lib/kubelet# cat /var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
# Removido para disminuir la salida
clusterDNS: # Aquí tenemos una lista y la primera ya tenemos la entrada para el service del coredns
- 10.96.0.10
# Removido para disminuir la salida
kubectl get svc -n kube-system -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 42h k8s-app=kube-dns
Vamos a verificar el resolv.conf de un pod y ver algunos detalles...
kubectl exec -it nginx-7854ff8877-wc4dr -c nginx -- bash
root@nginx-7854ff8877-wc4dr:/# cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
Vea el nameserver configurado y vea también que tenemos un search que busca todas las posibilidades. También vale observar que solo tenemos la posibilidad de resolver esto para los services y para pod necesitamos pasar el dominio completo.