aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.47k stars 3.83k forks source link

aws_ecs: missing "awslogs-endpoint" option in awslogs driver #30877

Closed krystianhub closed 1 month ago

krystianhub commented 1 month ago

Describe the bug

I'm using the latest version of the AWS CDK for Java. I want to create an ECS container definition with an AWS CloudWatch driver pointing to an IPv6-friendly endpoint (https://docs.aws.amazon.com/general/latest/gr/cwl_region.html), which in my case is "logs.eu-west-1.api.aws".

The AWS logs driver supports an option called "awslogs-endpoint" as noted in the Docker documentation: https://docs.docker.com/config/containers/logging/awslogs/.

Here is a snippet showing how I'm trying to set up the AWS logs driver in my ECS container definition:

   coreServicesTask.addContainer("example",
                ContainerDefinitionOptions.builder()
                        .essential(true)
                        .image(ContainerImage.fromEcrRepository(repo, version))
                        .environment(envs)
                        .memoryReservationMiB(1024)
                        .logging(
                                LogDrivers.awsLogs(AwsLogDriverProps.builder()
                                        .logGroup(ecsLogGroup)
                                        .mode(AwsLogDriverMode.NON_BLOCKING)
                                        .streamPrefix(prefixName)
                                        .build())
                        )
                        .build()
        );

The AwsLogDriverProps class does not have an "awslogs-endpoint" property that I can configure, and I couldn't find any other way to add custom properties. This forces me to use the default IPv4-only endpoint for CloudWatch Logs, which unnecessarily increases the load on my NAT instance. This is despite the fact that my containers are running on EC2 instances with dedicated IPv6 addresses capable of using an egress-only internet gateway.

Expected Behavior

The AwsLogDriverProps class should have a property or setter for configuring a custom CloudWatch Logs endpoint, as described at https://docs.aws.amazon.com/general/latest/gr/cwl_region.html.

Current Behavior

The AwsLogDriverProps and LogDrivers.awsLogs do not allow for setting up a custom API endpoint.

Reproduction Steps

Set up the most basic ECS container definition and try configuring the AWS log driver using AwsLogDriverProps.

Possible Solution

Either add a new setter or allow access to the underlying Map<String, String> so I can add custom properties as needed without waiting for CDK to include them as part of the AwsLogDriverProps class.

Additional Information/Context

I tried accessing "Options" HashMap the following way:

// create containerDefinition object and then...

var awsLogDriverConfig = containerDef.getLogDriverConfig();
var awsLogsOptions = awsLogDriverConfig.getOptions();
awsLogsOptions.put("awslogs-endpoint", "logs.eu-west-1.api.aws");

However, it looks like getOptions() produces a deep clone of the underlying HashMap object because modifying it doesn't make a difference when running cdk diff/deploy/synth operations.

CDK CLI Version

2.149.0 (build c8e5924)

Framework Version

No response

Node.js Version

v20.15.1

OS

Fedora 40

Language

Java

Language Version

OpenJDK Runtime Environment Corretto-17.0.11.9.1 (build 17.0.11+9-LTS)

Other information

No response

ashishdhingra commented 1 month ago

@krystianhub Good morning. Thanks for opening the issue. Wanted to check if you were able to find any reference for awslogs-endpoint in AWS ECS documentation, which I might have missed. As a workaround, you could use escape hatch to add property override as shown below (code uses TypeScript language):

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as logs from 'aws-cdk-lib/aws-logs';

export class Issue30877Stack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create a cluster
    const vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 2 });

    const cluster = new ecs.Cluster(this, 'EcsCluster', { vpc });
    cluster.addCapacity('DefaultAutoScalingGroup', {
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MICRO)
    });

    // Create Task Definition
    const taskDefinition = new ecs.Ec2TaskDefinition(this, 'TaskDef');
    const container = taskDefinition.addContainer('web', {
      image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
      memoryLimitMiB: 256,
      logging: ecs.LogDriver.awsLogs({
        streamPrefix: 'testprefix',
        mode: ecs.AwsLogDriverMode.NON_BLOCKING,
        logGroup: new logs.LogGroup(this, 'AwsEcsLogGriverLogGroup')
      })
    });

    // Add proeprty override for awslogs-endpoint.
    const cfnTaskDefinition = taskDefinition.node.defaultChild as ecs.CfnTaskDefinition;
    cfnTaskDefinition.addPropertyOverride('ContainerDefinitions.0.LogConfiguration.Options.awslogs-endpoint', 'myendpoint');

    container.addPortMappings({
      containerPort: 80,
      hostPort: 8080,
      protocol: ecs.Protocol.TCP
    });

    // Create Service
    const service = new ecs.Ec2Service(this, "Service", {
      cluster,
      taskDefinition,
    });
  }
}

This generates the following TaskDefinition in synthesized CFN template:

  TaskDef54694570:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        - Essential: true
          Image: amazon/amazon-ecs-sample
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group:
                Ref: AwsEcsLogGriverLogGroup2AD9AEEC
              awslogs-stream-prefix: testprefix
              awslogs-region:
                Ref: AWS::Region
              mode: non-blocking
              awslogs-endpoint: myendpoint
          Memory: 256
          Name: web
          PortMappings:
            - ContainerPort: 80
              HostPort: 8080
              Protocol: tcp
      ExecutionRoleArn:
        Fn::GetAtt:
          - TaskDefExecutionRoleB4775C97
          - Arn
      Family: Issue30877StackTaskDefA91FAAFF
      NetworkMode: bridge
      RequiresCompatibilities:
        - EC2
      TaskRoleArn:
        Fn::GetAtt:
          - TaskDefTaskRole1EDB4A67
          - Arn
    Metadata:
      aws:cdk:path: Issue30877Stack/TaskDef/Resource

Equivalent Java CDK code would look something like below:

TaskDefinition taskDefinition = TaskDefinition.Builder.create(this, "TaskDefinition").build();
        taskDefinition.addContainer(...);
        CfnTaskDefinition cfnTaskDefinition = (CfnTaskDefinition)taskDefinition.getNode().getDefaultChild();
        cfnTaskDefinition.addPropertyOverride("ContainerDefinitions.0.LogConfiguration.Options.awslogs-endpoint", "myEndpoint");

Thanks, Ashish

krystianhub commented 1 month ago

Thank you for the advice; I didn't know about the addPropertyOverride trick.

Unfortunately, you're right— the awslogs-endpoint option isn't supported on ECS.

Invalid request provided: Create TaskDefinition: Log driver awslogs disallows options: awslogs-endpoint

Are there any plans to introduce this option now that CloudWatch Logs dual-stack endpoints are available?

ashishdhingra commented 1 month ago

Thank you for the advice; I didn't know about the addPropertyOverride trick.

Unfortunately, you're right— the awslogs-endpoint option isn't supported on ECS.


Invalid request provided: Create TaskDefinition: Log driver awslogs disallows options: awslogs-endpoint

Are there any plans to introduce this option now that CloudWatch Logs dual-stack endpoints are available?

@krystianhub Thanks for sharing the results. This is a question for ECS team. Please use feedback link on their documentation page. Normally new features should be in team's roadmap.

Now that it's confirmed that ECS doesn't support the requested option, please confirm if we could close this issue.

Thanks, Ashish

krystianhub commented 1 month ago

I will, thank you. You can close this ticket.

github-actions[bot] commented 1 month ago

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

aws-cdk-automation commented 1 month ago

Comments on closed issues and PRs are hard for our team to see. If you need help, please open a new issue that references this one.