使用 ebextensions 动态设置每个环境的 EC2 实例类型
Posted
技术标签:
【中文标题】使用 ebextensions 动态设置每个环境的 EC2 实例类型【英文标题】:Dynamically set the EC2 Instance Type per Environment using ebextensions 【发布时间】:2020-09-14 17:18:44 【问题描述】:我想在所有环境中创建 EC2 实例类型 t3.medium
,在生产环境中创建 m5.large
。
我像这样使用.ebextensions
(YAML):
选项 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"]
选项 2:
InstanceType: "Fn::FindInMap": ["EnvironmentMap", "Ref": "AWSEBEnvironmentName", "EC2InstanceType"]
选项 3:
InstanceType:
- "Fn::FindInMap": ["EnvironmentMap", "Ref": "AWSEBEnvironmentName", "EC2InstanceType"]
结果
选项 1 因 Yaml 无效而失败(但我从这个 AWS example 获取了这个。
选项 2 和 3 因同样的问题而失败。
FindInMap 函数未被“调用”:
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, ....
它试图将整个函数/事物解释为一个字符串。
SecurityGroups
属性有效,InstanceType
无效。
我不能动态地做到这一点,我在 AWS doc、SO 或其他任何地方都找不到如何实现这一点。我会假设这是简单的东西。我错过了什么?
编辑:
选项 4:使用条件
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"]
错误:YAML exception: Invalid Yaml: could not determine a constructor for the tag !Equals in...
但这来自conditions 和if 的文档。
编辑 2:
我最终发现InstanceType
的选项是obsolute,我们应该使用:
aws:ec2:instances
InstanceTypes: "t3.medium"
但是很可惜,这也不能解决问题,因为我也不能在这里使用替换功能(Fn:findInMap
)。
【问题讨论】:
【参考方案1】:FindInMap
在option_settings
中不起作用的原因是,那里只允许四个内在函数(来自docs):
我不相信SecurityGroups
有效。我认为您的脚本在SecurityGroups
中的FindInMap
有机会被评估之前失败了。
但是,我试图找到一种方法使用Resources。我得到的关闭是使用以下config
文件:
Mappings:
EnvironmentMap:
production:
TheType: "t3.medium"
staging:
TheType: "t2.small"
Resources:
AWSEBAutoScalingLaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
InstanceType:
? "Fn::FindInMap"
:
- EnvironmentMap
-
Ref: "AWSEBEnvironmentName"
- TheType
虽然这更近了一步,但它最终还是失败了。原因是当 EB 将我们的 Resources
配置文件与它自己的模板连接时,它会产生以下内容:
"InstanceType":
"Ref": "InstanceType", # <--- this should NOT be here :-(
"Fn::FindInMap": [
"EnvironmentMap",
"Ref": "AWSEBEnvironmentName"
,
"TheType"
]
,
而不是
"InstanceType":
"Fn::FindInMap": [
"EnvironmentMap",
"Ref": "AWSEBEnvironmentName"
,
"TheType"
]
,
而出现这种情况是因为原来的InstanceType
(联合操作前)是:
"InstanceType":"Ref":"InstanceType",
因此,EB 不是用我们的配置文件中提供的自定义InstanceType
替换 InstanceType
,而是合并它们。
【讨论】:
感谢您的回答。我已经学到了一些东西。我认为这是一个基本操作。在 dev 上使用更小、更便宜的 EC2,在 prod 上使用更大更快的 EC2。这怎么这么难?那我们应该如何达到同样的效果呢? @Vetras 我目前没有答案。我也尝试使用Fn::GetOptionSetting,但没有运气。也许还有其他方法,更简单。我暂时不知道。对不起。 @Vetras 作为旁注,如果您使用 CloudFormation 来配置您的 EB 环境,您可以在那里轻松完成,而不是从.ebextensions
。
现在整个项目都是ebextensions,有点大。我计划很快将其克隆到 terraform 中。感谢您的帮助。以上是关于使用 ebextensions 动态设置每个环境的 EC2 实例类型的主要内容,如果未能解决你的问题,请参考以下文章
AWS Elastic Beanstalk:如何在 ebextensions 中使用环境变量?
从 .ebextensions 配置文件访问 Elastic Beanstalk 环境属性
使用配置文件 (.ebextensions) 在自定义 VPC 中为 TCP 直通配置 Elastic Beanstalk 环境的负载均衡器