Deploying Brocade Virtual Traffic Manager cluster in AWS through a CloudFormation template

Last time we’ve talked about the concept of Infrastructure as Code (IaC), and introduced two most prominent tools in the space, AWS CloudFormation and Hashicorp Terraform.

In this post, we’ll have a look at an AWS CloudFormation template that you can use to deploy a cluster of 2 x Brocade Virtual Traffic Managers with WAF into a new AWS VPC; what makes up that template; and how it all works.

We will take things quite slowly here. Some basic understanding of automation and/or scripting/programming will help, but not strictly necessary.

If on other hand you’re already well-versed in AWS CloudFormation but still interested in automating deployment of Brocade Virtual Traffic Managers in AWS, feel free to jump straight to the GitHub repo, and optionally read the vADC EC2 Instances section below.

Please note that this is work in progress and the code you’ll find there has no official support at this time, but rest assured, it is coming! 🙂

This post assumes that you have a general idea of what Brocade Virtual Traffic Manager and Virtual WAF are and what you need them for, so I won’t be spending time covering this here.

I’ll use the term “vADC” throughout this post (and in the template), because we’ll be dealing with one virtual appliance that includes both Traffic Manager and WAF, hence – “ADC”. 🙂

Some background

Virtual network function appliances, such as Traffic Managers and Web Application Firewalls (WAF), don’t stand alone by themselves. They need to be connected to the network where they can be accessed by users, and in turn access the backend servers.

The template we’ll be looking at will build an operational environment for a cluster of vADCs to run in, and then deploy the vADCs themselves into that environment. We will cover:

  • network connectivity with geographic redundancy;
  • network security;
  • role-based access controls;
  • basic appliance auto-healing; and
  • vADC clustering set-up.

But, first things first.

Anatomy of a CloudFormation template (CFT)

AWS CloudFormation Documentation covers all aspects of CFT in great detail, but let’s recap the most important points.

A CFT is a JSON-formatted text file that defines an infrastructure “stack”. The same CFT can be used to create as many instances of the stack as necessary.

A CFT that will build an infrastructure stack for us will need to do the following things:

  1. Define some input parameters that let user customise the individual instance of infrastructure stack that the template will deploy. This is achieved by the Parameters section of a template.
  2. Describe the AWS infrastructure resources that will form our stack, such as networks, compute instances, and so on. This is achieved by the Resources section of a template.
  3. Return some values to the user, which can be later queried from the newly created infrastructure stack. These could be things like automatically allocated DNS names of resources, public and private IP addresses, etc. This is done by the Outputs section of a template.

Additionally, your template logic may need to look variables up against user-selected values in maps, which is what the Mappings section is for.

If your template is designed to support multiple variations of an infrastructure stack, it will need an ability to deal with conditions, which is where the Conditions section comes into play.

Last but not least, interface key in Metadata section can control labels and layout of the input Parameters in the CloudFormation UI, when it is used to deploy a template interactively.

Now that we’ve got some idea of what goes into a template, let’s take a closer look at our real life example. We’ll be using a template I created that builds a redundant cluster of 2 x Brocade vADC appliances that can frontend your application servers whether they are in AWS, other public cloud, or on your premises.

We’ll talk more about use cases in later posts; but for now – let’s dig in.

You may want to open the following link to the complete template in a separate window to help you follow along: https://github.com/dkalintsev/Brocade/blob/master/vADC/CloudFormation/Templates/vADC-Deploy-cfn-init.template

What’s in our vADC stack?

Even though our template only creates a working cluster made of two vADCs and not a complete application, there’s still a fair amount of moving bits that need to be put in place. These bits are:

  1. AWS Virtual Private Cloud (VPC). By default, it’s not of much use; we’ll also need the following bits related to it:
    1. An Internet Gateway (IGW) to provide Internet access to our VPC;
    2. A handful of Subnets, where we can attach our vADC instances and at a later stage our application components (not covered in this template or blog). We want our subnets to provide geographical redundancy, so we’ll have them split across two Availability Zones.
    3. Routing table for our Internet-facing “public” Subnets
    4. Default route through the IGW for our Routing table
    5. Security Groups (firewall rules) that will govern what traffic is allowed to enter our vADC EC2 instances
    6. Public IP addresses for the vADC instances
  2. Elastic Network Interfaces for our vADC instances to go along with those public IPs
  3. AWS Identity and Access Management (IAM) Role for our vADC instances that will allow them to perform their necessary EC2-related functions
  4. vADC EC2 instances themselves
  5. AWS CloudWatch Recovery Alarms for the vADC instances that will automatically recover these instances in case of underlying AWS infrastructure failure
  6. CloudFormation WaitHandler, to allow the first member of vADC to come up and fully form the cluster before the second vADC instance is started.

