Resumo de kubedns no Kubernetes

Descoberta de serviço interno

Podemos acessar os serviços fornecidos pelo Pod através do ClusterIP (VIP) gerado pelo Service, mas ainda existe um problema ao utilizá-lo: como sabemos o VIP de uma aplicação? Por exemplo, temos dois aplicativos, um é um aplicativo de API e o outro é um aplicativo de banco de dados. Ambos os aplicativos são gerenciados por meio de implantação e expõem portas para fornecer serviços por meio de serviço. A API precisa se conectar ao aplicativo db. Só sabemos o nome do aplicativo db e o nome do serviço correspondente ao db, mas não sabemos seu endereço VIP. Aprendemos no curso de serviço anterior que podemos acessar o de volta pelo serviço ClusterIP Pod, se soubermos o endereço do VIP, tudo bem?

apiserver

Sabemos que as informações dos Endpoints de back-end do serviço correspondente podem ser consultadas diretamente do apiserver, portanto, a maneira mais fácil é consultar diretamente do apiserver. Se houver um aplicativo especial ocasionalmente, podemos usar o apiserver para consultar os Endpoints por trás do serviço diretamente. Não há problema, mas se cada aplicativo consultar os serviços dependentes ao iniciar, isso não apenas aumenta a complexidade do aplicativo, mas também faz com que nosso aplicativo dependa do Kubernetes, o grau de acoplamento é muito alto e não é universal sexo.

variável de ambiente

