company_banner

CoreDNS — DNS-сервер для мира cloud native и Service Discovery для Kubernetes



    Две недели назад Open Source-проект CoreDNS отметился своим очередным релизом — 008. Авторы называют свой продукт «DNS-сервером, состоящим из цепочки промежуточных компонентов (middleware), каждый из которых реализует какую-то возможность DNS». Что примечательно, они уже успели добиться включения CoreDNS в список официальных проектов организации CNCF (Cloud Native Computing Foundation), пополнив ряды Kubernetes, Prometheus, CNI, containerd, rkt и других разработок, активно применяемых в мире контейнеров, микросервисов и «родных облачных приложений» (cloud native).

    Как появился CoreDNS, для чего он предназначен и как его можно использовать?

    Знакомимся с CoreDNS


    CoreDNS — DNS-сервер, появившийся в начале 2016 года (под свободной лицензией Apache License v2) как форк быстрого веб-сервера Caddy, написанного на языке Go. Сам HTTP-сервер в Caddy реализован пакетом httpserver, двумя важнейшими типами в котором являются Handler (функция обработки HTTP-запроса) и Middleware (промежуточный слой, прицепляющий один Handler к другому, — таким образом формируется цепочка из обработчиков). Этот подход с цепочкой из функций переняли и в CoreDNS, что позволило разработчикам описывать своё решение очень лаконично: «CoreDNS — DNS-сервер, сцепляющий middleware».

    Второй основополагающей деталью в проекте CoreDNS является его преемственность от SkyDNS — service discovery, построенного поверх NoSQL-хранилища etcd и использующего DNS-запросы (специально сформированные SRV-записи) для обнаружения доступных сервисов. Фактически SkyDNS был лёгкой прослойкой между etcd, где на самом деле хранилась информация о сервисах, и DNS-сервером, через который эта информация становилась «публично» доступной. Судя по всему, активная разработка SkyDNS прекратилась около 7 месяцев назад (с добавлением поддержки etcd 3) в то время, как коммиты в кодовой базе CoreDNS можно наблюдать практически ежедневно.

    В CoreDNS не стали ограничиваться etcd как единственным бэкендом для данных, отображаемых в DNS-записях. На данный момент поддерживается ещё Kubernetes (который, впрочем, как известно, тоже использует etcd… ), что позволяет авторам официально позиционировать CoreDNS в качестве замены kube-dns. (Подробнее о том, как эту замену попробовать в действии, читайте ниже.)

    Примечание: Полная история взаимоотношений упомянутых DNS-решений: SkyDNS, CoreDNS, kube-dns — переплетена ещё теснее, чем могло показаться. Дело в том, что, во-первых, kube-dns использует библиотеки SkyDNS для обслуживания DNS-запросов, поступающих в поды и сервисы Kubernetes. А во-вторых, главным разработчиком CoreDNS является оригинальный автор SkyDNS — Miek Gieben — SRE из Google, которого также знают в сообществе Go благодаря его DNS-библиотеке. Всё это позволяет увидеть в CoreDNS не «конкурента» kube-dns, а скорее его эволюцию.

    Возможности CoreDNS


    Этот сервер позволяет принимать запросы по UDP/TCP, TLS (RFC 7858) и gRPC. А функционирует он как:

    • первичный DNS-сервер, отдающий данные о зоне из файла (DNS и DNSSEC) и позволяющий выполнять трансфер зоны;
    • вторичный DNS-сервер (поддерживаются только AXFR);
    • прокси (перенаправляет запросы другим серверам).

    Среди других значимых возможностей CoreDNS:

    • кэширование результатов запросов;
    • rewrite для запросов (qtype, qclass, qname);
    • балансировка запросов;
    • проверка состояния (health checking) конечных узлов;
    • метрики в Prometheus;
    • журналирование запросов и ошибок;
    • профилирование.

    Все перечисленные функции (включая даже режимы первичного и вторичного сервера) реализуются различными модулями, а точнее (в терминологии Caddy/CoreDNS) — middleware. Очевидно, что возможности легко расширять созданием новых middleware.


    Архитектура CoreDNS, где за каждую функцию отвечает свой middleware

    John Belamaric, архитектор в Infoblox и один из ведущих разработчиков CoreDNS, считает именно эту особенность главной в проекте:
    Существует множество различных DNS-серверов, существуют даже другие решения для обнаружения сервисов, основанные на DNS. Но одним из главных достоинств CoreDNS является то, насколько это решение расширяемое и гибкое. Это позволяет легко адаптировать его под динамичный, часто изменяющийся мир cloud-native.

    Почему CoreDNS взяли под опеку в CNCF?


    Вот как объясняется это событие на сайте проекта:
    Наша цель — сделать CoreDNS DNS-сервером и решением service discovery для cloud-native. CNCF как организация сосредоточена на совершенствовании архитектур для cloud-native. Таким образом, для нас это прекрасное совпадение [преследуемых целей]. Обнаружение сервисов — ключевой компонент в родном облачном пространстве CNCF, и CoreDNS первенствует в этой роли.

    В заявлении от имени самой CNCF выступил Chris Aniszczyk (COO в CNCF), отметивший, что «CoreDNS предоставляет важные сервисы для именования и эффективно интегрируется со многими другими проектами проектами категории cloud-native в CNCF», а также «CoreDNS — привлекательный вариант для обнаружения сервисов в Kubernetes».

    Примечание: На данный момент CoreDNS имеет начальный статус (inception) среди проектов CNCF, что означает необходимость пересмотра техническим комитетом этого статуса через год и принятия решения о его дальнейшей судьбе: убрать, продлить, повысить до incubating или graduated.

    Перейдём от теории к практике.

    CoreDNS как Service Discovery для Kubernetes


    Как уже писалось в примечании выше, разработчики CoreDNS не просто предлагают альтернативу для kube-dns — они взаимодействуют с сообществом Kubernetes, чтобы результат их работы был полезным для всех. Хороший тому пример — их инициатива по созданию спецификации, описывающей Service Discovery на базе DNS для Kubernetes. Она появилась с тем, чтобы «гарантировать совместимость существующей реализации в Kube-DNS и новой в CoreDNS». Версия 1.0.0 этой спецификации в основном копирует поведение kube-dns — ей соответствуют релизы CoreDNS 005 и выше (предлагая, помимо этого, дополнительные возможности, если сравнивать с kube-dns).

    Чтобы начать использовать CoreDNS в качестве Service Discovery в Kubernetes, разработчики подготовили конфигурацию (ConfigMap и Deployment) и даже Bash-скрипт deploy.sh для быстрого деплоя. Они позаботились и о примере, как этим пользоваться (все дальнейшие листинги взяты из него):

    $ ./deploy.sh 10.3.0.0/24 cluster.local

    • 10.3.0.0/24 — CIDRs сервисов;
    • cluster.local (указывается опционально) — доменное имя кластера.

    Результатом выполнения скрипта станет такой манифест:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: coredns
      namespace: kube-system
    data:
      Corefile: |
        .:53 {
            errors
            log stdout
            health
            kubernetes cluster.local {
              cidrs 10.3.0.0/24
            }
            proxy . /etc/resolv.conf
            cache 30
        }
    ---
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: coredns
      namespace: kube-system
      labels:
        k8s-app: coredns
        kubernetes.io/cluster-service: "true"
        kubernetes.io/name: "CoreDNS"
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: coredns
      template:
        metadata:
          labels:
            k8s-app: coredns
          annotations:
            scheduler.alpha.kubernetes.io/critical-pod: ''
            scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
        spec:
          containers:
          - name: coredns
            image: coredns/coredns:latest
            imagePullPolicy: Always
            args: [ "-conf", "/etc/coredns/Corefile" ]
            volumeMounts:
            - name: config-volume
              mountPath: /etc/coredns
            ports:
            - containerPort: 53
              name: dns
              protocol: UDP
            - containerPort: 53
              name: dns-tcp
              protocol: TCP
            livenessProbe:
              httpGet:
                path: /health
                port: 8080
                scheme: HTTP
              initialDelaySeconds: 60
              timeoutSeconds: 5
              successThreshold: 1
              failureThreshold: 5
          dnsPolicy: Default
          volumes:
            - name: config-volume
              configMap:
                name: coredns
                items:
                - key: Corefile
                  path: Corefile
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: kube-dns
      namespace: kube-system
      labels:
        k8s-app: coredns
        kubernetes.io/cluster-service: "true"
        kubernetes.io/name: "CoreDNS"
    spec:
      selector:
        k8s-app: coredns
      clusterIP: 10.3.0.10
      ports:
      - name: dns
        port: 53
        protocol: UDP
      - name: dns-tcp
        port: 53
        protocol: TCP

    Указанная здесь (в Corefile) директива cidrs 10.3.0.0/24 сообщает в Kubernetes middleware из CoreDNS, что необходимо обслуживать PTR-запросы для обратной зоны 0.3.10.in-addr.arpa.

    Остаётся передать результат на исполнение в Kubernetes:

    $ ./deploy.sh 10.3.0.0/24 | kubectl apply -f -
    configmap "coredns" created
    deployment "coredns" created
    service "kube-dns" configured

    … и убедиться, что новый DNS-сервер действительно заработал:

    $ kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools
    Waiting for pod default/dnstools to be running, status is Pending, pod ready: false
    If you don't see a command prompt, try pressing enter.
    # host kubernetes
    kubernetes.default.svc.cluster.local has address 10.3.0.1
    # host kube-dns.kube-system
    kube-dns.kube-system.svc.cluster.local has address 10.3.0.10
    # host 10.3.0.1
    1.0.3.10.in-addr.arpa domain name pointer kubernetes.default.svc.cluster.local.
    # host 10.3.0.10
    10.0.3.10.in-addr.arpa domain name pointer kube-dns.kube-system.svc.cluster.local.

    Как это выглядит на стороне самого CoreDNS? Вот пример для случая кластера из двух реплик CoreDNS, между которыми делается балансировка DNS-запросов:
    # найдем поды со службой CoreDNS
    $ kubectl get --namespace kube-system pods
    NAME                                    READY     STATUS    RESTARTS   AGE
    coredns-3558181428-0zhnh                1/1       Running   0          2m
    coredns-3558181428-xri9i                1/1       Running   0          2m
    heapster-v1.2.0-4088228293-a8gkc        2/2       Running   0          126d
    kube-apiserver-10.222.243.77            1/1       Running   2          126d
    kube-controller-manager-10.222.243.77   1/1       Running   2          126d
    kube-proxy-10.222.243.77                1/1       Running   2          126d
    kube-proxy-10.222.243.78                1/1       Running   0          126d
    kube-scheduler-10.222.243.77            1/1       Running   2          126d
    kubernetes-dashboard-v1.4.1-gi2xr       1/1       Running   0          24d
    tiller-deploy-3299276078-e8phb          1/1       Running   0          24d
    # посмотрим на логи первого
    $ kubectl logs --namespace kube-system coredns-3558181428-0zhnh
    2017/02/23 14:48:29 [INFO] Kubernetes middleware configured without a label selector. No label-based filtering will be performed.
    .:53
    2017/02/23 14:48:29 [INFO] CoreDNS-005
    CoreDNS-005
    10.2.6.127 - [23/Feb/2017:14:49:44 +0000] "AAAA IN kubernetes.default.svc.cluster.local. udp 54 false 512" NOERROR 107 544.128µs
    10.2.6.127 - [23/Feb/2017:14:49:44 +0000] "MX IN kubernetes.default.svc.cluster.local. udp 54 false 512" NOERROR 107 7.576897ms
    10.2.6.127 - [23/Feb/2017:14:49:52 +0000] "A IN kube-dns.kube-system.default.svc.cluster.local. udp 64 false 512" NXDOMAIN 117 471.176µs
    23/Feb/2017:14:49:52 +0000 [ERROR 0 kube-dns.kube-system.default.svc.cluster.local. A] no items found
    10.2.6.127 - [23/Feb/2017:14:50:00 +0000] "PTR IN 10.0.3.10.in-addr.arpa. udp 40 false 512" NOERROR 92 752.956µs
    # посмотрим на логи второго
    $ kubectl logs --namespace kube-system coredns-3558181428-xri9i
    2017/02/23 14:48:29 [INFO] Kubernetes middleware configured without a label selector. No label-based filtering will be performed.
    .:53
    2017/02/23 14:48:29 [INFO] CoreDNS-005
    CoreDNS-005
    10.2.6.127 - [23/Feb/2017:14:49:44 +0000] "A IN kubernetes.default.svc.cluster.local. udp 54 false 512" NOERROR 70 1.10732ms
    10.2.6.127 - [23/Feb/2017:14:49:52 +0000] "A IN kube-dns.kube-system.svc.cluster.local. udp 56 false 512" NOERROR 72 409.74µs
    10.2.6.127 - [23/Feb/2017:14:49:52 +0000] "AAAA IN kube-dns.kube-system.svc.cluster.local. udp 56 false 512" NOERROR 109 210.817µs
    10.2.6.127 - [23/Feb/2017:14:49:52 +0000] "MX IN kube-dns.kube-system.svc.cluster.local. udp 56 false 512" NOERROR 109 796.703µs
    10.2.6.127 - [23/Feb/2017:14:49:56 +0000] "PTR IN 1.0.3.10.in-addr.arpa. udp 39 false 512" NOERROR 89 694.649µs

    Для отключения логирования всех DNS-запросов (большая нагрузка на диск при реальном применени) достаточно убрать строку log stdout из Corefile.

    Важно: авторы предупреждают, что в случае использования Google Container Engine (GKE) описываемый пример не сработает из-за дополнительных процессов, не позволяющих заменить стандартный kube-dns. Есть путь решения этой проблемы, однако официально он пока не был ими документирован/анонсирован.

    CoreDNS для Minikube


    В случае локального запуска Kubernetes с Minikube есть схожая проблема: используемый в нём addon manager периодически проверяет (и поддерживает) состояние конфигураций всех установленных дополнений, одним из которых является kube-dns. Чтобы этот менеджер не мешал работе CoreDNS, есть простое решение.

    Оно заключается в том, чтобы изменить список установленных дополнений для minikube:

    $ minikube addons list
    - dashboard: enabled
    - default-storageclass: enabled
    - kube-dns: enabled
    - heapster: disabled
    - ingress: disabled
    - registry-creds: disabled
    - addon-manager: enabled
    $ minikube addons disable kube-dns
    kube-dns was successfully disabled
    $ minikube addons list
    - heapster: disabled
    - ingress: disabled
    - registry-creds: disabled
    - addon-manager: enabled
    - dashboard: enabled
    - default-storageclass: enabled
    - kube-dns: disabled

    Эту настройку необходимо выполнить до применения конфигурации CoreDNS в Kubernetes (т.е. до запуска kubectl apply -f из примера выше). А после применения этой конфигурации потребуется ещё удалить ReplicationController из kube-dns, поскольку отключение дополнения не делает этого автоматически:

    $ kubectl get -n kube-system pods
    NAME                          READY     STATUS    RESTARTS   AGE
    coredns-980047985-g2748       1/1       Running   1          36m
    kube-addon-manager-minikube   1/1       Running   0          9d
    kube-dns-v20-qzvr2            3/3       Running   0          1m
    kubernetes-dashboard-ks1jp    1/1       Running   0          9d
    $ kubectl delete -n kube-system rc kube-dns-v20
    replicationcontroller "kube-dns-v20" deleted

    Заключение


    CoreDNS — интересный проект, реальные перспективы которому придают его убедительное наследие (опыт со времён SkyDNS), тесная кооперация с профильным сообществом (Kubernetes и Go), признание в CNCF и, конечно, современный подход к реализации.

    Читайте также в нашем блоге по близким темам:

    Флант
    686,22
    Специалисты по DevOps и Kubernetes
    Поделиться публикацией

    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое