Use Fully Qualified Domain Name (FQDN) for GSLB Pool Member with F5 DNS

Normally, we define a specific IP (and port) to be used as GSLB pool member. This article provides a custom configuration to be able to use Fully Qualified Domain Name (FQDN) as GSLB pool member--with all GSLB features like health-check monitoring, load balancing method, persistence, etc. 

Despite GSLB as a mechanism to distribute traffic across datacenters having reached years of age, it has not become less relevant this recent years. The fact that internet infrastructure still rely heavily on DNS technology means GSLB is continuously used due to is lightweight nature and smooth integration.

When using F5 DNS as GSLB solution, usually we are dealing with LTM and its VS as GSLB server and pool member respectively. Sometimes, we will add a non-LTM node as a generic server to provide inter-DC load balancing capability. Either way, we will end up with a pair of IP and port to represent the application, in which we sent a health-check against. 

Due to the trend of public cloud and CDN, there is a need to use FQDN as GSLB pool member (instead of IP and port pair). Some of us may immediately think of using a CNAME-type GSLB pool to accommodate this. However, there is a limitation in which BIG-IP requires a CNAME-type GSLB pool to use a wideIP-type pool member, in which we will end up with an IP and port pair (again!)

CNAME-type GSLB pool need to use wideIP-type of member

We can use "static target", but there is "side-effect" where the pool member will always consider available (which then triggers the question why we need to use GSLB in the first place!).

Additionally, F5 BIG-IP TMUI accepts FQDN input when we configure GSLB server and pool member. However, it will immediately translate to IP based on configured DNS. Thus, this is not the solution we are looking for

Now this is where F5’s BIG-IP power (a.k.a programmability) comes into play.

 

Enter the realm of customization...

We all love customization, but at the same time do not want that to be overly complicated so that life becomes harder on day-2 🙃. Thus, the key is to use some customization, but simple enough to avoid unnecessary complication. 
Here is one idea to solve our FQDN as GSLB pool problem above

Configuration structure to enable FQDN as GSLB pool

The customized configuration object includes

1. External health-check monitor:

  • Dynamically resolve DNS to translate FQDN into IP address
  • Perform health-check monitoring against current IP address
  • Result is used to determine GSLB pool member availability status

2. DNS iRules:

  • Check #1: Checks if GSLB pool attached to wideIP contains only FQDN-type member (e.g. other pool referring to LTM VS is also attached to the wideIP)
    • If false, do nothing (let DNS response refer to LTM VS)
    • Otherwise, perform check #2
  • Check #2: Checks current health-check status of requested domain name
    • If FQDN is up, modify DNS response to return current IP of FQDN
    • Otherwise, perform fallback action as requirement (e.g. return empty response, return static IP, use fallback pool, etc.)

3. Internal Datagroup:

  • Store current IP of FQDN, updated according to health-check interval
  • Datagroup record value contains current IP if health-check success. Otherwise, the value contains empty data

Here are some of the codes, where configured; wideIP is gslb.test.com, while GSLB pool member FQDN is arcadia.f5poc.id

1. External health-check monitor config

gtm monitor external gslb_external_monitor { 
    defaults-from external 
    destination *:* interval 10 
    probe-timeout 5 
    run /Common/gslb_external_monitor_script 
    timeout 120 
    #define FQDN here 
    user-defined fqdn arcadia.f5poc.id 
}

   External health-check monitor script

#!/bin/sh
pidfile="/var/run/$MONITOR_NAME.$1..$2.pid"
if [ -f $pidfile ]
then
   kill -9 -`cat $pidfile` > /dev/null 2>&1
fi
echo "$$" > $pidfile
# Obtain current IP for the FQDN
resolv=`dig +short ${fqdn}`
# The actual monitoring action here
curl -fIs -k https://${fqdn}/ --resolve ${fqdn}:443:${resolv} | grep -i HTTP 2>&1 > /dev/null
status=$?
if [ $status -eq 0 ]
then
# Actions when health-check success    
    rm -f $pidfile
    tmsh modify ltm data-group internal fqdn { records replace-all-with { $fqdn {  data $resolv } } }
    echo "sending monitor to ${fqdn} ${resolv} with result OK" | logger -p local0.info
    echo "up"
else
# Actions when health-check fails    
    tmsh modify ltm data-group internal fqdn { records replace-all-with { $fqdn {  } } }
    echo "sending monitor to ${fqdn} ${resolv} with result NOK" | logger -p local0.info
fi
rm -f $pidfile

2. DNS iRules

when DNS_REQUEST { 
   set qname [DNS::question name] 
   # Obtain current IP for the FQDN
   set currentip [class match -value $qname equals fqdn] 
} 
when DNS_RESPONSE { 
   set rname [getfield [lindex [split [DNS::answer]] 4] "\}" 1 ]
   #Check if return is IP address of specially encoded FQDN IP, 10.10.10.10 in this example 
   if {$rname eq "10.10.10.10" }{ 
      #Response is only from pool with external monitor, meaning no other pool is attached to wideIP 
      if {$currentip ne ""}{ 
         #Current FQDN health-check success 
         DNS::answer clear 
         # Use current IP to construct DNS answer section
         DNS::answer insert "[DNS::question name]. 123 [DNS::question class] [DNS::question type] $currentip" 
      } else { 
         #Current FQDN health-check failed #Define action to be performed here 
         DNS::answer clear 
      } 
   } 
}

3. Internal Datagroup

ltm data-group internal fqdn {
    records {
        # Define FQDN as record name
        arcadia.f5poc.id {
            # Record data contains IP, where this will be continuously updated by external monitoring script
            data 158.140.176.219
        }
    }
    type string
}

*GSLB virtual server configuration

10.10.10.10 is used internally to indicate this response come from FQDN-type pool member. To be used by DNS iRule

 

Some testing

The resolve will follow whichever current IP address for the FQDN.
If a returning CNAME response is required, you can do so by modifying DNS irules above.

The logic and code are open to any improvement, so leave your suggestions in the comments if you have any. Thanks!

Published Sep 30, 2024
Version 1.0
  • Hi Doddy_ZUHRI ,

    I have followed your article and set this up and it works fine. Thanks for documenting. It's a clever workaround. 

    My only feedback is the script used in the EAV monitor has this variable which is not defined: $MONITOR_NAME, but it does not break the script. The name of the pid file is just not what you might expect.

    When I first set this up in a lab, I forgot that each instance of BIG-IP DNS must have itself as a server, or another BIG-IP instance, in order to be a Prober. So in my lab I had everything set up correctly except only 1 Generic Host and no BIG-IP instance. The DataCenter was therefore blue and the EAV monitor was not firing. I was focused on finding an issue inside the script, but it was my lack of a GSLB server of type BIG-IP that was the problem. Perhaps this could help someone else.

    Hopefully this helps others and I'm happy for folks to reach out to me directly over DevCentral messaging if they want me to walk them through this. Thanks again Doddy.

    Mike.