Forum Discussion

bigipjr28_13978's avatar
bigipjr28_13978
Icon for Nimbostratus rankNimbostratus
Jan 28, 2015

Name Based Virtual Hosting irule efficiency

Hey guys,

 

we are currently going the route of name based virutual hosting with all of applications. After finding a terrific doc https://devcentral.f5.com/articles/name-based-virtual-hosting-with-ltm that pretty much explains what we need I have a few concerns on the best way to scale it. Here are my concerns:

 

  1. if have say we have 100 sites, I am guessing that the irule will not scale that well when HTTP_REQUEST { switch [HTTP::host] { iz.hotkittehs.com { pool hotkittehs } www.bukkitsgalor.org { pool bukkitsgalor } icanhaz.devcentral.f5.com { pool icanhaz } default { reject } } } } or will it ? is there another way to make it more scalable efficient? prehaps breaking it out into a couple of separate switch statement while maintaining the same piece of code..thoughts ?

Thanks

 

  • From my experience (as we do something similar in my organization), we've used data groups to handle all this (and parse the values to get information we need).

    Regarding how to interact with data groups, this wiki page gives links to the class, findclass and matchclass functions, which should help guide you in the right direction.

    For us, we sometimes use a format like

    name1:value1|name2:value2|...
    as the data group value (with a hostname or uri prefix as the name on the data group record). From there we parse out the parameters we need. So for example

    • DG Record Name:
      example.com
    • DG Record Value:
      pool:my_pool|host:www.mynewhost.com

    So in our iRule, we would check for

    example.com
    in the data group

    set host [string tolower [HTTP::uri]]
    if { [class match $host equals DATA_GROUP_NAME] } {
        set param [class match -value $host equals DATA_GROUP_NAME]
         Add some checking for data integrity if necesary
    
        set params [split $param "|"]
        set pool [getfield [lsearch -inline -glob $params "pool:*"] ":" 2]
        set host [getfield [lsearch -inline -glob $params "host:*"] ":" 2]
    
         Set the pool
        pool $pool
         Change the host
        HTTP::host $host
    }
    

    It's a simple example, and depending on the amount of traffic, may not be the most efficient way of doing it, but I've found it's the simplest, as we just add a record to the data group and don't have to touch the iRule.

    Hope this helps.

  • Thanks for the great response. For me at least if the backend web servers are going to be using the same set apache ips I would have to create new pools containing the same set of ips, a seperate monitor, than add the pool to the irule that I pasted.

     

    • Michael_Jenkins's avatar
      Michael_Jenkins
      Icon for Cirrostratus rankCirrostratus
      True. To be thorough, you'd want to have separate pools with distinct monitors per application. If your requirements were more generic (i.e. you only care if the web server is up. you're not focused on specific web sites), you could have a single poo with a basic monitor checking just the root web site on the servers. If you need more specific checking (e.g. check that a login page comes up), you would need to have the different ones. The other option is to assign multiple monitors to a single pool, but the problem there comes because the monitors would be logically ANDed rather that ORed (so they both have to be up to be valid)
  • @michael j has it right - data groups are probably best for dealing with matching against a large list of items or matching against a list that changes often. A few of the biggest advantages to using data groups over "if/then" or "switch" logic are readability and you should rarely have to touch the iRule itself. Adding a new hostname/pool-name pair just requires adding an entry to a data-group.

    If you want to base the pool selection on the requested HTTP host header, you can try something like:

    A data group with string entries of name: HTTP hostname and value: pool-name

    ltm data-group internal test-dg {
        records {
            abc.com {
                data abc_pool
            }
            def.com {
                data def_pool
            }
        }
        type string
    }
    

    The associated iRule:

    when HTTP_REQUEST {
     test-dg is a string data-group where the entries are name:value pairs
     name is the requested HTTP host header, value is the associated pool-name
    
         check the requested HTTP host header against entries in data-group test-dg
        if { [class match [string tolower [HTTP::host]] equals test-dg ] } {
             if the HTTP host header is in test-dg
             send the request to the pool associated with the test-dg entry
            pool [class match -value [string tolower [HTTP::host]] equals test-dg ]
        } else {
             drop the request if the host header is not in test-dg
            drop
    }
    }
    
    • bigipjr28_13978's avatar
      bigipjr28_13978
      Icon for Nimbostratus rankNimbostratus
      Making sure I understand correctly as to what the code does. What its doing, upon a request checks the header comparing to the data group list where the pool(s) are going to refrerenced than goes to that pool..if anything else drop the connection
    • bigipjr28_13978's avatar
      bigipjr28_13978
      Icon for Nimbostratus rankNimbostratus
      Making sure I understand correctly as to what the code does. What its doing, upon a request checks the header comparing to the data group list where the pool(s) are going to refrerenced than goes to that pool..if anything else drop the connection
    • bigipjr28_13978's avatar
      bigipjr28_13978
      Icon for Nimbostratus rankNimbostratus
      sorry about the dupliate comment must have submitted it twice. Thanks
  • shaggy's avatar
    shaggy
    Icon for Nimbostratus rankNimbostratus

    @michael j has it right - data groups are probably best for dealing with matching against a large list of items or matching against a list that changes often. A few of the biggest advantages to using data groups over "if/then" or "switch" logic are readability and you should rarely have to touch the iRule itself. Adding a new hostname/pool-name pair just requires adding an entry to a data-group.

    If you want to base the pool selection on the requested HTTP host header, you can try something like:

    A data group with string entries of name: HTTP hostname and value: pool-name

    ltm data-group internal test-dg {
        records {
            abc.com {
                data abc_pool
            }
            def.com {
                data def_pool
            }
        }
        type string
    }
    

    The associated iRule:

    when HTTP_REQUEST {
     test-dg is a string data-group where the entries are name:value pairs
     name is the requested HTTP host header, value is the associated pool-name
    
         check the requested HTTP host header against entries in data-group test-dg
        if { [class match [string tolower [HTTP::host]] equals test-dg ] } {
             if the HTTP host header is in test-dg
             send the request to the pool associated with the test-dg entry
            pool [class match -value [string tolower [HTTP::host]] equals test-dg ]
        } else {
             drop the request if the host header is not in test-dg
            drop
    }
    }
    
    • bigipjr28_13978's avatar
      bigipjr28_13978
      Icon for Nimbostratus rankNimbostratus
      Making sure I understand correctly as to what the code does. What its doing, upon a request checks the header comparing to the data group list where the pool(s) are going to refrerenced than goes to that pool..if anything else drop the connection
    • bigipjr28_13978's avatar
      bigipjr28_13978
      Icon for Nimbostratus rankNimbostratus
      Making sure I understand correctly as to what the code does. What its doing, upon a request checks the header comparing to the data group list where the pool(s) are going to refrerenced than goes to that pool..if anything else drop the connection
  • if I was going to use a list that would just match against host headers would I just use a class ? is that something I do in the irule itself or done in tmos ? confused when it comes to some of the examples

     

    Thanks

     

    • shaggy's avatar
      shaggy
      Icon for Nimbostratus rankNimbostratus
      it is configured separately from the iRule. in the configuration utility, navigate to Local Traffic | iRules | Data Group List
    • Michael_Jenkins's avatar
      Michael_Jenkins
      Icon for Cirrostratus rankCirrostratus
      You would create the data group from the CLI (per @shaggy example), or through the F5 management GUI. Then you would utilize the data group within an iRule. If you want easy to manage iRule and Data Group management, I'd highly recommend downloading the iRule Editor (https://devcentral.f5.com/s/articles/iRule-Editor-Download). It makes it so much easier.
  • irule is editor has helped alot I download it a a coulple of months ago..would awesome if there it came bundled with the devices so that all you have to do is just click a download link and than install it locally to your machine. Instead of going to the dev central directly.

     

    • StephanManthey's avatar
      StephanManthey
      Icon for MVP rankMVP
      That´s just a trick to get folks messing around on DC and to see all the great stuff ... ;)
    • bigipjr28_13978's avatar
      bigipjr28_13978
      Icon for Nimbostratus rankNimbostratus
      A concern of is, how would this function from gtm prospective if we use a global configuration for our vips? So our setup is basically. GTM -> LTM ->POOL MEMBERS (webserver1, webserver2). If we only have to pool members and using hostheaders for all the applications and we wanted to failover between sites 1 and site 2 and since we use global config mode to manipulate that, wouldn't that fail all the applications over ?
  • I have put in place the irule along with the custom health monitor for each application. We are testing out two applications and the two that applications that are using the monitor are working and directing traffic with and without the irule.

     

    Here is the setup:

     

    pool test1.pool nodes 10.1.1.1 10.1.1.2 monitor GET /f5-monitor/f5-monitor.jsp HTTP/1.1\r\nHost: test1.com\r\nConnection: Close\r\n\r\n

     

    pool test2.pool nodes 10.1.1.1 10.1.1.2 monitor GET /f5-monitor/f5-monitor.jsp HTTP/1.1\r\nHost: test2.com\r\nConnection: Close\r\n\r\n

     

    I am able to get to test1.com and test2 with and without the use of the irule or data groups. How's this happening since the nodes are using the same pair of apache servers that are serving up the host header information and properly being routed to each application?

     

    Thanks

     

  • I have put in place the irule along with the custom health monitor for each application. We are testing out two applications and the two that applications that are using the monitor are working and directing traffic with and without the irule.

     

    Here is the setup:

     

    pool test1.pool nodes 10.1.1.1 10.1.1.2 monitor GET /f5-monitor/f5-monitor.jsp HTTP/1.1\r\nHost: test1.com\r\nConnection: Close\r\n\r\n

     

    pool test2.pool nodes 10.1.1.1 10.1.1.2 monitor GET /f5-monitor/f5-monitor.jsp HTTP/1.1\r\nHost: test2.com\r\nConnection: Close\r\n\r\n

     

    I am able to get to test1.com and test2 with and without the use of the irule or data groups. How's this happening since the nodes are using the same pair of apache servers that are serving up the host header information and properly being routed to each application?

     

    Thanks