Once this all is in place, our stack will look something like this:

vADC Stack Diagram; click to enlarge
vADC Stack Diagram; click to enlarge

This diagram was created using AWS CloudFormation Designer that doesn’t deal with labels (or layout, to be fair) all that well, but hopefully you can make some sense out of it.

Template walk-through

Ok, now let’s walk through our template, and figure out what is happening under the hood when we create an infrastructure stack instance from it.

If you’re already reasonably familiar with CloudFormation and prefer to get straight to the vADC-specific bits, please feel free to jump directly to the vADC EC2 Instances section below.

Metadata

First off, we have the Metadata section, where AWS::CloudFormation::Interface key helps us with grouping and formatting the user inputs, when the template is deployed through the AWS Console UI:

Console UI rendering input parameters; click to enlarge
Console UI rendering input parameters; click to enlarge

You can see the sections defined in ParameterGroups encompassing groups of input parameters and displaying friendly ParameterLabels instead of internal parameter variable names, for example New VPC CIDR Block: is shown instead of VPCCIDR.

Parameters

Next, we have the Parameters section, where we describe the parameters that need user input, and set any defaults. If this template is called from within another template, you will need to pass the values for these parameters from there.

Each Parameter is declared as a Logical Name with a number of properties, for example, InstanceType with the properties being Description, Type, Default, AllowedValues, and ConstraintDescription:

"InstanceType": {
  "Description": "Please select a vADC EC2 instance type",
  "Type": "String",
  "Default": "m4.large",
  "AllowedValues": [
    "t2.small",
    "t2.medium",
...
    "r3.8xlarge"
  ],
  "ConstraintDescription": "Must be an allowed EC2 instance type."
},

In addition to the obvious String, Number, and CommaDelimitedList, there are AWS-specific Types that are dynamically populated based on the current state of your AWS infrastructure. In our template, we use two such types: AWS::EC2::KeyPair::KeyName and List<AWS::EC2::AvailabilityZone::Name>.

When deployed through the AWS Console UI, the first one shows a drop-down where user can select a pre-existing KeyPair name, while the second will show all Availability Zones where you can create VPC subnets:

AZ Selection dialog; click to enlarge
AZ Selection dialog; click to enlarge

The AllowedPattern property takes a Java regex with double-escaped backslashes, e.g., to use a \ in your regex, you’ll need to include two of them – \\. This property is used to validate the input just before the template is executed. If validation doesn’t pass, a message defined in the ConstraintDescription property is displayed.

If you’re using AWS Console UI, validation only happens once you click the “Create” at the very last deployment step. The first page that collects user inputs will happily take an invalid input, just to throw up an error message in the end:

Parameter validation error in AWS Console UI
Parameter validation error in AWS Console UI

Mappings

In the next section, we describe Maps we will later use to look up values based on keys. In our template we have two maps, the AWSRegions being included for purely cosmetic reasons. 🙂

The vADCAMI one is quite important though, as it allows us to find the correct AMI for a given vADC version in our selected region.

In our template, lookup keys are version numbers for vADC appliance, with dots removed. I realise that this notation doesn’t look good and may even be confusing, but unfortunately CloudFormation doesn’t allow anything other than letters and numbers in keys, so I kind of didn’t have a choice. 😦

At this point keen reader might say “Hold on a sec, does this mean I need to keep track of the AMI IDs as things change, such as new regions and appliance versions?”, and would be absolutely right. At the time of writing, CloudFormation doesn’t have built-in functionality for looking up AMI IDs at the run time. (Yes, you could use a Lambda function to go around this, but IMO this solution is not pretty or particularly user-friendly). Fret not, we have you covered (to a point). 🙂 Please see the Tools page, where there is a shell script that can build a Mappings section for you by querying what’s published on AWS at the time that you can then directly paste into the template.

Conditions

This template doesn’t have any Conditions, but if you’re curious to see an example, please feel free to poke around my Brocade vRouter deployment template that does have some.

