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

Как и в любом деле в Интернет есть свои невидимые и незаметные работники, ежедневно, ежечасно… ежемиллисекундно выполняющие свои незамысловатые рутинные операции. Это конечно же маршрутизаторы, коммутаторы и другие устройства доставляющие пакеты данных из одной точки в другую. В них есть собственные регулировщики загрузки, перенаправляющие потоки другим путем в случае образования заторов. Но откуда они все знают куда доставить эти пакеты? Знающий человек скажет — «так там указан IP-адрес» и будет прав. Но обычный веб-серфер, как правило и представления не имеет об IP адресах, но тем не менее несколько миллиардов простых веб-серферов вполне себе успешно «бороздят» Интернет. Такую возможность им, да и «лицо» современной сети Интернет определяет другой «умпа-лумп» — служба DNS.

Большинство пользователей никогда не узнают о ее существовании, да что пользователи, многие системные администраторы, не говоря уже о программистах, представляют ее возможности достаточно поверхностно. Думаю, что не ошибусь, если скажу что и «крутые перцы» редко используют «продвинутые» приемы связанные с DNS. А между тем, многие функции, предоставляемые службой доменных имен, являются необходимыми элементами при создании высоконадежных и масштабируемых систем. Самые известные этих функций — это балансировка нагрузки и обеспечение отказоустойчивости. Более сложные — это геобалансировка, маршрутизация трафика. Да, да, именно маршрутизация с использованием средств DNS, но на этом мы сейчас останавливаться не будем. Мы начнем с простых вещей.



Что же наши «умпа-лумпы» DNS могут предложить для балансировки нагрузки? Наиболее очевидный и легко реализуемый способ, это так называемая балансировка round-robin. Она основана на том факте, что в DNS можно добавить несколько записей типа A (или AAA) для одного и того же имени. После чего DNS сервер будет отдавать их по-очереди, отправляя клиента то на один, то на другой сервер. Настроить такую балансировку несложно с использованием панели управления доменом любого провайдера или DNS сервера. Задача переходит из разряда «администрирование» в разряд «программирование» как только нам необходимо добавлять и убирать сервера в ферму автоматически. Например, если это сервера Amazon и у них динамический адрес. И уже точно, без написания скриптов не справиться с задачей обеспечения отказоустойчивости (failover).



Чтобы управлять сервером DNS он должен предоставлять определенное API. Самым простым «API» можно считать команду nsupdate, которая входит в состав практически всех дистрибутивов *nix и имеется в составе cygwin под Windows. Она может принимать команды из файла, и соответственно, ее работу можно запрограммировать, сгенерировав или подготовив заранее такой файл с командами. Например для динамического обновления записей о серверах мы можем настроить использование TSIG в BIND и далее:

# nsupdate -k файл_ключа файл_с_командами
Файл ключа выглядит так:
key domain.tld {
   algorithm hmac-md5;
   secret "PR3IxM1WocUm5uJ6-+yQeSmHbohhPR97K4RuNH2Vg7bYzM3R9Z27Li1w==";
};

Файл с командами так:
    server 192.168.100.1
    zone domain.tld
    update delete server1.domain.tld 3600 A
    update add server1.domain.tld 3600 A 192.168.100.99
    send

Между прочим, я использую этот прием для автоматической регистрации в собственном, внутреннем DNS новых серверов созданных в Amazon.

Другая разновидность API для управления DNS — это публичные сервисы DDNS (Dynamic Domain Name Services). Среди них можно назвать EasyDNS, DynDNS, NameCheap, Zoneedit и т. д. Интересующиеся могут поднять исходники универсального клиента обновлений ddclient и посмотреть в деталях как это реализуется. Все эти API представляют собой по сути протоколы обращения к определенным управляемым серверам DNS для добавления/обновления/удаления динамический адресных записей. Сервисы DDNS решают одну простую задачу — дать возможность людям с динамическим адресом, выдаваемым провайдером найти свой компьютер по имени. Вы регистрируетесь в сервисе, назначаете своему компьютеру в одном из предлагаемых доменов. Далее в клиентском ПО, на своем компьютере указываете это имя, регистрационное имя и пароль выбранного сервиса. После чего программа самостоятельно определяет ваш реальный IP адрес и регистрирует в DNS сервиса соответствующую адресную запись. При смене адреса провайдером, программа автоматически изменит его и в DNS сервиса. Таким образом вы получаете постоянное имя для меняющегося IP.

Если необходим полный контроль над DNS, например, если вы создаете сложный, высоконадежный распределенный сервис или являетесь провайдером хостинга и вам необходимо динамически перераспределять пространство IP-адресов, существуют полноценные API управления DNS: Dynect от DynDNS или PowerDNS Express от PowerDNS. Я остановлюсь на первом — Dynect, так как мне приходится, в рамках одного из наших проектов весьма плотно с ним работать.

