我有一个包含应用程序负载均衡器 ListenerRule 的 CloudFormation 模板。 ListenerRule 的必需属性之一是其优先级(1 到 50000 之间的数字)。每个 ListenerRule 的优先级必须是唯一的。
我需要多次部署相同的模板。每次启动模板时,ListenerRule 的优先级都应该更改。
目前,我已将优先级变成了启动堆栈时可以设置的参数,效果很好。有没有办法自动将 ListenerRule 的优先级设置为下一个可用优先级?
不,目前无法仅使用
AWS::ElasticLoadBalancingV2::ListenerRule
资源自动分配它。但是,可以使用自定义资源来实现。
首先让我们创建实际的自定义资源 Lambda 代码。
allocate_alb_rule_priority.py:
import json
import os
import random
import uuid
import boto3
import urllib3
SUCCESS = "SUCCESS"
FAILED = "FAILED"
# Member must have value less than or equal to 50000
ALB_RULE_PRIORITY_RANGE = 1, 50000
def lambda_handler(event, context):
try:
_lambda_handler(event, context)
except Exception as e:
# Must raise, otherwise the Lambda will be marked as successful, and the exception
# will not be logged to CloudWatch logs.
# Always send a response otherwise custom resource creation/update/deletion will be stuck
send(
event,
context,
response_status=FAILED if event['RequestType'] != 'Delete' else SUCCESS,
# Do not fail on delete to avoid rollback failure
response_data=None,
physical_resource_id=uuid.uuid4(),
reason=e,
)
raise
def _lambda_handler(event, context):
print(json.dumps(event))
physical_resource_id = event.get('PhysicalResourceId', str(uuid.uuid4()))
response_data = {}
if event['RequestType'] == 'Create':
elbv2_client = boto3.client('elbv2')
result = elbv2_client.describe_rules(ListenerArn=os.environ['ListenerArn'])
in_use = list(filter(lambda s: s.isdecimal(), [r['Priority'] for r in result['Rules']]))
priority = None
while not priority or priority in in_use:
priority = str(random.randint(*ALB_RULE_PRIORITY_RANGE))
response_data = {
'Priority': priority
}
send(event, context, SUCCESS, response_data, physical_resource_id)
def send(event, context, response_status, response_data, physical_resource_id, reason=None):
response_url = event['ResponseURL']
http = urllib3.PoolManager()
body = {
'Status': response_status,
'Reason': reason or 'See the details in CloudWatch Log Stream: ' + context.log_stream_name,
'PhysicalResourceId': physical_resource_id,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': response_data,
}
encoded_body = json.dumps(body).encode('utf-8')
headers = {
'content-type': '',
'content-length': str(len(encoded_body)),
}
http.request('PUT', response_url, body=encoded_body, headers=headers)
根据您的问题,您需要使用相同的模板创建多个堆栈。因此,我建议将自定义资源放置在仅部署一次的模板中。然后让另一个模板导入其
ServiceToken
。
allocate_alb_rule_priority_custom_resouce.yml
:
Resources:
AllocateAlbRulePriorityCustomResourceLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
- PolicyName: DescribeRulesPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- elasticloadbalancing:DescribeRules
Resource: "*"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
AllocateAlbRulePriorityCustomResourceLambdaFunction:
Type: AWS::Lambda::Function
Properties:
Handler: allocate_alb_rule_priority.lambda_handler
Role: !GetAtt AllocateAlbRulePriorityCustomResourceLambdaRole.Arn
Code: allocate_alb_rule_priority.py
Runtime: python3.8
Timeout: '30'
Environment:
Variables:
ListenerArn: !Ref LoadBalancerListener
Outputs:
AllocateAlbRulePriorityCustomResourceLambdaArn:
Value: !GetAtt AllocateAlbRulePriorityCustomResourceLambdaFunction.Arn
Export:
Name: AllocateAlbRulePriorityCustomResourceLambdaArn
您可以注意到我们将 ListenerArn 传递给 Lambda 函数。这是因为我们想避免新分配时的优先级编号冲突。
最后,我们现在可以在要多次部署的模板中使用新的自定义资源。
template_meant_to_be_deployed_multiple_times.yml
:
AllocateAlbRulePriorityCustomResource:
Type: Custom::AllocateAlbRulePriority
Condition: AutoAllocateAlbPriority
Properties:
ServiceToken:
Fn::ImportValue: AllocateAlbRulePriorityCustomResourceLambdaArn
ListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Priority: !GetAtt AllocateAlbRulePriorityCustomResource.Priority
[...]
这些是片段,可能无法按原样工作,尽管它们取自工作代码。我希望它能让您大致了解如何实现这一目标。如果您需要更多帮助,请告诉我。