Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically set the EC2 Instance Type per Environment using ebextensions

I want to create a EC2 instance type t3.medium on all environments and m5.large on production.

I'm using .ebextensions (YAML) like so:

option 1:

Mappings:
  EnvironmentMap:
    "production":
      TheType: "m5.large"
      SecurityGroup: "foo"
      ...
    "staging":
      TheType: "t3.medium"
      SecurityGroup: "bar"
      ...

option_settings:
  aws:autoscaling:launchconfiguration:
    IamInstanceProfile: "aws-elasticbeanstalk-ec2-role"
    InstanceType: !FindInMap
      - EnvironmentMap
      - !Ref 'AWSEBEnvironmentName'
      - TheType
    SecurityGroups:
      - {"Fn::FindInMap": ["EnvironmentMap", {"Ref": "AWSEBEnvironmentName"}, "SecurityGroup"]}

Option 2:

    InstanceType: {"Fn::FindInMap": ["EnvironmentMap", {"Ref": "AWSEBEnvironmentName"}, "EC2InstanceType"]}

Option 3:

    InstanceType:
      - {"Fn::FindInMap": ["EnvironmentMap", {"Ref": "AWSEBEnvironmentName"}, "EC2InstanceType"]}

Results

Option 1 fails with Invalid Yaml (but I took this from this AWS example.

Option 2 and 3 fail with the same problem. The FindInMap function is not "called": Invalid option value: '{"Fn::FindInMap":["EnvironmentMap","EC2InstanceType"]},{"Ref":"AWSEBEnvironmentName"}' (Namespace: 'aws:autoscaling:launchconfiguration', OptionName: 'InstanceType'): Value is not one of the allowed values: [c1.medium, c1.xlarge, c3.2xlarge, .... It tries to interpret the whole function/thing as a string.

For the SecurityGroups property it works, for InstanceType it does not.

I can't do it dynamically and I can't find how to achieve this neither on AWS doc, SO, or anywhere else. I would assume this is simple stuff. What am I missing?


EDIT:

Option 4: using conditionals

Conditions:
  IsProduction: !Equals [ !Ref AWSEBEnvironmentName, production ]

option_settings:

  aws:autoscaling:launchconfiguration:
    InstanceType: !If [ IsProduction, m5.large, t3.medium ]
    SecurityGroups:
      - {"Fn::FindInMap": ["EnvironmentMap", {"Ref": "AWSEBEnvironmentName"}, "SecurityGroup"]}

Error: YAML exception: Invalid Yaml: could not determine a constructor for the tag !Equals in...

But this comes from documentation on conditions and if.


EDIT 2:

I eventually found out that the option InstanceType is obsolute and we should use:

aws:ec2:instances
  InstanceTypes: "t3.medium"

But alas, this does not solve the problem either because I cannot use the replacement functions here as well (Fn:findInMap).

like image 543
Vetras Avatar asked Apr 14 '26 16:04

Vetras


1 Answers

The reason why FindInMap does not work in option_settings is the fact that only four intrinsic functions are allowed there (from docs):

  • Ref
  • Fn::GetAtt
  • Fn::Join
  • Fn::GetOptionSetting

I'm not convinced that SecurityGroups worked. I think your script failed before FindInMap in SecurityGroups got chance to be evaluated.

However, I tried to find a way using Resources. The closes I got was with the following config file:

Mappings:
  EnvironmentMap:
    production:
      TheType: "t3.medium"
    staging:
      TheType: "t2.small"

Resources:
  AWSEBAutoScalingLaunchConfiguration:
    Type: AWS::AutoScaling::LaunchConfiguration
    Properties:
      InstanceType:
        ? "Fn::FindInMap"
        :
          - EnvironmentMap
          - 
            Ref: "AWSEBEnvironmentName"
          - TheType

Although this is a step closer, it ultimately fails as well. The reason is that when EB is jointing our Resources config file with its own template, it produces the following:

"InstanceType": {
  "Ref": "InstanceType", # <--- this should NOT be here :-(
  "Fn::FindInMap": [
    "EnvironmentMap",
    {
      "Ref": "AWSEBEnvironmentName"
    },
    "TheType"
  ]
},

instead of

"InstanceType": {
  "Fn::FindInMap": [
    "EnvironmentMap",
    {
      "Ref": "AWSEBEnvironmentName"
    },
    "TheType"
  ]
},

And this happens because the original InstanceType (before the joint operation) is:

"InstanceType":{"Ref":"InstanceType"},

Therefore, EB instead of replacing InstanceType with our custom InstanceType provided in our config file, it just merges them.

like image 179
Marcin Avatar answered Apr 16 '26 04:04

Marcin