URL-based routing with NetScaler CPX

In a previous blog post, I showed how to use the NetScaler CPX to load balance a set of backend web servers. In this post, I’ll show how to use the CPX in a modern microservices-based architecture.

In a micro services environment, a service is split up into several co-operating micro services, each located at a different network endpoint. A different way to build the same service is to use a monolith pattern.

For example, imagine a WidgetShop service that has been built as a monolith

lb4

Although there are clearly identifiable services within the monolith, the entire service is always deployed and scaled together. So, even if the cart service didn’t need to be scaled up, it still gets deployed to every backend server. When the monolith is split into micro services, it might look like this:

lb5

Each microservice gets deployed in containers and can be deployed independently of the other microservices and also scaled independently. Depending on the networking, each Docker container could get a unique routable IP address, or get a unique TCP port on its host. To route the incoming traffic  properly, the load balancer has to look at the path component of the incoming URL. Based on the path, the load balancer “switches” or “routes” the traffic to different servers/microservices/containers. This is sometimes known as URL-based routing.

To achieve this in NetScaler CPX we have to use something called ‘content switching‘. Content Switching is very powerful — it can switch/route traffic based on the URL, HTTP headers, hostname, the payload itself and so on. To demonstrate URL-based routing, we’ll use Docker Compose again to layout the WidgetShop topology. To follow along, use the ‘ex2’ folder from this git repository https://github.com/chiradeep/cpxblog/

The Docker Compose file:

version: '2'
services:
  accounts_a:
    image: httpd:alpine
    volumes:
      - ${PWD}/:/usr/local/apache2/htdocs/
    expose:
      - 80
  accounts_b:
    image: httpd:alpine
    volumes:
      - ${PWD}/:/usr/local/apache2/htdocs/
    expose:
      - 80

  cart_a:
    image: httpd:alpine
    volumes:
      - ${PWD}/:/usr/local/apache2/htdocs/
    expose:
      - 80
  
  catalog_a:
    image: httpd:alpine
    volumes:
      - ${PWD}/:/usr/local/apache2/htdocs/
    expose:
      - 80
  catalog_b:
    image: httpd:alpine
    volumes:
      - ${PWD}/:/usr/local/apache2/htdocs/
    expose:
      - 80
  cpx:
    image: store/citrix/netscalercpx:11.1-53.11 
    ports:
      - 22
      - 88
    tty: true
    privileged: true

You can see that there’s 2 Accounts containers, 2 Catalog containers and 1 cart container, plus the CPX. Let’s run this and determine the IP addresses Docker assigns to these containers.

$ docker-compose up -d
$ names=$(docker-compose ps | awk -F" " '{print $1}' | tail -n+3)
$ for c in $names ; do    ip=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $c);   echo "$c : $ip"; done
ex2_accounts_a_1 : 172.21.0.6
ex2_accounts_b_1 : 172.21.0.5
ex2_cart_a_1 : 172.21.0.2
ex2_catalog_a_1 : 172.21.0.4
ex2_catalog_b_1 : 172.21.0.3
ex2_cpx_1 : 172.21.0.7

To configure content switching in the NetScaler we first have to enable it:

$ docker-compose port ex2_cpx_1 22
0.0.0.0:32862
$ ssh -p 32862 root@localhost
root@629e788ff846:~# cli_script.sh 'enable feature cs'
Done

In a NetScaler a content switching virtual server (“cs vserver”) becomes the front-end listener. This in turn sends traffic to LB vservers that represent the backend microservices. The microservices are grouped into Service Groups.

lb6

The rule that tells the cs vserver to send traffic to a particular lb vserver is called a policy (cs policy). The set of CLI commands looks like this:
First, configure the service groups with the backend IPs we have already discovered:

cli_script.sh 'add servicegroup accounts HTTP'
cli_script.sh 'add servicegroup cart HTTP'
cli_script.sh 'add servicegroup catalog HTTP'
cli_script.sh 'bind servicegroup accounts 172.21.0.6 80'
cli_script.sh 'bind servicegroup accounts 172.21.0.5 80'
cli_script.sh 'bind servicegroup cart 172.21.0.2 80'
cli_script.sh 'bind servicegroup catalog 172.21.0.3 80'
cli_script.sh 'bind servicegroup catalog 172.21.0.4 80'

Then create the lb vservers and bind the servicegroups to them:

cli_script.sh 'add lb vserver Accounts HTTP'
cli_script.sh 'add lb vserver Cart HTTP'
cli_script.sh 'add lb vserver Catalog HTTP'
cli_script.sh 'bind lb vserver Accounts accounts'
cli_script.sh 'bind lb vserver Cart cart'
cli_script.sh 'bind lb vserver Catalog catalog'

Create the WidgetShop cs vserver:

cli_script.sh 'add cs vserver WidgetShop HTTP 172.21.0.7 88'

Create the policies and bind them to the cs vserver:

cli_script.sh 'add cs policy accounts_policy -url "/accounts/*"'
cli_script.sh 'add cs policy cart_policy -url "/cart/*"'
cli_script.sh 'add cs policy catalog_policy -url "/catalog/*"'
cli_script.sh 'bind cs vserver WidgetShop -policyname accounts_policy -targetLBVServer Accounts'
cli_script.sh 'bind cs vserver WidgetShop -policyname cart_policy -targetLBVServer Cart'
cli_script.sh 'bind cs vserver WidgetShop -policyname catalog_policy -targetLBVServer Catalog'

Try it out:

$ docker-compose port ex2_cpx_1 88
0.0.0.0:32861
$ wget -q -O - http://localhost:32861/accounts/
$

This is the Accounts Service

In a subsequent blog post we’ll see how to automate this somewhat manual process.

Advertisements

2 thoughts on “URL-based routing with NetScaler CPX

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s