本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
了解如何使用带有自定义属性的 Amazon Cloud Map 服务发现 Amazon CLI
本教程演示了如何使用带有自定义属性的 Amazon Cloud Map 服务发现。您将创建一个微服务应用程序, Amazon Cloud Map 用于使用自定义属性动态发现资源。该应用程序由两个 Lambda 函数组成,它们在 DynamoDB 表中写入和读取数据,所有资源都注册在中。 Amazon Cloud Map
有关本教程的 Amazon Web Services Management Console 版本,请参阅了解如何使用带有自定义属性的 Amazon Cloud Map 服务发现。
先决条件
在开始本教程之前,请完成中的步骤设置为使用 Amazon Cloud Map。
创建 Amazon Cloud Map 命名空间
命名空间是一种用于对应用程序的服务进行分组的结构。在此步骤中,您将创建一个允许通过 Amazon Cloud Map API 调用发现资源的命名空间。
-
运行以下命令创建 HTTP 命名空间:
aws servicediscovery create-http-namespace \ --name cloudmap-tutorial \ --creator-request-id cloudmap-tutorial-request
该命令返回操作 ID。您可以使用以下命令检查操作的状态:
aws servicediscovery get-operation \ --operation-id operation-id
-
创建命名空间后,您可以检索其 ID 以用于后续命令:
aws servicediscovery list-namespaces \ --query "Namespaces[?Name=='cloudmap-tutorial'].Id" \ --output text
-
将命名空间 ID 存储在变量中以备后用:
NAMESPACE_ID=$(aws servicediscovery list-namespaces \ --query "Namespaces[?Name=='cloudmap-tutorial'].Id" \ --output text)
创建 DynamoDB 表
接下来,创建一个用于存储应用程序数据的 DynamoDB 表:
-
运行以下命令创建表:
aws dynamodb create-table \ --table-name cloudmap \ --attribute-definitions AttributeName=id,AttributeType=S \ --key-schema AttributeName=id,KeyType=HASH \ --billing-mode PAY_PER_REQUEST
-
等待表格变为活动状态后再继续:
aws dynamodb wait table-exists --table-name cloudmap
此命令将等待,直到表完全创建完毕并可供使用。
创建 Amazon Cloud Map 数据服务并注册 DynamoDB 表
现在,在你的命名空间中创建一个服务来表示数据存储资源:
-
运行以下命令为数据存储资源创建 Amazon Cloud Map 服务:
aws servicediscovery create-service \ --name data-service \ --namespace-id $NAMESPACE_ID \ --creator-request-id data-service-request
-
获取数据服务的服务 ID:
DATA_SERVICE_ID=$(aws servicediscovery list-services \ --query "Services[?Name=='data-service'].Id" \ --output text)
-
将 DynamoDB 表注册为具有指定表名的自定义属性的服务实例:
aws servicediscovery register-instance \ --service-id $DATA_SERVICE_ID \ --instance-id data-instance \ --attributes tablename=cloudmap
自定义属性
tablename=cloudmap
允许其他服务动态发现 DynamoDB 表名。
为 Lambda 函数创建 IAM 角色
创建一个 IAM 角色,Lambda 函数将使用该角色来访问 Amazon 资源:
-
为 IAM 角色创建信任策略文档:
cat > lambda-trust-policy.json << EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF
-
运行以下命令以使用信任策略创建 IAM 角色:
aws iam create-role \ --role-name cloudmap-tutorial-role \ --assume-role-policy-document file://lambda-trust-policy.json
-
为具有最低权限的自定义 IAM 策略创建文件:
cat > cloudmap-policy.json << EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "servicediscovery:DiscoverInstances" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "dynamodb:PutItem", "dynamodb:Scan" ], "Resource": "arn:aws:dynamodb:*:*:table/cloudmap" } ] } EOF
-
创建策略并将其附加到 IAM 角色:
aws iam create-policy \ --policy-name CloudMapTutorialPolicy \ --policy-document file://cloudmap-policy.json POLICY_ARN=$(aws iam list-policies \ --query "Policies[?PolicyName=='CloudMapTutorialPolicy'].Arn" \ --output text) aws iam attach-role-policy \ --role-name cloudmap-tutorial-role \ --policy-arn $POLICY_ARN aws iam attach-role-policy \ --role-name cloudmap-tutorial-role \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
创建 Lambda 函数来写入数据
要创建将数据写入 DynamoDB 表的 Lambda 函数,请执行以下步骤:
-
为写入函数创建 Python 文件:
cat > writefunction.py << EOF import json import boto3 import random def lambda_handler(event, context): try: serviceclient = boto3.client('servicediscovery') response = serviceclient.discover_instances( NamespaceName='cloudmap-tutorial', ServiceName='data-service') if not response.get("Instances"): return { 'statusCode': 500, 'body': json.dumps({"error": "No instances found"}) } tablename = response["Instances"][0]["Attributes"].get("tablename") if not tablename: return { 'statusCode': 500, 'body': json.dumps({"error": "Table name attribute not found"}) } dynamodbclient = boto3.resource('dynamodb') table = dynamodbclient.Table(tablename) # Validate input if not isinstance(event, str): return { 'statusCode': 400, 'body': json.dumps({"error": "Input must be a string"}) } response = table.put_item( Item={ 'id': str(random.randint(1,100)), 'todo': event }) return { 'statusCode': 200, 'body': json.dumps(response) } except Exception as e: return { 'statusCode': 500, 'body': json.dumps({"error": str(e)}) } EOF
此函数 Amazon Cloud Map 用于从自定义属性中发现 DynamoDB 表名,然后向表中写入数据。
-
打包并部署 Lambda 函数:
zip writefunction.zip writefunction.py ROLE_ARN=$(aws iam get-role --role-name cloudmap-tutorial-role \ --query 'Role.Arn' --output text) aws lambda create-function \ --function-name writefunction \ --runtime python3.12 \ --role $ROLE_ARN \ --handler writefunction.lambda_handler \ --zip-file fileb://writefunction.zip \ --architectures x86_64
-
更新函数超时以避免超时错误:
aws lambda update-function-configuration \ --function-name writefunction \ --timeout 5
创建 Amazon Cloud Map 应用程序服务并注册 Lambda 写入函数
要在命名空间中创建另一个服务来表示应用程序函数,请执行以下步骤:
-
为应用程序函数创建服务:
aws servicediscovery create-service \ --name app-service \ --namespace-id $NAMESPACE_ID \ --creator-request-id app-service-request
-
获取应用程序服务的服务 ID:
APP_SERVICE_ID=$(aws servicediscovery list-services \ --query "Services[?Name=='app-service'].Id" \ --output text)
-
将 Lambda 写入函数注册为具有自定义属性的服务实例:
aws servicediscovery register-instance \ --service-id $APP_SERVICE_ID \ --instance-id write-instance \ --attributes action=write,functionname=writefunction
自定义属性
action=write
并functionname=writefunction
允许客户根据其用途发现此功能。
创建 Lambda 函数来读取数据
要创建从 DynamoDB 表中读取数据的 Lambda 函数,请执行以下步骤:
-
为读取函数创建 Python 文件:
cat > readfunction.py << EOF import json import boto3 def lambda_handler(event, context): try: serviceclient = boto3.client('servicediscovery') response = serviceclient.discover_instances( NamespaceName='cloudmap-tutorial', ServiceName='data-service') if not response.get("Instances"): return { 'statusCode': 500, 'body': json.dumps({"error": "No instances found"}) } tablename = response["Instances"][0]["Attributes"].get("tablename") if not tablename: return { 'statusCode': 500, 'body': json.dumps({"error": "Table name attribute not found"}) } dynamodbclient = boto3.resource('dynamodb') table = dynamodbclient.Table(tablename) # Use pagination for larger tables response = table.scan( Select='ALL_ATTRIBUTES', Limit=50 # Limit results for demonstration purposes ) # For production, you would implement pagination like this: # items = [] # while 'LastEvaluatedKey' in response: # items.extend(response['Items']) # response = table.scan( # Select='ALL_ATTRIBUTES', # ExclusiveStartKey=response['LastEvaluatedKey'] # ) # items.extend(response['Items']) return { 'statusCode': 200, 'body': json.dumps(response) } except Exception as e: return { 'statusCode': 500, 'body': json.dumps({"error": str(e)}) } EOF
此函数还用于 Amazon Cloud Map 发现 DynamoDB 表名,然后从表中读取数据。它包括错误处理和分页注释。
-
打包并部署 Lambda 函数:
zip readfunction.zip readfunction.py aws lambda create-function \ --function-name readfunction \ --runtime python3.12 \ --role $ROLE_ARN \ --handler readfunction.lambda_handler \ --zip-file fileb://readfunction.zip \ --architectures x86_64
-
更新函数超时:
aws lambda update-function-configuration \ --function-name readfunction \ --timeout 5
将 Lambda 读取函数注册为服务实例
要将 Lambda 读取函数注册为应用服务中的另一个服务实例,请执行以下步骤:
aws servicediscovery register-instance \ --service-id $APP_SERVICE_ID \ --instance-id read-instance \ --attributes action=read,functionname=readfunction
自定义属性action=read
并functionname=readfunction
允许客户根据其用途发现此功能。
创建和运行客户端应用程序
要创建用于发现和调用 Amazon Cloud Map 写入函数的 Python 客户端应用程序,请执行以下步骤:
-
为写入客户端应用程序创建一个 Python 文件:
cat > writeclient.py << EOF import boto3 import json try: serviceclient = boto3.client('servicediscovery') print("Discovering write function...") response = serviceclient.discover_instances( NamespaceName='cloudmap-tutorial', ServiceName='app-service', QueryParameters={ 'action': 'write' } ) if not response.get("Instances"): print("Error: No instances found") exit(1) functionname = response["Instances"][0]["Attributes"].get("functionname") if not functionname: print("Error: Function name attribute not found") exit(1) print(f"Found function: {functionname}") lambdaclient = boto3.client('lambda') print("Invoking Lambda function...") resp = lambdaclient.invoke( FunctionName=functionname, Payload='"This is a test data"' ) payload = resp["Payload"].read() print(f"Response: {payload.decode('utf-8')}") except Exception as e: print(f"Error: {str(e)}") EOF
此客户端使用该
QueryParameters
选项来查找具有该action=write
属性的服务实例。 -
为读取的客户端应用程序创建一个 Python 文件:
cat > readclient.py << EOF import boto3 import json try: serviceclient = boto3.client('servicediscovery') print("Discovering read function...") response = serviceclient.discover_instances( NamespaceName='cloudmap-tutorial', ServiceName='app-service', QueryParameters={ 'action': 'read' } ) if not response.get("Instances"): print("Error: No instances found") exit(1) functionname = response["Instances"][0]["Attributes"].get("functionname") if not functionname: print("Error: Function name attribute not found") exit(1) print(f"Found function: {functionname}") lambdaclient = boto3.client('lambda') print("Invoking Lambda function...") resp = lambdaclient.invoke( FunctionName=functionname, InvocationType='RequestResponse' ) payload = resp["Payload"].read() print(f"Response: {payload.decode('utf-8')}") except Exception as e: print(f"Error: {str(e)}") EOF
-
运行写入客户端向 DynamoDB 表添加数据:
python3 writeclient.py
输出应显示成功响应,HTTP 状态代码为 200。
-
运行读取客户端从 DynamoDB 表中检索数据:
python3 readclient.py
输出应显示写入表的数据,包括随机生成的 ID 和 “这是测试数据” 值。
清理资源
完成本教程后,请清理资源以免产生额外费用。
-
首先,运行以下命令取消注册服务实例:
aws servicediscovery deregister-instance \ --service-id $APP_SERVICE_ID \ --instance-id read-instance aws servicediscovery deregister-instance \ --service-id $APP_SERVICE_ID \ --instance-id write-instance aws servicediscovery deregister-instance \ --service-id $DATA_SERVICE_ID \ --instance-id data-instance
-
运行以下命令删除服务:
aws servicediscovery delete-service \ --id $APP_SERVICE_ID aws servicediscovery delete-service \ --id $DATA_SERVICE_ID
-
运行以下命令删除命名空间:
aws servicediscovery delete-namespace \ --id $NAMESPACE_ID
-
运行以下命令删除 Lambda 函数:
aws lambda delete-function --function-name writefunction aws lambda delete-function --function-name readfunction
-
运行以下命令删除 IAM 角色和策略:
aws iam detach-role-policy \ --role-name cloudmap-tutorial-role \ --policy-arn $POLICY_ARN aws iam detach-role-policy \ --role-name cloudmap-tutorial-role \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole aws iam delete-policy \ --policy-arn $POLICY_ARN aws iam delete-role --role-name cloudmap-tutorial-role
-
运行以下命令删除 DynamoDB 表:
aws dynamodb delete-table --table-name cloudmap
-
运行以下命令清理临时文件:
rm -f lambda-trust-policy.json cloudmap-policy.json writefunction.py readfunction.py writefunction.zip readfunction.zip writeclient.py readclient.py