image.png

Amazon Q Developer 是亚马逊推出的一个专为专业开发人员设计的人工智能助手,旨在提升代码开发和管理效率。其主要功能包括代码生成、调试、故障排除和安全漏洞扫描,提供一站式代码服务。

Amazon Q Developer 基于亚马逊云科技 17 年来积累的知识和经验训练而成,在帮助开发人员构建和开发基于亚马逊云的应用时,能够更好地体现其优势——可以为用户创建更加准确的云基础设施代码。为了展现这一独特优势,本文将以典型的亚马逊云基础设施构造需求为主题,展示 Amazon Q 在加速亚马逊云基础设施构建方面的具体实践。

构造符合生产需要的 VPC(Virtual Private Cloud)

VPC 是一个虚拟网络服务,允许用户在云中创建隔离的网络环境,自定义 IP 地址范围、配置路由和设置网络网关,实现资源的安全隔离与灵活管理。当用户第一次使用亚马逊云时,每个 Region 都会有一个默认的 VPC,通常包含 3 个公开子网,然而这样的 VPC 通常无法满足应用架构的生产需要,如良好的网络隔离性和安全性等要求。创建一个符合生产要求的 VPC 并非易事,它需要专业的网络规划能力,同时还要熟悉亚马逊云控制台的操作。而有了 Amazon Q Developer,这项工作会变得非常简单。

架构

一个符合生产需要的 VPC 架构,通常如下图所示。

1745317903695.jpg

需求描述

  • 3 个可用区(AZ),满足工作负载对跨可用区(AZ)网络高可用的需要。
  • 每个可用区(AZ)内均有一个公开子网,方便面向公网的跳板机,和负载均衡器等必须放在公开子网里的资源的硬性要求。
  • 每个可用区(AZ)内均需要规划多个不同用途的私有子网,分别用来为工作负载,数据库,以及中间件预留分配足够的 IP 地址。同时,每类子网都规划了不同的 IP 容量,以充分利用资源,并为将来扩容留出足够的余量。
  • 另外,所有私有子网的工作负载,都有访问公网的需要,以便于满足对外发送数据的需要,或者操作系统升级等联网需求。

传统方法

需手工在控制台创建。但这种方式,开发者必须理解所有细节,不但工作量大,而且很容易出错。

现代方法

可以利用亚马逊云科技提供的 CDK,用 IaC(Infrastructure as Code)的方式来通过创建 CDK 代码工程,以创建和维护资源。

  • 优点:IaC 方式的优点是以代码为基础设施描述的唯一来源,利于追溯变更,可以一键部署,一键销毁,非常符合 DevOps 的开发/运维模式,是当代普遍采用的管理基础设施的重要技术手段。
  • 缺点:CDK 代码本身有较大的学习成本,当开发人员具体为不同资源进行编码的时候,熟悉每一个资源的编码细节是必须的工作,为此,在实际编码的过程中,开发者不得不经常查阅开发手册,亦是十分耗时费力。

Amazon Q Developer 的方式

  • 可以以自然语言的交互形式,快速协助开发者生成 CDK 资源创建代码,可以大大降低开发人员必须深入细节才能编写高质量 CDK 代码所必须消耗的精力和时间。
  • 开发/运维人员仅需对架构有较为高层的认知,即可快速令 Amazon Q 编写出高质量的 CDK 代码。

Amazon Q Developer 实践

用自然语言,将需求以自然语言描述如下:

create a vpc, meeting below requirement:
- named "Q-VPC"
- cidr:10.0.0.0/16
- in each AZ, there're 4 subnets.
    - one subnet for jumpserver, the prefix is "pub_", 64 ips in total.
    - one subnet for db, the prefix is "db_", 256 ips in total.
    - one subnet for middleware, the the prefix is "mw_", 256 ips in total
    - one subnet for workload, the prefix is "wk_", 8192 ips in totial.
- totally 3 AZs.
- only one natgateway.
- a python based cdk project.

使用 Amazon Q 里的 Chat Window 里,输入上述提示词,Amazon Q 将会返回详细的代码建议,如下图所示。

image.png

