TCP- и UDP-балансировка для DNS#

В этом примере разворачивается ANIC и DNS-сервер, а затем настраивается балансировка TCP и UDP для DNS-сервиса с использованием ключа stream-snippets в ConfigMap.

Стандартные ресурсы Ingress в Kubernetes предполагают, что используется HTTP-трафик, и не предназначены для обработки TCP- или UDP-трафика, поэтому, чтобы встроить необходимую конфигурацию балансировки TCP/UDP в блок stream {}, используется ключ stream-snippets из ConfigMap.

В ANIC можно использовать headless-сервис и его DNS-имя, чтобы получить реальные IP-адреса подов и балансировать нагрузку между ними. ANIC регулярно заново разрешает DNS-имя, чтобы автоматически обновлять его при добавлении или удалении подов.

Примечание

  • Для тестирования используется утилита dig. Убедитесь, что она установлена.

  • Для настройки TCP/UDP-балансировки используется родная конфигурация Angie.

  1. Установите ANIC. Убедитесь, что порт 5353 открыт как для TCP-, так и для UDP-трафика.

  2. Сохраните публичный IP-адрес ANIC в переменной оболочки:

    $ IC_IP=<ваш_IP-адрес>
    
  3. Сохраните порт 5353, используемый ANIC, в переменной оболочки:

    $ IC_5353_PORT=<номер порта>
    

    Примечание

    Если вы хотите настроить ANIC с помощью сервиса LoadBalancer, то в нем нельзя использовать протоколы TCP и UDP одновременно. В этом случае создайте два отдельных сервиса: для TCP и для UDP. Соответственно, у вас будет два разных публичных IP-адреса (см. примеры ниже).

  4. Разверните DNS-сервер:

    • Разверните две реплики CoreDNS, настроенные на пересылку DNS-запросов на 8.8.8.8.

    • Создайте два сервиса — coredns и coredns-headless.

    Пример
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: coredns
    data:
      Corefile: |
        .:53 {
          forward . 8.8.8.8:53
          log
        }
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: coredns
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: coredns
      template:
        metadata:
          labels:
            app: coredns
        spec:
          containers:
          - name: coredns
            image: coredns/coredns:1.10.0
            args: [ "-conf", "/etc/coredns/Corefile" ]
            volumeMounts:
            - name: config-volume
              mountPath: /etc/coredns
              readOnly: true
            ports:
            - containerPort: 53
              name: dns
              protocol: UDP
            - containerPort: 53
              name: dns-tcp
              protocol: TCP
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                add:
                - NET_BIND_SERVICE
                drop:
                - all
              readOnlyRootFilesystem: true
          volumes:
            - name: config-volume
              configMap:
                name: coredns
                items:
                - key: Corefile
                  path: Corefile
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: coredns
    spec:
      selector:
       app: coredns
      ports:
      - name: dns
        port: 53
        protocol: UDP
      - name: dns-tcp
        port: 53
        protocol: TCP
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: coredns-headless
    spec:
      clusterIP: None
      selector:
       app: coredns
      ports:
      - name: dns
        port: 53
        protocol: UDP
      - name: dns-tcp
        port: 53
        protocol: TCP
    

    Примените настройки:

    $ kubectl apply -f dns.yaml
    
  5. Создайте конфигурацию балансировки нагрузки. В примере настраиваются два сервера: один принимает TCP-трафик на порту 5353, а второй — UDP-трафик на том же порту. Оба сервера балансируют входящий трафик между подами CoreDNS.

    Пример
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: angie-config
      namespace: angie-ingress
    data:
        stream-snippets: |
          resolver kube-dns.kube-system.svc.cluster.local valid=5s;
    
          upstream coredns-udp {
              zone coredns-udp 64k;
              server coredns-headless.default.svc.cluster.local service=_dns._udp resolve;
          }
    
          server {
              listen 5353 udp;
              listen [::]:5353 udp;
              proxy_pass coredns-udp;
              proxy_responses 1;
              status_zone coredns-udp;
          }
    
          upstream coredns-tcp {
              zone coredns-tcp 64k;
              server coredns-headless.default.svc.cluster.local service=_dns-tcp._tcp resolve;
          }
    
          server {
              listen 5353;
              listen [::]:5353;
              proxy_pass coredns-tcp;
              status_zone coredns-tcp;
          }
    

    ANIC поддерживает повторное разрешение DNS-имен с помощью параметра resolve в директиве upstream. При использовании параметра resolve, ANIC не завершит перезагрузку с ошибкой, если имя upstream-хоста не удается разрешить.

    Помимо IP-адресов, ANIC также может получать порты через DNS-записи типа SRV.

    Для разрешения IP-адресов и портов ANIC использует Kube-DNS, который указывается в директиве resolver. Также устанавливается параметр valid=5s, чтобы ANIC повторно разрешал DNS-имена каждые 5 секунд.

    Вместо обычного сервиса coredns используется coredns-headless. Этот сервис создается как headless-сервис, то есть ему не выделяется виртуальный IP, и ANIC может разрешить все реальные IP-адреса подов CoreDNS.

    Примечание

    ANIC завершит перезагрузку с ошибкой, если DNS-имя, указанное в директиве resolver, не может быть разрешено. Чтобы избежать этого, рекомендуется использовать виртуальный IP-адрес сервиса kube-dns вместо его DNS-имени.

  6. Обновите ConfigMap, добавив ключ stream-snippets с конфигурацией балансировки нагрузки.

    Используется ключ stream-snippets в объекте ConfigMap, чтобы настроить балансировку TCP- и UDP-трафика для наших подов CoreDNS.

    Примените настройки:

    $ kubectl apply -f angie-config.yaml
    
  7. Проверьте, что конфигурация успешно применена:

    $ kubectl describe configmap angie-config -n angie-ingress
    . . .
    Events:
    Type    Reason   Age   From       Message
    ----    ------   ----  ----       -------
    Normal  Updated  3s    ANIC       Configuration from angie-ingress/angie-config was updated
    
  8. Протестируйте DNS-сервер.

    Чтобы проверить, что балансировка TCP/UDP работает, выполните разрешение имени kubernetes.io с использованием нашего DNS-сервера, доступного через ANIC.

    Разрешение kubernetes.io через UDP:

    $ dig @$IC_IP -p $IC_5353_PORT kubernetes.io
    
    ; <<>> DiG 9.10.6 <<>> @<REDACTED>> -p 5353 kubernetes.io
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33368
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 512
    ;; QUESTION SECTION:
    ;kubernetes.io.                 IN      A
    
    ;; ANSWER SECTION:
    kubernetes.io.          299     IN      A       45.54.44.100
    
    ;; Query time: 111 msec
    ;; SERVER:<REDACTED>#5353(<REDACTED>)
    ;; WHEN: Fri Aug 17 12:49:54 BST 2018
    ;; MSG SIZE  rcvd: 71
    

    Разрешение kubernetes.io через TCP:

    $ dig @$IC_IP -p $IC_5353_PORT kubernetes.io +tcp
    
    ; <<>> DiG 9.10.6 <<>> @<REDACTED> -p 5353 kubernetes.io +tcp
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49032
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 512
    ;; QUESTION SECTION:
    ;kubernetes.io.                 IN      A
    
    ;; ANSWER SECTION:
    kubernetes.io.          146     IN      A       45.54.44.100
    
    ;; Query time: 95 msec
    ;; SERVER: <REDACTED>#5353(<REDACTED>)
    ;; WHEN: Fri Aug 17 12:52:25 BST 2018
    ;; MSG SIZE  rcvd: 71
    Look at the Ingress Controller logs:
    
    $ kubectl logs <angie-ingress-pod> -n angie-ingress
    . . .
    <REDACTED> [17/Aug/2018:11:49:54 +0000] UDP 200 71 42 0.016
    <REDACTED> [17/Aug/2018:11:52:25 +0000] TCP 200 73 44 0.098
    

    Посмотрите логи:

    $ kubectl logs <angie-ingress-pod> -n angie-ingress
    . . .
    <REDACTED> [17/Aug/2018:11:49:54 +0000] UDP 200 71 42 0.016
    <REDACTED> [17/Aug/2018:11:52:25 +0000] TCP 200 73 44 0.098