Skip to main content

DNS in Kubernetes

Quais os nomes são atribuídos para quais objetos? Quais são os registros DNS atribuídos aos services? Quais são os registros DNS atribuídos aos pods?

Os nodes são criados antes do cluster kubernetes e provavelmente registrados no DNS da sua organização e atribuídos algum ip dentro da rede da sua organização. Como eles são gerenciados não é motivo de preocupação dentro do cluster.

Quando fazemos o setup do cluster o kubernetes deploya um DNS server chamado CoreDNS. Se você fizer o setup manualmente terá que fazer por conta própria.

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 o CoreDNS aqui é um deployment com duas replicas e não um DaemonSet. Também temos um service criado.

Antigamente o kubernetes usava o kube-dns agora usa o coredns. coredns e kube-dns são tudo a mesma coisa nesse momento.

Toda vez que um service ou pod é criado o kube-dns/coredns, depende da configuração do cluster, é responsável por criar uma entrada na tabela de registros. Ele faz isso monitorando o kube-apiserver.

Como qualquer service e pod é acessível em todo o cluster, somente fazer o mapeamento de hostname para ip é o suficiente.

alt text

Os pods podem referenciar outros pods ou services no mesmo namespace somente pelo nome. Se um pod quiser acessar outro pod em outro namespace deve referenciar o namespace também.

alt text

Ainda podemos passar o grupo e o domain do cluster que funcionaria.

alt text

O DNS record para pods não é criado por default, mas pode ser feito. O record usará o ip do pod e substituirá os . por -.

alt text

Toda vez que um pod é criado seu /etc/resolv.conf utiliza o nameserver apontando para o coredns.

alt text

Explorando um pouco como o coredns é deployado.

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
# Duas replicas para uma questão de redundância e strategy para que pelo menos 1 esteja ativo
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 estejam no mesmo hostname
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: k8s-app
operator: In
values:
- kube-dns
topologyKey: kubernetes.io/hostname
weight: 100

containers:
# O entrypoint é o binário coredns e a configuração passada estará nesse /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 A PORTA 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 um configmap para a configuração do coredns
- configMap:
defaultMode: 420
items:
- key: Corefile
path: Corefile
name: coredns
name: config-volume
...

Se explorarmos o configmap podemos ver que temos vários plugins configurados:

  • errors
  • health
  • kubernetes (este é o plugin que faz o coredns trabalhar com o kubernetes)
  • Prometheus
  • cache
  • reload

Tudo isso são plugins e as configurações passadas para eles. Se quiser explorar mais plugins pode 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 nos concentrar no plugin kubernetes. Para ativar o dns record para pods é só uma entrada aqui.

    kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}

Mas como o pod recebe essa entrada para usar o coredns para resolver os nomes? Kubelet

Se analisarmos o arquivo de config do 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 diminuir a saída
clusterDNS: # Aqui temos uma lista e a primeira e já temos a entrada para o service do coredns
- 10.96.0.10
# Removido para diminuir a saída

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 conferir o resolv.conf de um pod e ver uns detalhes...

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

Veja o nameserver configurado e veja também que temos um search que busca todas as possibilidades. Também vale observar que somente temos a possibilidade de resolver isso para os services e para pod precisamos passar o domain completo.