Resources

This is the section where the main magic happens.

Since CF template describes the desired state of the stack you’re building, the order in which you list your resources in the template does not matter. In most cases, CloudFormation is able to figure out dependencies between resources and schedule create / modify / delete operations accordingly; but if you’d like to spell them out explicitly or when AWS explicitly advises you to do so, you can by using the DependsOn property pointing to another Resource that has to exist before the creation of your dependant Resource will start.

VPC

Our template is designed to create a new VPC, instead of using an existing one. The first Resource called VPC does that. The key property for this resource is CidrBlock, which tells the new VPC which IP CIDR block (supernet) to use. In our case, we using the Ref function to obtain the value for that property from the Parameter called VPCCIDR:

"VPC": {
  "Type": "AWS::EC2::VPC",
  "Properties": {
    "CidrBlock": {
      "Ref": "VPCCIDR"
    },
...

Next, we create a Name Tag for this VPC, which will show up in the “Name” column in AWS Console UI when we look at the VPCs we have. We build the name from the name you’ve given to your stack when starting the deployment, and the word VPC:

"Tags": [
  { "Key": "Name",
    "Value": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "VPC" ] ] }
  }

Assuming you’ve called your stack instance “MyStack”, the code above will set the Name for our VPC to MyStack-VPC.

Subnets

To utilise network connectivity provided by VPC, one has to create Subnets. Each subnet has three main “anchors”: VpcId, CidrBlock, and AvailabilityZone:

"PublicSubnet1": {
  "Type": "AWS::EC2::Subnet",
  "Properties": {
    "VpcId": {
      "Ref": "VPC"
    },
    "CidrBlock": {
      "Ref": "PublicSubnetCIDR1"
    },
...
    "AvailabilityZone": {
      "Fn::Select": [ "0", { "Ref": "AZs" } ]
    }
  }
},

Here we’re Ref’ing the resource VPC and parameter PublicSubnetCIDR1, and grabbing the first element in the array parameter AZs, that you’ve populated from an available AZs drop-down when specifying the input parameters for your stack instance.

In themselves, all subnets are created equal – they are not “public” nor “private”. These names are nominal, and really only signify the intent. “Public” subnets are the ones associated with Routing Tables that have default route that leads to the Internet, usually through an Internet Gateway, while private ones don’t.

The Internet Gateway

Next up, we create an Internet Gateway resource, or “IGW”, and then associate it with our VPC. It is done through the Resources AWS::EC2::InternetGateway and AWS::EC2::VPCGatewayAttachment, which is a very straight-forward operation that instantiates an IGW and makes it available as a destination in routing tables of the VPC in question.

Routes and Routing Tables

By default, all subnets are associated with the default routing table, so if we want to make some subnets “public” while leaving others “private”, we’ll need to:

  • Create a new routing table;
  • Populate it with the appropriate route(s); and
  • Associate the subnets that need these routes with this routing table.

This is what the next four resources do through AWS::EC2::RouteTable, AWS::EC2::Route, and AWS::EC2::SubnetRouteTableAssociation, accordingly:

"PublicSubnetRouteTable": {
  "DependsOn": "AttachGateway",
  "Type": "AWS::EC2::RouteTable",
  "Properties": {
    "VpcId": {
      "Ref": "VPC"
    },
  }
...
},

"PublicRoute1": {
  "Type": "AWS::EC2::Route",
  "DependsOn": "AttachGateway",
   "Properties": {
    "RouteTableId": {
      "Ref": "PublicSubnetRouteTable"
    },
    "DestinationCidrBlock": "0.0.0.0/0",
    "GatewayId": {
      "Ref": "InternetGateway"
    }
  }
},

"PublicSubnet1RouteTableAssociation": {
  "Type": "AWS::EC2::SubnetRouteTableAssociation",
  "Properties": {
    "SubnetId": {
      "Ref": "PublicSubnet1"
    },
    "RouteTableId": {
      "Ref": "PublicSubnetRouteTable"
    }
  }
},

