如何通过AWS CDK获取EC2实例的公网IP或公网DNS?
在AWS CDK中获取EC2公网IP/DNS的正确姿势
当然可行!我之前帮很多开发者解决过这个问题——你看到的${Token[TOKEN.XX]}是CDK的正常机制,先给你拆解原因,再给几种实用的解决方案:
为什么会出现Token?
CDK是声明式的基础设施即代码工具,在你执行cdk synth或cdk deploy的早期阶段,EC2实例还没被AWS实际创建,所以公网IP、公网DNS这类动态生成的属性还没有真实值。CDK用Token作为占位符,等部署完成后才会被AWS替换成实际的资源值。直接在代码里print的话,只能拿到这个占位符,而不是真实IP/DNS。
解决方案1:用CfnOutput输出部署后的真实值(最常用)
这是最简单直接的方式,部署完成后会在控制台显示结果,也可以导出到文件供SSH/Ansible使用。修改你的代码,在EC2实例定义后添加这两行:
core.CfnOutput(self, "EC2PublicDNS", value=ec2.instance_public_dns_name, description="EC2实例公网DNS") core.CfnOutput(self, "EC2PublicIP", value=ec2.instance_public_ip, description="EC2实例公网IP")
执行cdk deploy后,控制台会输出类似这样的内容:
Outputs: WebsiteStack.EC2PublicDNS = ec2-12-34-56-78.us-east-1.compute.amazonaws.com WebsiteStack.EC2PublicIP = 12.34.56.78
如果想把输出保存到JSON文件(方便脚本读取),用这条命令部署:
cdk deploy --outputs-file ec2-outputs.json
之后你可以直接从ec2-outputs.json里提取IP/DNS,比如用jq命令:
# 获取公网IP jq -r '.WebsiteStack.EC2PublicIP' ec2-outputs.json
解决方案2:在CDK代码中传递Token给其他资源
如果你的CDK代码需要把公网IP/DNS传给其他资源(比如Lambda函数的环境变量、S3桶的通知配置),直接使用Token即可——CDK会在部署阶段自动把Token替换成真实值,不需要做额外处理:
# 示例:把EC2公网DNS传给Lambda函数 lambda_fn = aws_lambda.Function( self, "MyAnsibleTriggerLambda", runtime=aws_lambda.Runtime.PYTHON_3_11, code=aws_lambda.Code.from_asset("lambda"), handler="handler.lambda_handler", environment={ "EC2_PUBLIC_DNS": ec2.instance_public_dns_name, "EC2_PUBLIC_IP": ec2.instance_public_ip } )
解决方案3:部署时实时获取并输出(进阶)
如果需要在部署过程中就拿到真实值(而不是等部署完成),可以用CDK的自定义资源(Custom Resource)来调用AWS API查询实例属性。示例代码如下:
from aws_cdk import custom_resources as cr # 创建一个Lambda函数作为自定义资源的处理器,用于查询EC2实例信息 ec2_info_handler = aws_lambda.Function( self, "EC2InfoHandler", runtime=aws_lambda.Runtime.PYTHON_3_11, code=aws_lambda.Code.from_inline(""" import boto3 import json def handler(event, context): ec2_client = boto3.client('ec2') instance_id = event['ResourceProperties']['InstanceId'] # 查询实例详情 response = ec2_client.describe_instances(InstanceIds=[instance_id]) instance_data = response['Reservations'][0]['Instances'][0] return { 'PhysicalResourceId': instance_id, 'Data': { 'PublicDnsName': instance_data.get('PublicDnsName', ''), 'PublicIpAddress': instance_data.get('PublicIpAddress', '') } } """), handler="index.handler" ) # 给Lambda函数添加查询EC2实例的权限 ec2_info_handler.add_to_role_policy(aws_iam.PolicyStatement( actions=["ec2:DescribeInstances"], resources=["*"] )) # 创建自定义资源,传入EC2实例ID ec2_info_resource = cr.AwsCustomResource(self, "EC2InfoResource", resource_type="Custom::EC2InstanceInfo", service_token=ec2_info_handler.function_arn, properties={ "InstanceId": ec2.instance_id } ) # 输出自定义资源返回的真实IP/DNS core.CfnOutput(self, "EC2PublicDNS_RealTime", value=ec2_info_resource.get_string("PublicDnsName")) core.CfnOutput(self, "EC2PublicIP_RealTime", value=ec2_info_resource.get_string("PublicIpAddress"))
这种方式会在EC2实例创建完成后立即查询并输出真实值,适合需要在部署流程中即时获取的场景。
内容的提问来源于stack exchange,提问作者Ikar Pohorský
相关产品推荐
相关产品推荐

