About Archive Other Contact

How to implement gdnsd on FreeBSD

I was looking for a solution to increase the availability of my public web sites, see my previous post for the introduction to this.

gdnsd is an authoritative-only name server. The initial ‘g’ stands for geographic, as gdnsd offers a plugin system for geographic (or other sorts of) balancing, redirection, and service-state-concious failover. This post explains how gdnsd is implemented at SoCruel.NU to achieve the availability goals, which are:

To make these goals happen the simplefo gdnsd plugin is used. This is one of the more simple plugins of gdnsd. More complex setups with geographic balacing, redirection and service-state-concious failover scenario’s are possible!

Requirements

The following requirements have to be in place to be able to implement what is described in this post:

Please replace all assumed names and IP addresses with your own, if you want to implement this in your own environment.

Install gdnsd (version 2)

gdnsd has currently 2 major versions: version 2.x and version 3.x. Both are available in the FreeBSD ports and packages collection. Use the following command to install the gdnsd package on the gdns1.mydomain.tld and gdns2.mydomain.tld systems:

$ sudo pkg install gdnsd2

The installation package has created the directory /usr/local/etc/gdnsd, which is where gdnsd stores its configuration. We create two new directories here to store our plugin and service type configurations:

$ sudo mkdir /usr/local/gdnsd/plugins.d
$ sudo mkdir /usr/local/gdnsd/service-types.d

Before we start the configuration of gdnsd we create the adminstate file (otherwise <a href=“https://gdnsd.org/” target=“blank”>gdnsd complains at startup):

$ sudo touch /var/db/gdnsd/admin_state

For more information about the admin_state see the gdnsd wiki.

Configure gdnsd (version 2)

The configuration of this gdnsd implementation consist of 4 parts:

Each of these is discussed below. All 4 must be performed on both the gdns1.mydomain.tld and gdns2.mydomain.tld systems. The configuration of gdns1.mydomain.tld is shown.

gdnsd main config file

The main gdnsd configuration file on FreeBSD is /usr/local/etc/gdnsd/config. This configuration file is clearly documented on the gdnsd GitHub wiki. The main configuration file used for this implementaion looks like:

options => {
   listen => [ 2.4.6.8, 127.0.0.1 ]
   dns_port => 53
   http_listen => [ 127.0.0.1 ]
   http_port => 3506
   chaos_response => "Just a nameserver."
}

service_types => {
   $include{service-types.d}
}

plugins => {
   simplefo => {
      $include{plugins.d}
   }
}

The following is configured here:

gdnsd service type configuration

With a gdnsd service type you define how your end points, in this case the web servers, are monitored by gdnsd. The status is shown on the gdnsd web interface (see the main config file).

The name of the service type for our webapp.mydomain.tld URL is httpmonitorwebapp and its configuration is:

http_monitor_webapp => {
   plugin => http_status
   ok_codes => [200]
   vhost => webapp.mydomain.tld
   url_path => /monitor.html
   interval = 15
   timeout = 5
   up_thresh = 5
   ok_thresh = 3
   down_thresh = 6
}

This is copied and pasted in a file called webapp.conf and put it in the directory /usr/local/etc/gdnsd/service-types.d. This configuration states:

For more detailed information about the gdnsd service types see the gdnsd GitHub wiki.

gdnsd plugin configurations

With a gdnsd plugin you define the failover type of the service you load balance. gdnsd ships with 8 plugins. Here the simple primary -> secondary address failover is chosen using the simplefo plugin. Its configuration is:

webapp => {
   service_types => http_monitor_webapp
   primary => 11.12.13.1
   secondary => 22.33.44.5
}

This is copied and pasted in a file called webapp.conf and put it in the directory /usr/local/etc/gdnsd/plugins.d. This configuration states:

the zone file

The gdnsd zone files reside in the directory /usr/local/etc/gdnsd/zones. A file named webapp.mydomain.tld is created in this directory and the contents are as below:

$TTL 3600
$ORIGIN webapp.mydomain.tld.

@ IN SOA gdns1.mydomain.tld. hostmaster.mydomain.tld. (
           2020042201  ; serial number
           43200       ; Refresh
           3600        ; Retry
           864000      ; Expire
           7200        ; Min TTL
           )

    60           IN     NS   gdns1.mydomain.tld.
    60           IN     NS   gdns2.mydomain.tld.

@   15           DYNA   simplefo!webapp

A gdnsd zone file looks very much like a zone file of any other name server software. Except for the last line:

@   15           DYNA   simplefo!webapp

This is a DYNA record, which is for dynamically-determined address records (both A and AAAA) via plugin code. This line states the following:

Configure the mydomain.tld zone

Once you have done the above, one more item needs to be configured. And that is configure the name servers for the webapp.mydomain.tld domain in the mydomain.tld. zone (which runs on the ns1.mydomain.tld., ns2.mydomain.tld. and ns3.mydomain.tld. name servers). This is done in the last 2 lines of the example zone file shown below:

$ORIGIN mydomain.tld. ; default zone domain
$TTL 3600             ; default time to live

@ IN SOA ns1.mydomain.tld. hostmaster.mydomain.tld. (
           2020042201  ; serial number
           43200       ; Refresh
           3600        ; Retry
           864000      ; Expire
           86400       ; Min TTL
           )

           IN     NS      ns1.mydomain.tld.
           IN     NS      ns2.mydomain.tld.
           IN     NS      ns3.mydomain.tld.

webapp     IN     NS      gdns1.mydomain.tld.
           IN     NS      gdns2.mydomain.tld.

This example zone file can be used for name servers like BIND or NSD.

A failover explained

So what happens when a failover occurs for webapp.mydomain.tld from the primary web server to the secondary web server in case the primary web server becomes unavailable?

The name servers for the webapp.mydomain.tld zone have a time to live value configured of 60 seconds. gdnsd ‘knows’ that the primary web server is down after 6 x 15 seconds is 90 seconds. So after the next (the 7th) interval gdnsd answers queries with the IP address of the secondary (failover) web server. But the clients have to wait a little longer because of the time to live value of 60 seconds, as they will get an update after 120 seconds.

As soon as the primary web server becomes available again gdnsd takes up_thresh times interval seconds to change the query answers back using the primary web server IP address. The clients still depend on the time to live value of 60 seconds. But that is less important in this case, as now no downtime is part of this!

Resources

Some (other) resources about this subject:

Updated: April 28, 2020