可以看到 Amazon Q 可以很好地理解需求,并精准的计算出了每个子网的掩码,要知道在过去要做到这一点,开发者要自己去计算才能设计得出来。

开发者可以充分利用这种和 Amazon Q 的“交谈”机制,不断审视 Amazon Q 的输出,进而不断进行代码的修正/变更,往往这个交谈的过程会持续多次,直至最终形成比较满意的结果。

当反复交谈,得到了最终满足需要的提示词,即可在 Chat 窗口里输入/dev 并回车,使 Amazon Q 进入智能体模式,然后将上一个步骤的最终提示词输入后并回车,Amazon Q 将真正进行编码工作,在指定的目录里,创建出建议的 CDK 代码,如下图所示。

image.png

image.png

执行 cdk deploy 来进行代码部署,并打开控制台进行验证。如下图所示。

image.png

image.png

可以很清晰地看到,CDK 精准地创建了满足要求的资源。一个基本满足生产需要的 VPC 网络就这样搭建成功了。

结论

Amazon Q 仅用几轮自然语言对话,即可创建满足复杂要求的亚马逊云资源的创建要求,大大提升了工作效率。

构造 CDN(CloudFront + S3)

快速构造一个内容分发网络。

架构

1745318837537.jpg

需求描述

  • 创建一个 S3 bucket(私有),作为静态资源存储,本例为一个文本文件。
  • 创建 CloudFront,并配置源站为 S3。
  • 用户通过输入 CloudFront distribution 的 URL,即可下载文本文件。

传统方法

全部操作都需要手工在控制台创建,不但繁琐而且容易出现错误,并且操作都是一次性的,无法再次复用。

现代方法

利用亚马逊云科技提供的 CDK 来创建 CloudFront 和 S3,并编写 CDK 代码来满足上述需求。但每个亚马逊云资源的 CDK 具体编写代码都有不同,需要翻阅开发文档,或者寻找类似的样例代码去进行修改、并需要反复调试,效率很低,费时费力。

Amazon Q Developer 的方式

用自然语言的方式,交代给 Amazon Q,让后者去处理所有细节,编写出准确、高效的 CDK 代码。

Amazon Q Developer 实践

用自然语言,将需求描述如下。

create a cloudfront, meeting below requirement:
- a S3 bucket as origin
- there's a test text file named abc.txt, being put in s3 bucket
- print full test url in the end of cdk deploy.

创建一个目录,例如 cf-s3,并使用 IDE(本例为 IntelliJ IDEA),对于本例,由于 任务的复杂度比较低,所以可以尝试直接用/dev 功能(智能体),在 Amazon Q 里的 Chat Window 里,先键入/dev,然后输入上述提示词,如下图所示。

image.png

Amazon Q 将询问代码创建的位置,选择刚才新创建的目录后,点 Retry,Amazon Q 即开始工作,然后点 Accept all,即可创建一个标准的 CDK 工程,完整结构如下图所示。

image.png

可以看到 Amazon Q 很好地理解了需求,包括测试所需要的文本文件(含内容)都给创建好了! CDK 关键代码如下图所示。

image.png

执行 cdk deploy 来进行代码部署,如下图所示。

image.png

部署结束之后,CDK 打印出来了完整的测试所需要的 CloudFront distribution 的 URL,粘贴这个 URL 到浏览器中进行测试,如下图所示。

image.png

粘贴这个 URL 到浏览器中进行测试,如下图所示。

image.png

结论

寥寥几行描述,Amazon Q 便完成了内容分发网络的 CDK 代码编写。虽然这个用例相对简单,但用 Amazon Q 来实现,毫无疑问会更简单!

构造经典的 Amazon Serverless 后端应用

本例将展示在 Amazon Q 的助力之下,如何快速实现一个经典的 Amazon 无服务架构后端,该后端包含 APIGateway + Lambda + DynamoDB,且 APIGateway 上提供的 RestAPI 需要经过 Cognito 鉴权才能正常访问。

架构

1745318366040.jpg