Dynect — это API для управления DNS серверами компании «Dynamic Network Services Inc.», известной по своей торговой марке DynDNS. Я буду на нее ссылаться как на «Dyn». Сервера DNS Dyn размещены по всему миру и представлены в нескольких дата-центрах в каждом из географических регионов (к сожалению, пока без России, но это не создает больших проблем). Но при этом все они (или группа, зависит от прав) управляются как одно целое через Dynect. Такое распределение дает серьезное расширение возможностей службы имен с точки зрения надежности, геобалансировки и геотаргетирования.

Dynect предоставляет практически полный набор вызовов для управления DNS и DDNS (в том числе и сервисом DynDNS) плюс систему разграничения прав. Последнее важно, так как позволяет стоить на базе Dynect различные публичные сервисы и изолировать записи и пользователей в рамках одного или нескольких доменов. Функции разделены на группы:

  • Общие (General) — служат для управления подключением к API (Sessions), управления ключами TSIG, получения разнообразной информации.
  • Пользователи (Users) — как следует из названия, служат для управления пользователями и их правами.
  • Зоны (Zones) — группа, служащая для управления зонами DNS и записями в них.

Полный список функций представлен на сайте DynDNS и доступен после регистрации в качестве партнера или корпоративного клиента. Каждая из функций имеет как REST, так и SOAP вызов. Имеется еще экспериментальная поддержка XML-RPC, но я ее не пробовал. Моим любимым способом вызова является SOAP/WSDL, так как в этом случае у меня нет необходимости вручную описывать вызовы и проделывать связанные с этим операции поддержанию библиотеки вызовов в актуальном состоянии. В качестве языка программирования я использую Java (и среду Netbeans), но на сайте Dyn есть примеры и для других языков.