"PublicSubnet2RouteTableAssociation": {
...

The code above creates a routing table PublicSubnetRouteTable, a default (0.0.0.0/0) route PublicRoute1, and finally associates the two together.

By default, routing tables are created with one route for to the VpcCidr subnet and next hop of Local, meaning EC2 instances using this routing table will be able to send packets to instances in all subnets of the same VPC, subject to Security Group configuration.

SecurityGroups (interface-attached firewall)

By default, EC2 instances are associated with the VPC’s default Security Group, which is probably not quite what we want. Dealing with this is, again, a multi-step process:

  • Create a SecurityGroup resource; and
  • Attach one or more SecurityGroups to network interface resources we’ll be using with our instances.

For our template, we create vADCSecurityGroup resource of type AWS::EC2::SecurityGroup, populating its SecurityGroupIngress property with the appropriate ingress firewall rules as per Chapter 4 of the Virtual Traffic Manager Cloud Services Installation and Getting Started Guide.

The SSH rule deserves some more attention, since the source IP for this rule is the Ref’ed from the RemoteAccessCIDR parameter that user can specify at the deploy time, setting it to their own IP or subnet to limit who can connect to the newly built vTM appliances.

Unless we need to control what outbound connections are allowed, we can leave SecurityGroupEgress as default, which is to permit all.

For more info on AWS Security Groups, please refer to the AWS VPC Security Groups documentation.

Network interfaces and all that goes with them

Our two vADC EC2 instances will need to be connected to their respective Subnets, and the way to do it is through their Network Interfaces.

There are a few ways of dealing with it. One is to create Elastic Network Interface resource and then associate it with an EC2 instance. Another is to define Network Interface parameters directly within the EC2 resource definition.

There is no right or wrong way; both have their pros and cons. This template uses the first way, so let’s have a look at what’s involved.

First, we allocate us some public IP addresses using AWS::EC2::EIP resource type for vADC1EIP and vADC2EIP. “EIP” here stands for “Elastic IP”, meaning it can be flexibly associated with different Elastic Network Interface, or “ENI”.

Then, we create our ENIs vADC1Interface1 and vADC2nterface1 and associate them with the appropriate Subnets and our Security Group:

"vADC1Interface1": {
  "Type": "AWS::EC2::NetworkInterface",
  "Properties": {
    "SubnetId": {
      "Ref": "PublicSubnet1"
    },
    "Description": "External interface for the vADC 1",
    "GroupSet": [
      {
        "Ref": "vADCSecurityGroup"
      }
    ],
    "SourceDestCheck": "false",
...
  }
},

The SourceDestCheck is set to false to enable support for L4 load balancing.

The SubnetId property of an ENI will determine that ENI’s private IP address.

Finally, we associate the EIPs we allocated earlier with our ENIs:

"AssociatevADC1Interface": {
  "Type": "AWS::EC2::EIPAssociation",
  "Properties": {
    "AllocationId": {
      "Fn::GetAtt": [
        "vADC1EIP",
        "AllocationId"
      ]
    },
    "NetworkInterfaceId": {
      "Ref": "vADC1Interface1"
    }
  }
},
...

IAM

Virtual Traffic Manager requires a range of permissions to perform a number of EC2-related functions, such as (quoting “Using IAM Roles” section from Chapter 4 of the guide we linked to above):

During normal communication with EC2, the Traffic Manager executes a range of API calls to perform various functions. When you create an IAM role, you must assign the correct level of authority to the role to execute these calls.

For general Traffic Manager functioning:

  • DescribeRegions
  • DescribeInstances
  • DescribeAddresses
  • DescribeNetworkInterfaces

For Fault Tolerance:

  • AssociateAddress
  • DisassociateAddress
  • AllocateAddress
  • ReleaseAddress
  • AssignPrivateIPAddresses
  • UnAssignPrivateIpAddresses

For Autoscaling:

  • RunInstances
  • CreateTags
  • TerminateInstances

To implement this, we first create an IAM Role resource called vADCIAMRole with the trust policy set to vADCIAMPolicy with the permissions shown above. Then, we create an IAM Instance Profile resource vADCInstanceIAMProfile associated with this Role. We will associate our vADC EC2 instances with this Instance Profile to give them permissions to do the necessary operations.

You may notice that the Policy’s “Resource” property is set to “*", meaning vADCs will have these permissions over all EC2 instances in your account. This is because the particular EC2 actions that vADC needs do not support resource-level permissions. Yeah.

Ok, the next part is probably the most interesting one. 🙂

vADC EC2 instances

There are two stages of deploying vADC appliances in AWS:

  • Infrastructure build and configuration; and
  • Application-specific configuration.

I’m working on several options for the app-specific configuration management stage, and will make it available once ready. In meanwhile, this template deals with the first stage, so let’s have a look at that.

Since our two vADC instances need to work together as a cluster, simply deploying them as individual instances isn’t going to work. Instead, we’ll need to deal with the following three things:

  1. First, we need a way to tell CloudFormation to hold off deployment of the vADC2 until we know that vADC1 has come up and had a chance to form a cluster. If we don’t do that, vADC2 will not be able to join the cluster since it isn’t ready yet.
  2. Second, we need to tell vADC2 what cluster to join by telling it the private IP address of vADC1, along with the right password.
  3. Last but not least, since we’re using Developer Edition of vADC AMIs, we’ll need to tell both vADCs that we’re OK with them running in the Developer Mode. If we don’t do that, you will need to connect to each vADC’s UI after the deployment, and click a button to accept that to bring them online.

Let’s deal with these one by one.

For the first one, we could try and specify vADC1 as DependsOn for vADC2, but this will only delay deployment of vADC2 until CloudFormation thinks it’s finished deploying vADC1, which didn’t really work for me. So instead we’ll use a Wait Condition that vADC1 will signal to when it’s ready, and set DependsOn for vADC2 to that Wait Condition:

"WaitHandle01": {
    "Type": "AWS::CloudFormation::WaitConditionHandle",
    "Properties": {}
},

"WaitCondition01": {
    "Type": "AWS::CloudFormation::WaitCondition",
    "DependsOn": "vADC1",
    "Properties": {
        "Handle": {
            "Ref": "WaitHandle01"
        },
        "Timeout": "600"
    }
},

"vADC2": {
  "Type": "AWS::EC2::Instance",
  "DependsOn": "WaitCondition01",
...

This will create the resource WaitCondition01 that will wait for 600 seconds to hear a signal directed at WaitHandle01. If the signal doesn’t arrive within the timeout period, stack creation will be declared “failed”, and CloudFormation will roll everything back, deleting all it created up to now.

Next we need some means of sending a signal from within vADC1 to our WaitCondition once we’re all good to go, which requires running some commands during the deployment of vADC1. For that, we’ll use a combination of two bootstrapping methods available in AWS: cloud-init and cfn-init.

vADC’s cloud-init support is restricted. Instead of any arbitrary shell commands, it only allows you to pass a strictly-defined set of variables in the parameter=value format, separated by spaces. Valid parameters are listed in the “Preconfiguring the Traffic Manager at Launch Time” section of the Chapter 4 in Virtual Traffic Manager Cloud Services Installation and Getting Started Guide. In this template, we are using password and accept_license for both vADC instances, plus cluster_host, cluster_fingerprint, and join_tips for the second. To run additional actual shell commands during deploy time, we’ll add cfn_stack, cfn_resource, and cfn_region to the above, which will cause vADC to call cfn-init with a configSet of default. This is how we’re going to get our signal out.

The instructions for cfn-init are passed in the Metadata property of an AWS::EC2::Instance resource. vADC will only execute “default” configSet, so that’s what we’re using:

"vADC1": {
  "Type": "AWS::EC2::Instance",
  "Metadata" : {
    "AWS::CloudFormation::Init" : {
      "configSets" : {
        "default" : [ "CreateFiles", "RunCommands" ]
      },

Then, we define two sections – CreateFiles and RunCommands.

The CreateFiles is currently a dummy section included for future support of application-specific configuration. cfn-init supports creation or downloading of text files and substitution of moustache-formatted parameters inside those files, which is what this bit demonstrates. It doesn’t do anything useful at this time beyond providing an example.

      "CreateFiles" : {
        "files" : {
          "/tmp/test.txt" : {
            "content" : "Content for {{name}}",
            "context" : { "name" : "test" }
...

This code will create a file /tmp/test.txt with content set to Content for test. For more on what you can do with files, see AWS::CloudFormation::Init docs.

The RunCommands section defines two commands we need to execute on vADC1 when it’s being deployed.

The first one adds a line to vADC’s global config telling it that the Developer Mode has been accepted, preventing the need to click that option in the UI.

The second command pauses for 3 minutes to give vADC services a chance to complete cluster preparation, and then executes cfn-signal command to send a notification to our WaitHandle01, telling it that we’ve completed the deployment and it’s ok to proceed:

      "RunCommands" : {
        "commands" : {
          "01-dev_mode_accept" : {
            "command" : "echo \"developer_mode_accepted     yes\" >> /opt/zeus/zxtm/global.cfg"
          },
          "99-wait_3_mins_then_signal_that_we_are_done" : {
            "command" : { "Fn::Join" : ["", [
              "sleep 180 && /usr/local/bin/cfn-signal -s true '",
              { "Ref" : "WaitHandle01" },
              "'"
            ]]}
...

Further down in the vADC1’s properties we have the UserData section that includes the cloud-init parameters we’ve talked about above:

...
    "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
      "password=",
        { "Ref" : "AdminPass" },
      " accept_license=y",
      " cfn_stack=",
        { "Ref" : "AWS::StackName" },
      " cfn_resource=",
        "vADC1",
      " cfn_region=",
        { "Ref" : "AWS::Region" }
    ]]}},
...

At this point, we’ll have out vADC1 instance running, having formed a new cluster, and ready for vADC2 to join it. In vADC2 resource, we include the following couple bits:

  • The DependsOn for the WaitCondition01 to wait for vADC1; and
  • 02-replicate_updated_config command that we need to execute after updating vADC2’s global config with developer_mode_accepted. This is to synchronise the locally-made config change to the rest of the cluster (vADC1 in this case).
"vADC2": {
  "Type": "AWS::EC2::Instance",
  "DependsOn": "WaitCondition01",
  "Metadata" : {
    "AWS::CloudFormation::Init" : {
      "configSets" : {
        "default" : [ "RunCommands" ]
      },
      "RunCommands" : {
        "commands" : {
...
          "01-dev_mode_accept" : {
            "command" : "echo \"developer_mode_accepted     yes\" >> /opt/zeus/zxtm/global.cfg"
          },
          "02-replicate_updated_config" : {
            "command" : "sleep 30 && /opt/zeus/zxtm/bin/replicate-config"
          }
...

Lastly, we populate vADC2’s UserData with the parameters that tell it where to find the vADC1’s cluster to join, and instructing it to run its own cfn-init section:

"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
  "accept_license=y",
  " password=",
    { "Ref" : "AdminPass" },
  " cluster_host=",
    { "Fn::GetAtt" : [ "vADC1Interface1", "PrimaryPrivateIpAddress" ] },
  " cluster_fingerprint=unsafe",
  " join_tips=y",
  " cfn_stack=",
    { "Ref" : "AWS::StackName" },
  " cfn_resource=",
    "vADC2",
  " cfn_region=",
    { "Ref" : "AWS::Region" }
]]}},

Recovery Alarms

Since we’re deploying our vADC EC2 instances as AWS::EC2::Instance resources as opposed to using AutoScale Groups, we need to take care of their wellbeing. By default, if an EC2 instance becomes unhealthy, no action is taken by AWS to return it to a running state.

In general there are a couple broad categories for where things could go wrong for an instance: (1) underlying AWS infrastructure, and (2) things inside the instance itself (OS or application).

For the purpose of this template, we’re creating an AWS::CloudWatch::Alarm for both of our vADC instances that will watch over EC2 status checks, and attempt to recover if those checks fail for 15 minutes. These checks are for the underlying AWS infrastructure, such as hypervisor and networking, and will not detect vADC software or OS failures. There is clearly more room for further improvement; it is on the plans. 🙂

Which brings us to the very end of our template:

Outputs

The purpose of the Outputs section is to return some of the values dynamically created during instantiation of the stack. These can be seen in the AWS CloudFormation UI, or queried by the AWS CLI.

In cases where one CloudFormation template is called from within another one, Outputs can be used to pass the values from the called template to the calling one.

Conclusion

That’s it for now, folks! Thank you for staying with us through this somewhat long-ish post. Hopefully this was useful, and as usual – please do feel free to ask in comments if I missed something or got too tongue-tied explaining! 🙂

And as you know, the best way to learn is to try, so head to this template’s page on GitHub, scroll to “How to Use” part, and use the one-click deploy button to take it for a spin!

Advertisements

About Dmitri Kalintsev

Some dude with a blog and opinions ;) View all posts by Dmitri Kalintsev

4 responses to “Deploying Brocade Virtual Traffic Manager cluster in AWS through a CloudFormation template

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

%d bloggers like this: