今回は2024年4月の終わりにGAとなったAmazon Q Developerを使ってみました。
背景
以前Amazon CodeWhispererからCloudFormationコードの開発を試しましたが、つい先日Amazon Q DeveloperがGAとなり、CodeWhispererもAmazon Q Developerの機能の一部として変更されました。
なお今回は触れませんが、GAになって以下のような機能が追加されています。
- AWSアカウント上のリソース情報の提供: S3バケットやLambda関数といったリソースの個数などをチャットから質問できます。
- AWSコスト情報の提供: アカウント上で利用料金の大きいリソース種別などを質問できます。
- Software development:
/dev
コマンドと自然言語を組み合わせて、コードを生成します(CodeCatalystとの連携が必要)。 - Code transformation: Javaのコードのバージョン更新に合わせてコードを修正します (ドキュメント)。
※参考:
検証
Visual Studio Codeの拡張機能更新
以前Amazon CodeWhispererをVisual Studio Codeにインストールしているので、VSCodeの再起動・更新を行います。起動後、Amazon Qにログインすれば準備は完了です。
コード生成
試しに前回と同様CloudFormationのコードを生成してみます。生成時の精度などはまだわかりませんが、生成時のメッセージが Amazon Q is generating…
に変更されています。
特に問題もなく生成されました。
コードの説明
続いて既存コードに対する機能をいくつか見ていきます。
IDE上でコードを選択して右クリックを押すと、以下のようにいくつかオプションが表示されます。
このうち explain
をクリックすると、選択したコードがどんな内容かを説明してくれます。
今回は以下のように出力されました。CloudFormationの各項目について説明してくれるので、初めて見るコードの理解に役立ちそうです。
The code you provided is a CloudFormation template that defines an ECS (Elastic Container Service) Task Definition. The Task Definition is the blueprint for running a Docker container in an ECS cluster.
Here's a breakdown of the key elements in the code:
- ECSTaskDefinition:
- This is the CloudFormation resource that defines the ECS Task Definition.
- The
Type
is set toAWS::ECS::TaskDefinition
, which is the CloudFormation resource type for an ECS Task Definition.
- Properties:
RequiresCompatibilities
: Specifies the launch type compatibility for the task. In this case, it's set toFARGATE
, which means the task will run on AWS Fargate, a serverless compute engine for containers.Cpu
: Specifies the number of CPU units used by the task. In this case, it's set to1024
, which is equivalent to 1 vCPU.Memory
: Specifies the amount of memory (in MiB) used by the task. In this case, it's set to2048
MiB, which is 2 GB.NetworkMode
: Specifies the Docker networking mode to use for the containers in the task. In this case, it's set toawsvpc
, which provides each task with its own elastic network interface.ExecutionRoleArn
: Specifies the ARN (Amazon Resource Name) of the IAM role that provides permissions for the ECS task to access other AWS services.ContainerDefinitions
: Defines the container(s) that will be part of the task. In this case, there is a single container definition.Name
: The name of the container, which is set to the name of the CloudFormation stack.Image
: The Docker image to use for the container, which is specified by theECRRepository
parameter.PortMappings
: Defines the port mapping between the container and the host. In this case, the container exposes port 80.LogConfiguration
: Configures the log driver and options for the container. In this case, it's set to use theawslogs
log driver, which sends logs to CloudWatch Logs.
This CloudFormation template sets up an ECS Task Definition that runs a single container on the Fargate launch type, with specific CPU, memory, and networking configurations, as well as logging settings.
コードのリファクタリング
先ほどと同様にコードを選択して右クリックしたのち、今度は refactor
を選択します。今度は選択したコードを修正する場合の選択肢を提示してくれます。
ここでは大きく4か所の修正を提案されました。
ECSTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Ref AWS::StackName RequiresCompatibilities: - FARGATE Cpu: 1024 Memory: 2048 NetworkMode: awsvpc ExecutionRoleArn: !GetAtt ECSExecutionRole.Arn TaskRoleArn: !GetAtt ECSTaskRole.Arn ContainerDefinitions: - Name: app Image: !Ref ECRRepository PortMappings: - ContainerPort: 80 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref AWS::StackName awslogs-region: !Ref AWS::Region awslogs-stream-prefix: ecs
Here are the changes made in the refactored code:
- Family: I've added the
Family
property to theECSTaskDefinition
resource. This property specifies the name of the task definition. In this case, it's set to the name of the CloudFormation stack using the!Ref AWS::StackName
intrinsic function. - TaskRoleArn: I've added the
TaskRoleArn
property to theECSTaskDefinition
resource. This property specifies the ARN of the IAM role that provides permissions for the ECS task to access other AWS services. In this case, it's set to theECSTaskRole
resource, which should be defined elsewhere in the CloudFormation template. - Container Name: I've changed the container name from the stack name to a more generic "app" name. This makes the task definition more reusable and easier to understand.
- Formatting: I've improved the formatting of the code for better readability, such as aligning the properties and using consistent indentation.
These changes make the task definition more explicit and easier to understand. The Family
and TaskRoleArn
properties provide more context about the task definition, and the container name change makes the definition more generic and reusable.
Remember, when working with AWS credentials in your code, it's important to fetch them from environment variables instead of hardcoding them directly in the code. This helps maintain better security practices and makes the code more portable.
コードの修正
今度は fix
を試してみます。オプションを選択する前に一部コードをわざと変にしておきます。すると、誤った箇所を指摘しつつ、正しい記述を表示してくれました。
ECSTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - FARGATE Cpu: 1024 Memory: 2048 NetworkMode: awsvpc ExecutionRoleArn: !GetAtt ECSExecutionRole.Arn ContainerDefinitions: - Name: !Ref AWS::StackName Image: !Ref ECRRepository PortMappings: - ContainerPort: 80 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref AWS::StackName awslogs-region: !Ref AWS::Region awslogs-stream-prefix: ecs
The changes made in this fixed version are:
- Removed
FARGATEFailed
fromRequiresCompatibilities
: The correct value for theRequiresCompatibilities
property isFARGATE
, notFARGATEFailed
. - Kept the rest of the code unchanged: The rest of the code, including the
Cpu
,Memory
,NetworkMode
,ExecutionRoleArn
,ContainerDefinitions
,PortMappings
, andLogConfiguration
properties, remains the same as the original code block.
This fixed version of the code should work as expected, creating an ECS Task Definition with the specified configurations.
Remember, when working with AWS credentials in your code, it's important to fetch them from environment variables instead of hardcoding them directly in the code. This helps maintain better security practices and makes the code more portable.
コードの最適化
optimize
はコードを最適化し、パフォーマンスの向上などをサポートする機能です。ここでは以下のように4つの提案をされました。
ECSTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - FARGATE Cpu: 1024 Memory: 2048 NetworkMode: awsvpc ExecutionRoleArn: !GetAtt ECSExecutionRole.Arn TaskRoleArn: !GetAtt ECSTaskRole.Arn ContainerDefinitions: - Name: app Image: !Ref ECRRepository PortMappings: - ContainerPort: 80 Environment: - Name: LOG_LEVEL Value: info LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: ecs DependsOn: - LogGroup LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Ref AWS::StackName RetentionInDays: 7
Here are the optimizations made in this version:
- Added
TaskRoleArn
: I've added theTaskRoleArn
property to theECSTaskDefinition
resource. This property specifies the ARN of the IAM role that provides permissions for the ECS task to access other AWS services. In this case, it's set to theECSTaskRole
resource, which should be defined elsewhere in the CloudFormation template. - Changed container name: I've changed the container name from the stack name to a more generic "app" name. This makes the task definition more reusable and easier to understand.
- Added environment variable: I've added an environment variable
LOG_LEVEL
with a value ofinfo
. This can be used by the application running in the container to control the logging level. - Moved log group to separate resource: I've moved the log group configuration to a separate
LogGroup
resource. This makes the code more modular and easier to maintain. TheDependsOn
property ensures that the log group is created before the task definition. - Improved log group configuration: I've added the
RetentionInDays
property to theLogGroup
resource, which specifies the number of days to retain the log events. In this case, it's set to 7 days.
These optimizations make the task definition more explicit, reusable, and easier to maintain. The addition of the task role and environment variable provide more flexibility and control over the container's execution. The separation of the log group configuration into a separate resource improves the overall code structure and modularity.
Remember, when working with AWS credentials in your code, it's important to fetch them from environment variables instead of hardcoding them directly in the code. This helps maintain better security practices and makes the code more portable.