Посмотрим, как с использованием Dynect можно обновить запись. Логически мы должны выполнить следующие шаги: зарегистрироваться в Dynect (создать сессию), обновить запись, опубликовать изменения, выйти (закрыть сессию). Приводимый ниже код не полный. Так как с одной стороны, пример демонстрационный. С другой, собственно сам класс обращения к Dynect генерируется Netbeans автоматически по WSDL-файлу и править такой, автоматически сгенерированный код, нет никакой необходимости.

   public update() {
      try {
          if ( userLogin(customerCode, userName, userPassword) {
              if (updateARecord(zone, fqdn, ip))
                 publishZone(zone);
          userLogout();
          }
      } catch ( ErrorResponse ex) { // обработчик исключения
      }
   }

    /**
     * Зарегистрироваться в DynDNS. Регистрация самостоятельно обрабатывает 
     * исключения.
     * @param customerCode
     * @param userName
     * @param userPassword
     * @return 
     */
    public boolean userLogin( String customerCode, String userName, String userPassword ) {
            SessionLoginRequestType sessionRequest;
            SessionLoginResponseType sessionResponse;
            boolean status;

        sessionRequest = new SessionLoginRequestType();            
        sessionRequest.setUserName(userName);
        sessionRequest.setPassword(userPassword);
        ...
        try {
            sessionResponse = DynDNS.sessionLogin(sessionRequest);
            if ( success.equalsIgnoreCase(sessionResponse.getStatus()) ) {
                loginData = sessionResponse.getData();
                status = true;
            } else {
                status = false;
            }
        } catch (ErrorResponse ex) {
            status = false;
        }
        return status;
    }

    /**
     * Выйти из DynDNS
     * @throws ErrorResponse 
     */
    public void userLogout() throws ErrorResponse {
            SessionLogoutRequestType logoutRequest = new SessionLogoutRequestType();
            SessionLogoutResponseType logoutResponse;

        if ( loginData != null ) {
            logoutRequest.setToken(loginData.getToken());
            logoutResponse = DynDNS.sessionLogout(logoutRequest);            
        }
    }

  /**
     * Обновить запись типа A в DynDNS
     * @param zone
     * @param fqdn
     * @param ip
     * @return
     * @throws ErrorResponse 
     */
    public boolean updateARecord ( String zone, String fqdn, String ip ) throws ErrorResponse {
            UpdateARecordRequestType request = new UpdateARecordRequestType();
            UpdateARecordResponseType response;
            RDataA   value = new RDataA();
            boolean status;

        request.setToken(loginData.getToken());
        request.setFqdn(fqdn);
        request.setZone(zone);
        value.setAddress(ip);
        request.setRdata(value);
        response = DynDNS.updateARecord(request);

        status = success.equalsIgnoreCase(response.getStatus());
        return status;
    }

  /**
     * Функция обновляет зону в DynDNS - публикует изменения в DNS.
     * @param zone - обновляемая зона
     * @return 
     * @throws api2.dynect.net.ErrorResponse
     */
    public boolean publishZone ( String zone ) throws ErrorResponse {
            PublishZoneRequestType request;
            PublishZoneResponseType response;
            boolean status;

        request = new PublishZoneRequestType();
        request.setToken(this.loginData.getToken());
        request.setZone(zone);
        response = DynDNS.publishZone(request);
        status = success.equalsIgnoreCase(response.getStatus());

        return status;
    }

Внимательный читатель заметит, что в вызовах фигурирует еще некое customerCode. Да, чтобы получить доступ к Dynect API в полном объеме необходимо вступить с компанией Dyn в определенные отношения, и тогда вам выдадут значение для этого поля. Мы для ДинРУ, на базе Dynect разработали целый рад Интернет-инструментов.

В качестве заключения. Недавно получил сообщение от одной из известных Российских Интернет компаний о проводимых работах с просьбой переписать имя сервера в коде клиента обращения к их ресурсам… Похоже архитекторы этой системы вообще никогда не слышали про DNS… Может хватит пилить Интернет на коленке?

Комментарии (13)


  1. Ivan_83
    21.04.2015 22:13
    +2

    В топку динднс, именно корпорацию.
    Есть бесплатные аналоги не хуже, а за деньги лучше сразу свой домен купить и городить на нём собственный динднс для собственных нужд.


    1. AxianLTD Автор
      23.04.2015 08:00

      Буду признателен если вы покажете «бесплатный аналог не хуже»?
      К сожалению ничего нет и близко. Как все это поверхностные суждения заключающиеся в попытке сравнить только сервис DDNS. Но статья не про это…
      Я не фанат Dyn, но для промышленных решений кроме пока них не предлагает никто.


      1. zup
        23.04.2015 18:18

        ну почему же никто не предлагает?
        существуют же коммерческие gslb продукты, которые можно купить в том aws marketplace.
        да, это скорее всего не подойдет для мелких проектов. но, если бюджет позволяет, почему нет?
        на dns запросы gslb решение всегда будет возвращать адрес из доступной локации, плюс можно динамически добавлять адреса серверов используя api балансировщика.

        в общем, решения существуют. вопрос бюджетов.


        1. AxianLTD Автор
          23.04.2015 18:43

          Как говорил мой преподаватель философии — прежде чем спорить или высказываться, определитесь с предметом. Ivan_83 предлагал использовать «бесплатные аналоги», я же как раз за промышленный подход. Так что мы с вами zup на одной волне ;-)


          1. AxianLTD Автор
            23.04.2015 18:49

            Да, хотел добавить. gslb, насколько я понимаю, относится только к хостингу на базе Amazon, всем остальным придется решать вопросы самостоятельно.


            1. zup
              23.04.2015 18:57

              ну здесь опять-таки есть gslb вендоры, которые продают виртуалки для самых разных гипервизоров.
              поэтому, если не используете Amazon, можно взять другой хостинг (vmware, hyper-v, xenserver, kvm) и развернуть виртуальный gslb.


          1. zup
            23.04.2015 18:52

            ок :) просто Ivan_83 писал про бесплатные, а я привязался к

            Я не фанат Dyn, но для промышленных решений кроме пока них не предлагает никто.


            1. AxianLTD Автор
              23.04.2015 19:05

              Согласен ;-) Век живи, век учись


  1. foxmuldercp
    22.04.2015 20:26

    У меня с одной стороны проще, с другой — веселее:
    docker-host при создании/(пере)запуске/удалении контейнера по шаблону имени контейнера скриптами регистрируется/обновляется/удаляется в связке powerdns + postgresql на внутренние зоны.


    1. AxianLTD Автор
      23.04.2015 08:04

      Вариант на коленке работает. Сам делаю так когда задача этого требует.
      Но есть задачи когда «на коленке» не вариант. Скрипты выдержат 1000 серверов? А 10000? А встраивание в бизнес-приложение? А мониторинг? А 10 географических зон? И как синхронизировать все это будем? Создадим собственный Dyn? Но почему мы все время пытаемся быть кустарями-ремесленниками? Зачем все время повторяем одно и тоже, одни и те же ошибки?


      1. foxmuldercp
        23.04.2015 13:24

        Буду делать дальше, скорее всего архитектура поменяется, поскольку это не один docker-host и далеко не с одним контейнером


  1. achekalin
    24.04.2015 11:50

    Есть теория, что NS-сервера для домена должны жить в разных TLD, так, чтобы даже при смерти/недоступности для мира части корневых серверов домер ресолвился через NS-ы в других TLD.

    Это логично, и я как-то был свидетелем, как подобная предосторожность спасает нервы, когда, скажем, зоны .net или .com перестают ресолвиться, но, что удивительно, что Google, что DynDNS как компании живут на NS-ах в одной TLD. И вот Dyn я понять не могу — их работа как раз обеспечить работу доменов клиентов при любых проблемах в Интернете…


    1. AxianLTD Автор
      24.04.2015 11:59

      Не очень понятна теория — каждый из корневых серверов содержит полную информацию о всех корневых tld и способен ее ресолвить. NS сервера Dyn распределены по миру по десятку дата-центров. За 15 лет не было ни одного отказа, даже когда некоторые корневые сервера подвергались атаке. Так что свою задачу IMHO Dyn выполняет. К стати, Яндекс тоже имеет существенные мощности DNS, распределенные по стране, поэтому мы его и выбрали как бэкенд для своего DDNS.
      Проблемы ресолвинга для tld, о которых вы говорите скорее всего связаны с проблемами общей маршрутизации с каком-то из сегментов сети.