TECHSTEP

ITインフラ関連の記事を公開してます。

Amazon Q DeveloperがGAされたのでVisual Studio Codeから使ってみる

今回は2024年4月の終わりにGAとなったAmazon Q Developerを使ってみました。

aws.amazon.com

背景

以前Amazon CodeWhispererからCloudFormationコードの開発を試しましたが、つい先日Amazon Q DeveloperがGAとなり、CodeWhispererもAmazon Q Developerの機能の一部として変更されました。

なお今回は触れませんが、GAになって以下のような機能が追加されています。

  • AWSアカウント上のリソース情報の提供: S3バケットやLambda関数といったリソースの個数などをチャットから質問できます。
  • AWSコスト情報の提供: アカウント上で利用料金の大きいリソース種別などを質問できます。
  • Software development: /dev コマンドと自然言語を組み合わせて、コードを生成します(CodeCatalystとの連携が必要)。
  • Code transformation: Javaのコードのバージョン更新に合わせてコードを修正します (ドキュメント)。

※参考:

aws.amazon.com

検証

Visual Studio Code拡張機能更新

以前Amazon CodeWhispererをVisual Studio Codeにインストールしているので、VSCodeの再起動・更新を行います。起動後、Amazon Qにログインすれば準備は完了です。

コード生成

試しに前回と同様CloudFormationのコードを生成してみます。生成時の精度などはまだわかりませんが、生成時のメッセージが Amazon Q is generating… に変更されています。

特に問題もなく生成されました。

コードの説明

続いて既存コードに対する機能をいくつか見ていきます。

docs.aws.amazon.com

IDE上でコードを選択して右クリックを押すと、以下のようにいくつかオプションが表示されます。

このうち explain をクリックすると、選択したコードがどんな内容かを説明してくれます。

今回は以下のように出力されました。CloudFormationの各項目について説明してくれるので、初めて見るコードの理解に役立ちそうです。

Certainly, let me explain the selected code block for the ECS Task Definition.

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:

  1. ECSTaskDefinition:
    • This is the CloudFormation resource that defines the ECS Task Definition.
    • The Type is set to AWS::ECS::TaskDefinition, which is the CloudFormation resource type for an ECS Task Definition.
  2. Properties:
    • RequiresCompatibilities: Specifies the launch type compatibility for the task. In this case, it's set to FARGATE, 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 to 1024, which is equivalent to 1 vCPU.
    • Memory: Specifies the amount of memory (in MiB) used by the task. In this case, it's set to 2048 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 to awsvpc, 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 the ECRRepository 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 the awslogs 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か所の修正を提案されました。

Here's a refactored version of the ECS Task Definition code block:

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:

  1. Family: I've added the Family property to the ECSTaskDefinition 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.
  2. TaskRoleArn: I've added the TaskRoleArn property to the ECSTaskDefinition 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 the ECSTaskRole resource, which should be defined elsewhere in the CloudFormation template.
  3. 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.
  4. 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 を試してみます。オプションを選択する前に一部コードをわざと変にしておきます。すると、誤った箇所を指摘しつつ、正しい記述を表示してくれました。

Here's the fixed version of the ECS Task Definition code block:

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:

  1. Removed FARGATEFailed from RequiresCompatibilities: The correct value for the RequiresCompatibilities property is FARGATE, not FARGATEFailed.
  2. Kept the rest of the code unchanged: The rest of the code, including the Cpu, Memory, NetworkMode, ExecutionRoleArn, ContainerDefinitions, PortMappings, and LogConfiguration 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つの提案をされました。

Here's an optimized version of the ECS Task Definition code block:

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:

  1. Added TaskRoleArn: I've added the TaskRoleArn property to the ECSTaskDefinition 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 the ECSTaskRole resource, which should be defined elsewhere in the CloudFormation template.
  2. 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.
  3. Added environment variable: I've added an environment variable LOG_LEVEL with a value of info. This can be used by the application running in the container to control the logging level.
  4. 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. The DependsOn property ensures that the log group is created before the task definition.
  5. Improved log group configuration: I've added the RetentionInDays property to the LogGroup 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.