No Limit?

04/06/2016
Posted in AWS Blog
04/06/2016 Tom De Blende
[A:] No no limits, we’ll reach for the sky!
No valley to deep, no mountain too high
No no limits, won’t give up the fight
We do what we want and we do it with pride
No no, no no no no, no no no no, no no there’s no limit!
No no, no no no no, no no no no, no no there’s no limit!

No limit? Well, actually there is. Several actually. And that became painfully clear yesterday, when I was scripting the new environment for one of our customers. Not using Troposphere, so it can more easily be managed by non-Python savvy people.

What they need is not that special. They want to be able to deploy identical environments fast and easy. Not very complex environments either. Mainly EC2 and RDS. Say 10 servers and 5 DB instances.

But you know how it goes. All servers in an environment have different disk layouts. Different instance types. Different availability zones. And while the requirement now is to deploy completely identical environments, you know the day will come someone will come up to you and ask: why are we using SSD disks in our Dev environment? Why are those partitions so large in Test? So it’s best to be prepared, and allow for some flexibility. The plan was to create a CloudFormation script, and deploy it using Ansible. All configurable parameters can then be put in Ansible in an easy Yaml structure instead of -for example- a JSON parameter file.

So I started writing the code to create one server and its backend RDS instance, thinking: if I get this straightened out, it’s just a matter of copy pasting it for most other servers and instances, and setting server specific parameter values in Ansible. Well, pretty soon I hit the first AWS limit: one can only have 60 parameters for a CloudFormation template. I had many more. Bummer. I first looked into nested Stacks to overcome this limit, but as you can’t pass parameters straight to a child stack, they were not the answer here. They are an answer to a different problem though, but more on that later.

The best way to work around parameter limits, are mappings. It’s not ideal though, as my goal was to only configure new environments by creating a new playbook in Ansible and never having to touch the template code for this. Unfortunately, that is not an option. I now create a mapping per environment, and configure most variables there. The environment to deploy is passed as a parameter, which can then be used to search through the mapping and values are read using the Fn::FindInMap function. Pretty much as show below:
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "Deploy new AWS environment",
  "Parameters": {
    "Env": {
      "Type":           "String",
      "Description":    "AWS Environment",
      "AllowedValues":  ["dev","uat"]
    }
  },
  "Mappings": {
    "Envs": {
      "dev": {
        "SubnetPrivate1a": "subnet-1234xxxx",
        "SubnetPrivate1b": "subnet-1234yyyy"
      },
      "uat": {
        "SubnetPrivate1a": "subnet-4321xxxx",
        "SubnetPrivate1b": "subnet-4321yyyy"
      }
    }
  },
  "Resources" : {
    "DBSubnets": {
      "Type": "AWS::RDS::DBSubnetGroup",
      "Properties": {
        "DBSubnetGroupDescription": "Database Subnet group",
        "SubnetIds": [
          {
            "Fn::FindInMap": [
              "Envs",
              {
                "Ref": "Env"
              },
              "SubnetPrivate1a"
            ]
          },
          {
            "Fn::FindInMap": [
              "Envs",
              {
                "Ref": "Env"
              },
              "SubnetPrivate1b"
            ]
          }
        ]
      }
    },
...

So yeah, I was pretty pleased with the result. I was able to rewrite my code and transfer a lot of parameters to mappings. A new environment would now mean creating a new entry in the map. Not that big a deal. And hey, one can have a hundred mappings per template. We will never have that many environments. We are golden! Well… until I started to copy and paste all mapping entries… There I hit the second limit. One can only have a maximum of 63 mapping attributes. OK, that is 33 more than what is stated in the official documentation, but with the variables I wanted and the amount of servers, that was not nearly enough.

Now what? Well, back to the Nested Stacks. While they are not an answer to the parameter limit, they are to the mapping attributes boundary. When I create a child template for each type of server with its RDS instance, I don’t need that many mapping attributes per template, and all is well again. You can also pass parameters from parent to child, like this:
  "Resources" : {
    "Server1": {
      "Type": "AWS::CloudFormation::Stack",
      "Properties": {
        "TemplateURL": "https://s3.eu-central-1.amazonaws.com/xxx/xxx.json.template",
        "TimeoutInMinutes": "60",
        "Parameters": {
          "CEnv": {
            "Ref": "Env"
          },
And in the child stack you declare the parameter again and pick it up with a Ref:
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Deploy Server1",
  "Parameters": {
    "CEnv": {
      "Type":           "String",
    },
{"Fn::FindInMap": ["Envs", { "Ref":"CEnv"}, "KeyToLookFor"]},
Granted, at first sight it adds more complexity to the code. On the other hand it makes it more modular, and we probably are now safe from some other limits like the amount of resources per template, the maximum size of your template file or the total amount of swirly brackets you can have in one template. Actually I made that last one up, but for a complete list you can check the documentation at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html.
  • SHARE

Leave a Reply

Your email address will not be published. Required fields are marked *

LET'S WORK
TOGETHER

Need a hand? Or a high five?
Feel free to visit our offices and come say hi
… or just drop us a message

We are ready when you are

Cloudar NV – BE

Veldkant 7
2550 Kontich (Antwerp)
Belgium

info @ cloudar.be

+32 3 450 67 18

VAT BE0564 763 890

Cloudar BV – NL

Van Deventerlaan 31-51
3528 AG Utrecht
The Netherlands

info @ cloudar.nl

+32 3 450 67 18

VAT NL864471099B01

    This contact form is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

    contact
    • SHARE