需求描述

  • 创建一个受到 Cognito 鉴权保护的 Amazon APIGateway。
  • Amazon APIGateway 对接 Amazon Lambda,后者来实现真正的业务需求。
  • 创建一个 Docker Image 作为实际实现的 Amazon Lambda,并在代码中实现对 DynamoDB 的 CRUD 操作。
  • 编写测试代码测试上述接口(模拟真实客户端的行为)。

传统方法

全部操作都需要手工在控制台创建,繁琐程度超过前两个用例所需总和的数倍,即使是经验丰富的亚马逊云的从业人士,也要花费很多时间来进行调整和验证。

Amazon Q Developer 的方式

用自然语言的方式交给 Amazon Q 来处理,简化所有流程,快速直达结果。

Amazon Q Developer 实践

用自然语言,将需求描述如下(请注意,本次提示词较上两次更加贴近于高层业务而非技术细节)。

requirements:
I need a suite of serverless application, includes:
1) apigateway, provides restapi, integration with lambda, requires integration with cognito.
2) a lambda function base on docker, as backend.
3) dynamodb is the storage.
4) a cdk project to deploy all of above components.
please create full framework code, in a well done project structure.

创建一个目录,例如 qdev,并使用 IDE(本例为 IntelliJ IDEA)尝试直接使用/dev 功能(智能体)——在 Amazon Q 里的 Chat Window 里,先键入/dev,然后输入上述提示词,如下图所示。

image.png

Amazon Q 将询问代码位置,选择刚才新创建的目录后,点 Retry,Amazon Q 即开始工作,然后点 Accept all,即可创建一个标准的 CDK 工程,完整结构如下图所示。

image.png

可以看到 Amazon Q 很好地理解了需求,完全依照要求创建出来了 CDK 工程,其中最关键的创建亚马逊云资源的代码如下图所示。

from aws_cdk import (
    Stack,
    aws_apigateway as apigateway,
    aws_lambda as lambda_,
    aws_dynamodb as dynamodb,
    aws_cognito as cognito,
    aws_iam as iam,
    Duration,
    RemovalPolicy
)
from constructs import Construct


class ApiStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Create Cognito User Pool
        user_pool = cognito.UserPool(
            self, "UserPool",
            self_sign_up_enabled=True,
            auto_verify=cognito.AutoVerifiedAttrs(email=True),
            standard_attributes=cognito.StandardAttributes(
                email=cognito.StandardAttribute(required=True, mutable=True)
            )
        )

        # Create Cognito App Client
        client = user_pool.add_client("app-client",
            auth_flows=cognito.AuthFlow(user_password=True)
        )

        # Create DynamoDB table
        table = dynamodb.Table(
            self, "ItemsTable",
            partition_key=dynamodb.Attribute(
                name="id",
                type=dynamodb.AttributeType.STRING
            ),
            removal_policy=RemovalPolicy.DESTROY,
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST
        )

        # Create Lambda function using Docker
        backend_function = lambda_.DockerImageFunction(
            self, "BackendFunction",
            code=lambda_.DockerImageCode.from_image_asset("./lambda"),
            memory_size=1024,
            timeout=Duration.seconds(30),
            architecture=lambda_.Architecture.ARM_64,
            environment={
                "DYNAMODB_TABLE": table.table_name
            }
        )

        backend_function.role.add_managed_policy(
            iam.ManagedPolicy.from_aws_managed_policy_name("AmazonBedrockFullAccess"))

        # Grant Lambda function permissions to access DynamoDB
        table.grant_read_write_data(backend_function)

        # Create API Gateway with Cognito Authorizer
        api = apigateway.RestApi(
            self, "ServerlessApi",
            rest_api_name="Serverless API",
            description="Serverless API with Cognito authentication"
        )

        authorizer = apigateway.CognitoUserPoolsAuthorizer(
            self, "ApiAuthorizer",
            cognito_user_pools=[user_pool]
        )

        api.root.add_method(
            "ANY",
            apigateway.LambdaIntegration(backend_function),
            authorizer=authorizer,
            authorization_type=apigateway.AuthorizationType.COGNITO
        )

        items = api.root.add_resource("items")
        items.add_method(
            "ANY",
            apigateway.LambdaIntegration(backend_function),
            authorizer=authorizer,
            authorization_type=apigateway.AuthorizationType.COGNITO
        )

        items.add_resource("{proxy+}").add_method(
            "ANY",
            apigateway.LambdaIntegration(backend_function),
            authorizer=authorizer,
            authorization_type=apigateway.AuthorizationType.COGNITO
        )