Para resolver o problema acima, na versão anterior, o Kubernetes adotava o método da variável de ambiente. Ao iniciar cada Pod, ele definirá as informações de IP e porta de todos os serviços por meio da variável de ambiente, para que o aplicativo no Pod possa ler as variáveis ​​de ambiente para obter as informações de endereço dos serviços dependentes. Este método é relativamente simples de usar, mas há um grande problema que os serviços dependentes devem existir antes do Pod iniciar, caso contrário, eles não serão injetados nas variáveis ​​de ambiente. Por exemplo, primeiro criamos um serviço Nginx: (test-nginx.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  labels:
    k8s-app: nginx-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    name: nginx-service
spec:
  ports:
  - port: 5000
    targetPort: 80
  selector:
    app: nginx

Crie o serviço acima:

$ kubectl create -f test-nginx.yaml
deployment.apps "nginx-deploy" created
service "nginx-service" created
$ kubectl get pods
NAME                                      READY     STATUS    RESTARTS   AGE
...
nginx-deploy-75675f5897-47h4t             1/1       Running   0          53s
nginx-deploy-75675f5897-mmm8w             1/1       Running   0          53s
...
$ kubectl get svc
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
...
nginx-service   ClusterIP   10.107.225.42    <none>        5000/TCP         1m
...

Podemos ver que dois Pods e um serviço chamado nginx-service foram criados com sucesso. O serviço escuta na porta 5000 e encaminhará o tráfego para todos os Pods que ele faz proxy (temos o app: nginx label aqui dois Pods).

Agora, vamos criar um pod comum novamente e observar se a variável de ambiente no pod contém as informações de serviço do nginx-service acima: (test-pod.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: test-service-pod
    image: busybox
    command: ["/bin/sh", "-c", "env"]

Em seguida, crie um pod para esse teste:

$ kubectl create -f test-pod.yaml
pod "test-pod" created

Após a criação do Pod, verificamos as informações do log:

$ kubectl logs test-pod
...
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=test-pod
HOME=/root
NGINX_SERVICE_PORT_5000_TCP_ADDR=10.107.225.42
NGINX_SERVICE_PORT_5000_TCP_PORT=5000
NGINX_SERVICE_PORT_5000_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_SERVICE_SERVICE_HOST=10.107.225.42
NGINX_SERVICE_PORT_5000_TCP=tcp://10.107.225.42:5000
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
NGINX_SERVICE_SERVICE_PORT=5000
NGINX_SERVICE_PORT=tcp://10.107.225.42:5000
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
...

Podemos ver que muitos processamentos de variáveis ​​de ambiente foram impressos, incluindo o serviço nginx que acabamos de criar, incluindo HOST, PORT, PROTO, ADDR, etc., bem como outras variáveis ​​de ambiente de serviço existentes. acessar o serviço nginx-service neste Pod, podemos passar diretamente NGINX_SERVICE_SERVICE_HOST e NGINX_SERVICE_SERVICE_PORT, mas também sabemos que se o serviço nginx-service não foi iniciado quando o Pod é iniciado, na variável de ambiente estamos Se esta informação não pode ser obtido, é claro que podemos usar métodos como initContainer para garantir que o serviço nginx seja iniciado antes de iniciar o pod, mas esse método aumenta a complexidade da inicialização do pod, portanto, esse não é o método ideal.

cuboDNA

Devido às limitações das variáveis ​​de ambiente acima, precisamos de uma solução mais inteligente. Na verdade, podemos aprender uma solução ideal por nós mesmos: ou seja, podemos usar diretamente o nome do serviço, porque o nome do serviço não Não precisamos nos preocupar com o endereço ClusterIP alocado, porque esse endereço não é fixo, então seria ótimo se usássemos diretamente o nome do serviço e, em seguida, a conversão do endereço ClusterIP correspondente pudesse ser feita automaticamente. Sabemos que a conversão direta entre nome e IP é muito parecida com os sites que costumamos visitar? A função de conversão entre eles pode ser resolvida por meio do DNS. Da mesma forma, o Kubernetes também fornece uma solução de DNS para resolver o problema de descoberta de serviço acima.

Introdução ao Kubedns

O serviço DNS não é um serviço de sistema independente, mas existe como um plug-in addon, ou seja, não é necessário ser instalado no cluster Kubernetes. Claro, recomendamos fortemente a instalação. Este plug-in pode ser Considerado um complemento em execução no cluster Kubernetes. Sempre foi um aplicativo especial e agora existem dois plug-ins recomendados: kube-dns e CoreDNS. Instalamos o plug-in kube-dns diretamente quando usamos o kubeadm para criar o cluster. Se você não se lembra, pode voltar e dar uma olhada. Claro, também é muito conveniente se quisermos usar o CoreDNS, basta executar o seguinte comando:

$ kubeadm init --feature-gates=CoreDNS=true

O pod DNS do Kubernetes inclui 3 contêineres, que podem ser visualizados por meio da ferramenta kubectl:

$ kubectl get pods -n kube-system
NAME                                    READY     STATUS    RESTARTS   AGE
...
kube-dns-5868f69869-zp5kz               3/3       Running   0          19d
...

A coluna READY pode ser vista como 3/3 e os três contêineres incluídos no kube-dns podem ser vistos claramente usando o seguinte comando:

$ kubectl describe pod kube-dns-5868f69869-zp5kz -n kube-system

Quais são as funções dos três contêineres kube-dns, dnsmasq-nanny e sidecar?

  • kubedns: Com base na biblioteca SkyDNS, o kubedns monitora os eventos de alteração de Service e Endpoints por meio do apiserver e os sincroniza com o Cache local, realizando uma descoberta de serviço DNS em tempo real de Service e Pod no cluster Kubernetes
  • dnsmasq: O contêiner dsnmasq implementa a função de cache DNS (reservar um local com tamanho padrão de 1G na memória para salvar os registros de consulta DNS mais usados ​​no momento. Se não houver nenhum registro a ser encontrado no cache, ele consultará em kubedns. e armazenar em cache os resultados), gerar configuração dinamicamente ouvindo ConfigMap
  • sider: o contêiner sidecar implementa a detecção de DNS configurável, coleta os indicadores de monitoramento correspondentes e os expõe para uso pelo prometheus
    insira a descrição da imagem aqui

Impacto nos conjuntos

O DNS Pod tem um IP estático e é exposto como um serviço Kubernetes. Depois que esse IP estático for atribuído, o kubelet passará --cluster-dns = <dns-service-ip>o DNS configurado com parâmetros para cada contêiner. O nome DNS também requer um nome de domínio e o domínio local pode ser --cluster-domain = <default-local-domain>configurado no kubelet usando parâmetros.

Dizemos que o contêiner dnsmasq gera dinamicamente a configuração ouvindo o ConfigMap e pode personalizar domínios stub e servidores de nome de domínio upstream e downstream.

Por exemplo, o seguinte ConfigMap estabelece uma configuração DNS com um único domínio stub e dois servidores de nomes upstream:

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {"acme.local": ["1.2.3.4"]}
  upstreamNameservers: |
    ["8.8.8.8", "8.8.4.4"]

As solicitações de DNS com o sufixo **.acme.local** são encaminhadas para o DNS 1.2.3.4 conforme explicado acima. Os servidores DNS públicos do Google atendem a consultas upstream. A tabela a seguir descreve como as consultas com nomes de domínio específicos são mapeadas para seus servidores DNS de destino:

nome do domínio O servidor que respondeu à consulta
kubernetes.default.svc.cluster.local para dns
foo.acme.local DNS personalizado (1.2.3.4)
widget.com DNS upstream (um de 8.8.8.8, 8.8.4.4)

Além disso, também podemos definir políticas de DNS para cada Pod. Atualmente, o Kubernetes oferece suporte a duas políticas de DNS específicas do pod: "Default" e "ClusterFirst". Essas políticas podem ser especificadas por meio do sinalizador dnsPolicy.

Observação: o padrão não é a política de DNS padrão. Se nenhum dnsPolicy for especificado explicitamente , ClusterFirst será usado

  • Se dnsPolicy for definido como "Default", a configuração de resolução de nomes será herdada do nó em que o pod está sendo executado. Servidores de nomes upstream personalizados e domínios stub não podem ser usados ​​com esta política
  • Se dnsPolicy estiver definido como "ClusterFirst", isso dependerá se os domínios stub e os servidores DNS upstream estão configurados
    • Nenhuma configuração personalizada: qualquer solicitação que não corresponda ao sufixo do nome de domínio do cluster configurado acima, como "www.kubernetes.io", será encaminhada para o servidor de nomes upstream herdado do nó.
    • Faça uma configuração personalizada: se os domínios stub e os servidores DNS upstream estiverem configurados (semelhante ao que foi configurado no exemplo anterior), as consultas DNS encaminharão as solicitações com base no seguinte processo:
      • As consultas são enviadas primeiro para a camada de cache do DNS em kube-dns.
      • Na camada de cache, verifique o sufixo da solicitação e encaminhe-o ao DNS correspondente de acordo com as seguintes condições:
        • Nome com sufixo de cluster (por exemplo, ".cluster.local"): as solicitações são enviadas para kubedns.
        • Nome com sufixo de domínio stub (por exemplo, ".acme.local"): a solicitação é enviada para o resolvedor de DNS personalizado configurado (por exemplo, escuta em 1.2.3.4).
        • Falha ao corresponder ao nome com sufixo (por exemplo, "widget.com"): a solicitação é encaminhada para o DNS upstream (por exemplo: servidores DNS públicos do Google, 8.8.8.8 e 8.8.4.4).
          insira a descrição da imagem aqui

formato de nome de domínio

Dissemos anteriormente que, se o serviço que construímos oferece suporte à resolução de nomes de domínio, podemos resolver nossa função de descoberta de serviço; portanto, que tipo de registro DNS pode ser gerado pelo serviço usando kbedns?

  • Serviço Ordinário: Será gerado o nome de domínio servicename.namespace.svc.cluster.local, que será resolvido para o ClusterIP correspondente ao Serviço. A chamada entre Pods pode ser abreviada como servicename.namespace. Se estiver sob o mesmo namespace, pode até ser Apenas escreva servicename para acessar
  • Headless Service: serviço headless, ou seja, se clusterIP estiver definido como None, será resolvido para a lista de IPs do Pod especificado, e um Pod específico também poderá ser acessado por meio de podname.servicename.namespace.svc.cluster.local.

As funções implementadas pelo CoreDNS são consistentes com as do KubeDNS, mas todas as funções do CoreDNS estão integradas no mesmo contêiner. Na última versão 1.11.0, o CoreDNS foi oficialmente recomendado. Você também pode instalar o CoreDNS em vez do KubeDNS. Outros O o uso é o mesmo: https://coredns.io/

teste

Agora vamos usar um Pod simples para testar o acesso ao nome de domínio do Serviço:

$ kubectl run --rm -i --tty test-dns --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
/ #

Entramos no Pod, verificamos o conteúdo de **/etc/resolv.conf, podemos ver o endereço do nameserver 10.96.0.10**, este endereço IP é um IP estático fixo atribuído pelo cluster quando o plugin kubedns é instalado Address, podemos visualizá-lo com o seguinte comando:

$ kubectl get svc kube-dns -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP   62d

Ou seja, o nameserver padrão do nosso Pod é o endereço de kubedns. Agora vamos visitar o serviço nginx-service que criamos anteriormente:

/ # wget -q -O- nginx-service.default.svc.cluster.local

Pode-se observar que quando utilizamos o comando wget para acessar o nome de domínio do serviço nginx-service, ficamos travados e não obtivemos os resultados esperados, isso porque a porta exposta quando criamos o Serviço acima era 5000:

/ # wget -q -O- nginx-service.default.svc.cluster.local:5000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
    
    
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Adicione a porta 5000 e você poderá acessar o serviço normalmente. Tente acessar: nginx-service.default.svc, nginx-service.default, nginx-service. Não surpreendentemente, esses nomes de domínio podem acessar os resultados esperados normalmente.

Neste ponto, percebemos a comunicação entre nós por meio do nome de domínio Service dentro do cluster? Vamos tentar acessar serviços em diferentes namespaces por nós mesmos.


Acho que você gosta

Origin blog.csdn.net/u010674953/article/details/129838288
Recomendado
Clasificación