如何识别 aws cdk 应用程序何时在部署状态下运行?

Posted

技术标签:

【中文标题】如何识别 aws cdk 应用程序何时在部署状态下运行?【英文标题】:How can I identify when the aws cdk app is running in the deployment state? 【发布时间】:2021-10-13 21:14:39 【问题描述】:

我有以下问题:

我创建了一个堆栈,在创建资源后(特别是带有 Amazon MQ 的 rabbitmq 代理)我想配置一些不能用 cdk 完成的东西,而必须通过 REST api 调用来完成。

问题是我只想在代理启动并运行并且rabbitmq_url被解析后仅在部署状态下进行其余的api调用。

我有类似以下的东西,但没有按预期工作:

# Doc Ref: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-amazonmq-broker.html
rabbitmq_broker = amazonmq. \
    CfnBroker(self, "RabbitMQBroker",
              broker_name=f"os.getenv('ENVIRONMENT_NAME')-rabbitmq",
              engine_type="RABBITMQ",
              engine_version="3.8.17",
              deployment_mode="SINGLE_INSTANCE",
              host_instance_type="mq.t3.micro",
              subnet_ids=[[public_subnet.subnet_id for public_subnet in vpc.public_subnets][0]],
              logs=amazonmq.CfnBroker.LogListProperty(general=True),
              # This means we can access rabbitmq from internet without going into the VPC
              publicly_accessible=True,
              users=[amazonmq.CfnBroker.UserProperty(username=os.getenv('RABBITMQ_USER'),
                                                     password=os.getenv('RABBITMQ_PASSWORD'))],
              auto_minor_version_upgrade=True)

rabbitmq_url = f"rabbitmq_broker.ref.mq.os.getenv('CDK_DEFAULT_REGION').amazonaws.com"

...

# Only executed when the token is resolved in the deploy stage
if not core.Token.is_unresolved(rabbitmq_broker.ref):
# Create virtual host 'kmhbackend' via RabbitMQ Management HTTP API
    response = requests.post(f"https://rabbitmq_url:15671/api/vhosts/kmhbackend",
                          auth=(os.getenv('RABBITMQ_USER'), os.getenv('RABBITMQ_PASSWORD')),
                          headers='content-type': 'application/json')

    if response.status_code != requests.codes.get('created'):
        Log.error("Warning: The virtual host has not been created")
        print("Warning: The virtual host has not been created")

如何识别 cdk 应用何时在部署状态下运行?

我不想只使用上下文变量来识别它。

提前致谢

【问题讨论】:

你可以一直等待你的堆栈完成它的整个部署,然后执行 API 调用? @DebdutGoswami,你是什么意思等待整个部署完成,先执行 cdk deploy 然后执行一些其他脚本来配置剩下的东西?这样会有点松散 Iac 的感觉,因为我需要在每次部署后手动执行或创建一个 lambda 来监听事件,但这样做会有点痛苦 你是绝对正确的,但我只是提出了一种解决方法,因为我无法在 cdk 文档中找到任何类似的东西。也许我只是在寻找错误的关键字。您可以改为在他们的 github 存储库中提出功能请求。 【参考方案1】:

所以深入阅读文档后,解决方案是在新的嵌套堆栈中创建自定义资源,并在2个堆栈之间添加依赖关系,这样自定义资源将等待初始资源完全部署。

所以解决办法是这样的:

class MessageBrokerConfigStack(core.NestedStack):
    """
    This stack will take of configure rabbitmq once it's created by API calls

    * the RabbitMQ Management HTTP API at 'rabbitmq-web-console:15671' ,
    docs of API can be found in rabbitmq_url/api/index.html

    Warning: In the docs the port used for the RabbitMQ Management HTTP API is 15672,
    but with AWS the port to be used is 15671
    """

    def __init__(self, scope: core.Construct, id: str,
                 vpc: ec2.Vpc, rabbit_broker_url: str,
                 rabbitmq_user: str, rabbitmq_password: str,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
    
        ...
        onEvent = lambda_. \
        Function(self, "CR_RabbitMQ_configurator_handler",
                 function_name="cr_cdk_rabbitmq_configurator_handler",
                 description="Function that will handle all the configuration for rabbitmq broker created by cdk",
                 runtime=lambda_.Runtime.PYTHON_3_7,
                 layers=[layer],
                 handler="config_rabbitmq.lambda_handler",
                 code=lambda_.Code.from_asset('aws_lambda/lambdas')
                 )

    config_rabbitmq_provider = cr.Provider(self, 'CR_RabbitMQ_configurator_provider',
                                           vpc=vpc,
                                           vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE),
                                           on_event_handler=onEvent)

    # Will create a custom resource in cloudformation, this custom resource is compose by a lambda that
    # will contain a function and this function will handle the different events
    # ref https://docs.aws.amazon.com/cdk/latest/guide/apps.html#lifecycle
    # ref https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html#cfn_layer_custom
    config_rabbitmq = core.CustomResource(self, 'CR_RabbitMQ_configurator',
                                          service_token=config_rabbitmq_provider.service_token,
                                          properties=
                                              "rabbitmq_url": rabbit_broker_url,
                                              "rabbit_user": rabbitmq_user,
                                              "rabbit_password": rabbitmq_password
                                          )

然后 lambda 代码将侦听事件并执行所需的操作。

import requests


def lambda_handler(event, context):
    """
    This method is the native input for AWS Lambda
    """

    print("lambda rabbitmq received")
    print(event)
    print(context)

    props = event['ResourceProperties']
    rabbitmq_url = props['rabbitmq_url']
    rabbit_user = props['rabbit_user']
    rabbit_password = props['rabbit_password']

    print(rabbitmq_url)
    print(rabbit_user)
    print(rabbit_password)

    if event["RequestType"] == "Create":
        # ref https://docs.aws.amazon.com/cdk/latest/guide/apps.html#lifecycle
        # ref https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html#cfn_layer_custom
        # Only executed when the token is resolved in the deploy stage
        # Create virtual host 'kmhbackend' via RabbitMQ Management HTTP API
        response = requests.put(f"https://rabbitmq_url:15671/api/vhosts/new_virtual_host",
                                auth=(rabbit_user, rabbit_password),
                                headers='content-type': 'application/json')

        print("response from rabbitmq:")
        print(response)

        if response.status_code != requests.codes.get('created'):
            print("Warning: The virtual host has not been created")
    

然后在父栈上我们只需要做

resource = Resource(....)

configResource = ConfigResouce(...)

configResource.add_dependency(resource)

【讨论】:

以上是关于如何识别 aws cdk 应用程序何时在部署状态下运行?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 aws-cdk 从 AWS Secrets Manager 导入 EKS 密钥?

如何在部署前从@aws-cdk/aws-appsync 检索 schema.graphql 文件

如何在部署期间使用非 AWS 资源扩展 AWS CDK

如何使用 Elastic Beanstalk 为 AWS CDK 设置环境变量?

如何将现有资源从不同的 AWS 账户导入 AWS CDK

如何在 AWS CDK 的“CodeBuildAction”中指定区域?