仔细阅读这段 CDK 代码,可以清晰地看到所有资源的创建,以及复杂的关联关系的建立,还有各种 IAM 授权,都被 Amazon Q 以 CDK 的形式处理得十分妥当,这无疑大大简化了开发者的负担。

另外,Amazon Q 还提供了关键的 Lambda 实现代码,甚至自动编写了测试用的一个叫做 items 的 RestAPI 作为样例,展示了完整的 CRUD 过程。如图所示。

image.png

执行 cdk deploy 来进行代码部署(过程与前两个例子一致,此处从略)。创建出来的资源如下图所示。

image.png
API Gateway 资源

image.png
受到 Cognito 保护的/items 接口

image.png
关联到 Lambda 作为后端

image.png
Docker Image 类型的 Lambda

为了方便测试,手动在 Cognito 里创建一个用户(模拟 signup)。进入对应的 Cognito UserPool 中,选择 User,点击“Create User”来创建用户,如下图所示。

image.png

创建用户成功后,效果如下图所示,请务必记录初始密码!测试程序第一次登录后会要求用这个密码来登录,且会要求修改密码,这个初始密码仅能用一次。

image.png

还要对 App Client 的鉴权方式进行一下配置,调整 Authentication flows 的选项,如下图所示。

image.png

image.png

在 CDK 工程中,创建一个 tests 的目录,再次使用 Amazon Q,编写测试代码,来模拟从鉴权,到调用所有 API 的全部过程。提示词如下。

requirements:
accroding to this cdk project, please write a python test application which includes:
1) auth congnito user pool (handle password challege is required) and get/print the id token.
2) use id token to auth apigateway, test /items rest apis

image.png

Amazon Q Developer 将创建如下代码。

import boto3
import os
import requests
from botocore.exceptions import ClientError

def check_pro_status(custom_attrs):
    """Check if user is pro and return paid status"""
    try:
        # Check if custom:pro exists and its value
        if 'custom:pro' not in custom_attrs:
            paid = False
        else:
            paid = custom_attrs['custom:pro'].lower() == 'yes'

        return {
            'paid': paid,
            'custom_attributes': custom_attrs
        }

    except Exception as e:
        print(f"Error checking pro status: {e}")
        raise


def test_api_with_cognito_auth():
    # First get the Cognito access token
    # Initialize Cognito Identity Provider client
    cognito_idp = boto3.client('cognito-idp')
    
    # Replace these with your actual values
    USER_POOL_ID = os.getenv('COGNITO_USER_POOL_ID')
    CLIENT_ID = os.getenv('COGNITO_CLIENT_ID')
    USERNAME = os.getenv('COGNITO_USERNAME')
    PASSWORD = os.getenv('COGNITO_PASSWORD')
    
    try:
        # Attempt to authenticate
        auth_response = cognito_idp.initiate_auth(
            AuthFlow='USER_PASSWORD_AUTH',
            ClientId=CLIENT_ID,
            AuthParameters={
                'USERNAME': USERNAME,
                'PASSWORD': PASSWORD
            }
        )
        
        # Check if password needs to be changed
        if auth_response.get('ChallengeName') == 'NEW_PASSWORD_REQUIRED':
            print("Password change required...")
            
            # Respond to the challenge with a new password
            new_password = 'NewPassword123!'  # Replace with desired new password
            challenge_response = cognito_idp.respond_to_auth_challenge(
                ClientId=CLIENT_ID,
                ChallengeName='NEW_PASSWORD_REQUIRED',
                Session=auth_response['Session'],
                ChallengeResponses={
                    'USERNAME': USERNAME,
                    'NEW_PASSWORD': new_password
                }
            )
            
            # Get the tokens from the challenge response
            tokens = challenge_response['AuthenticationResult']
            access_token = tokens['AccessToken']
            print("Password changed successfully!")
            
        else:
            # Get the tokens from the initial auth response
            tokens = auth_response['AuthenticationResult']
            access_token = tokens['AccessToken']
            id_token = tokens['IdToken']
        
        print(f"Access Token: {access_token}")
        print(f"ID Token: {id_token}")
        #create a new function to get custome attributes
        response = cognito_idp.get_user(
            AccessToken=access_token
        )
        pro = False
        custom_attrs = response['UserAttributes']
        if 'custom:pro' not in custom_attrs:
            pro = False
        else:
            pro = custom_attrs['custom:pro'].lower() == 'yes'

        if pro:
            print("User is pro")
        else:
            print("User is not pro")
        
        # Now use the access token to call the API
        api_url = os.getenv('API_ENDPOINT')
        headers = {
            'Content-Type': 'application/json'
        }
        headers = {
            'Authorization': f'Bearer {access_token}',
            'Content-Type': 'application/json'
        }
        headers = {
            'Authorization': f'Bearer {id_token}',
            'Content-Type': 'application/json'
        }
        # Test GET /items endpoint
        response = requests.get(f"{api_url}/items", headers=headers)
        assert response.status_code == 200
        items = response.json().get('items', [])
        assert isinstance(items, list)
        
        # Test POST /items endpoint
        test_item = {
            "id": "test-item-1",
            "name": "Test Item",
            "description": "This is a test item"
        }
        response = requests.post(f"{api_url}/items", headers=headers, json=test_item)
        assert response.status_code == 200
        assert response.json()['message'] == "Item created"
        
        # Test GET /items/<id> endpoint
        response = requests.get(f"{api_url}/items/test-item-1", headers=headers)
        assert response.status_code == 200
        assert response.json()['id'] == "test-item-1"
        
        # Test PUT /items/<id> endpoint
        updated_item = {
            "name": "Updated Test Item",
            "description": "This is an updated test item"
        }
        response = requests.put(f"{api_url}/items/test-item-1", headers=headers, json=updated_item)
        assert response.status_code == 200
        assert response.json()['message'] == "Item updated"
        
        # Test DELETE /items/<id> endpoint
        response = requests.delete(f"{api_url}/items/test-item-1", headers=headers)
        assert response.status_code == 200
        assert response.json()['message'] == "Item deleted"
        print(response.status_code)
        print(response.json())

    except ClientError as e:
        print(f"Authentication error: {str(e)}")
        raise

if __name__ == '__main__':
    test_api_with_cognito_auth()

浏览代码,可以观察到 Amazon Q Developer 非常完美地进行了 Cognito UserPool 的鉴权,甚至可以在第一次运行,需要修改密码的场景,会提示用户修改密码,大大节约了常规调试同样功能所需要的时间开销。

运行测试代码,观察结果(从略)。

结论

开发者利用 Amazon Q Developer 的强大能力,前后仅需 10 几行自然语言描述,即可完成相当复杂的 Serverless 资源创建和配置,并可以帮助开发者轻松编写测试代码验证业务接口的可用性,对工作效率的提升,令人叹为观止。

最后

本文以创建/维护亚马逊云资源作为主要内容,提供了简单易懂、图文并茂的实际代码用例,对 AmazonQ Develop 如何能够加速亚马逊云资源开发的具体操作过程进行了详细描述。

本篇作者

image.png

本期最新实验为《Agentic AI 帮你做应用 —— 从0到1打造自己的智能番茄钟
✨ 自然语言玩转命令行,10分钟帮你构建应用,1小时搞定新功能拓展、测试优化、文档注释和部署
💪 免费体验企业级 AI 开发工具,质量+安全全掌控
⏩️[点击进入实验] 即刻开启 AI 开发之旅
构建无限, 探索启程!

亚马逊云开发者
2.9k 声望9.6k 粉丝

亚马逊云开发者社区是面向开发者交流与互动的平台。在这里,你可以分享和获取有关云计算、人工智能、IoT、区块链等相关技术和前沿知识,也可以与同行或爱好者们交流探讨,共同成长。