From 1aea2438a610249d26a8e6995f0d5de7ec9a33a7 Mon Sep 17 00:00:00 2001 From: Gabriel Dos Santos Date: Mon, 24 Feb 2025 15:07:42 -0500 Subject: [PATCH 1/2] Base impl for ecs fargate cdk --- src/ecs/constants.ts | 48 +++ src/ecs/environment.ts | 70 ++++ src/ecs/fargate/constants.ts | 44 +++ src/ecs/fargate/datadog-ecs-fargate.ts | 369 +++++++++++++++++++ src/ecs/fargate/interfaces.ts | 35 ++ src/ecs/interfaces.ts | 108 ++++++ src/ecs/utils.ts | 94 +++++ src/index.ts | 6 + src/sample/ecs_fargate/ecs_fargate.ts | 132 +++++++ src/sample/ecs_fargate/index.ts | 53 +++ src/sample/{ => lambda}/index.ts | 22 +- src/sample/{ => lambda}/index_cdk_v2_test.ts | 6 +- src/sample/lambda/{ => python}/hello_py.py | 0 src/sample/lambda_nodejs/hello_node.js | 13 - test/ecs/environment.spec.ts | 59 +++ 15 files changed, 1032 insertions(+), 27 deletions(-) create mode 100644 src/ecs/constants.ts create mode 100644 src/ecs/environment.ts create mode 100644 src/ecs/fargate/constants.ts create mode 100644 src/ecs/fargate/datadog-ecs-fargate.ts create mode 100644 src/ecs/fargate/interfaces.ts create mode 100644 src/ecs/interfaces.ts create mode 100644 src/ecs/utils.ts create mode 100644 src/sample/ecs_fargate/ecs_fargate.ts create mode 100644 src/sample/ecs_fargate/index.ts rename src/sample/{ => lambda}/index.ts (85%) rename src/sample/{ => lambda}/index_cdk_v2_test.ts (89%) rename src/sample/lambda/{ => python}/hello_py.py (100%) delete mode 100644 src/sample/lambda_nodejs/hello_node.js create mode 100644 test/ecs/environment.spec.ts diff --git a/src/ecs/constants.ts b/src/ecs/constants.ts new file mode 100644 index 000000000..6e8f1dc1a --- /dev/null +++ b/src/ecs/constants.ts @@ -0,0 +1,48 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +import { Duration } from "aws-cdk-lib"; +import { DatadogECSBaseProps, Cardinality } from "./interfaces"; + +/** + * Default props for the Datadog ECS Fargate construct + */ +export const DatadogEcsBaseDefaultProps: DatadogECSBaseProps = { + registry: "public.ecr.aws/datadog/agent", + imageVersion: "latest", + memoryLimitMiB: 1024, + + site: "datadoghq.com", + logLevel: "INFO", + + enableAPM: true, + enableAPMSocket: true, + + enableDogstatsd: true, + enableDogstatsdSocket: true, + enableDogstatsdOriginDetection: false, + dogstatsdCardinality: Cardinality.LOW, + + enableLogCollection: false, + enableASM: false, + enableCWS: false, + + isHealthCheckEnabled: true, + datadogHealthCheck: { + command: ["agent", "health"], + interval: Duration.seconds(5), + retries: 3, + startPeriod: Duration.seconds(15), + timeout: Duration.seconds(5), + }, +}; + +/** + * Default CWS entrypoint prefix for application containers + */ +export const entryPointPrefixCWS = ["/cws-instrumentation-volume/cws-instrumentation", "trace", "--"]; diff --git a/src/ecs/environment.ts b/src/ecs/environment.ts new file mode 100644 index 000000000..504844965 --- /dev/null +++ b/src/ecs/environment.ts @@ -0,0 +1,70 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +export class EnvVarManager { + private envVars: Record = {}; + private overwrittenKeys: Set = new Set(); + + constructor(defaultEnvVars: Record = {}) { + this.addAll(defaultEnvVars); + } + + /** + * Adds an environment variable if the value is not undefined. + * If the key already exists, it records that it has been overwritten. + */ + add(key: string, value: string | undefined): void { + if (value === undefined) { + return; + } + if (this.envVars.hasOwnProperty(key)) { + this.overwrittenKeys.add(key); + } + this.envVars[key] = value; + } + + /** + * Adds all environment variables from a record. + */ + addAll(envVars: Record | undefined): void { + if (envVars === undefined) { + return; + } + for (const [key, value] of Object.entries(envVars)) { + this.add(key, value); + } + } + + /** + * Retrieves an environment variable by key. + */ + retrieve(key: string): string | undefined { + return this.envVars[key]; + } + + /** + * Returns all stored environment variables. + */ + retrieveAll(): Record { + return { ...this.envVars }; + } + + /** + * Returns a list of keys that have been overwritten. + */ + retrieveOverwrittenKeys(): string[] { + return Array.from(this.overwrittenKeys); + } + + /** + * Returns a string representation of the environment variables. + */ + toString(): string { + return JSON.stringify(this.envVars); + } +} diff --git a/src/ecs/fargate/constants.ts b/src/ecs/fargate/constants.ts new file mode 100644 index 000000000..9a95014e7 --- /dev/null +++ b/src/ecs/fargate/constants.ts @@ -0,0 +1,44 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +import { Duration } from "aws-cdk-lib"; +import { DatadogECSFargateLogDriverProps, DatadogECSFargateProps } from "./interfaces"; +import { DatadogEcsBaseDefaultProps } from "../constants"; + +/** + * Default log driver configuration for ECS Fargate + */ +export const DatadogECSFargateLogDriverDefaultProps: DatadogECSFargateLogDriverProps = { + hostEndpoint: "http-intake.logs.datadoghq.com", + registry: "public.ecr.aws/aws-observability/aws-for-fluent-bit", + imageVersion: "stable", +}; + +/** + * Default environment variables for the Agent in Fargate Tasks + */ +export const FargateDefaultEnvVars = { + DD_ECS_TASK_COLLECTION_ENABLED: "true", + ECS_FARGATE: "true", +}; + +/** + * Default props for the Datadog ECS Fargate construct + */ +export const DatadogEcsFargateDefaultProps: DatadogECSFargateProps = { + ...DatadogEcsBaseDefaultProps, + logDriverConfiguration: DatadogECSFargateLogDriverDefaultProps, + isLogRouterHealthCheckEnabled: false, + logRouterHealthCheck: { + command: ["curl -f http://127.0.0.1:2020/api/v1/health || exit 1"], + interval: Duration.seconds(5), + retries: 3, + startPeriod: Duration.seconds(15), + timeout: Duration.seconds(5), + }, +}; diff --git a/src/ecs/fargate/datadog-ecs-fargate.ts b/src/ecs/fargate/datadog-ecs-fargate.ts new file mode 100644 index 000000000..e7f277254 --- /dev/null +++ b/src/ecs/fargate/datadog-ecs-fargate.ts @@ -0,0 +1,369 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +import { + ContainerImage, + Protocol, + ContainerDefinition, + FirelensLogRouterType, + TaskDefinition, + FargateTaskDefinition, +} from "aws-cdk-lib/aws-ecs"; +import * as ecs from "aws-cdk-lib/aws-ecs"; +import { CfnTaskDefinition } from "aws-cdk-lib/aws-ecs/lib/ecs.generated"; +import * as iam from "aws-cdk-lib/aws-iam"; +import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; +import { Construct } from "constructs"; +import log from "loglevel"; +import { DatadogEcsFargateDefaultProps, FargateDefaultEnvVars } from "./constants"; +import { + DatadogECSFargateInternalProps, + DatadogECSFargateProps, + entryPointPrefixCWS, + isOperatingSystemLinux, + mergeFargateProps, + validateECSProps, +} from "../../index"; +import { EnvVarManager } from "../environment"; + +export class DatadogEcsFargate extends Construct { + scope: Construct; + props: DatadogECSFargateProps; + + constructor(scope: Construct, id: string, props: DatadogECSFargateProps) { + if (process.env.DD_CONSTRUCT_DEBUG_LOGS?.toLowerCase() === "true") { + log.setLevel("debug"); + } + super(scope, id); + this.scope = scope; + this.props = mergeFargateProps(DatadogEcsFargateDefaultProps, props); + } + + public editFargateTasks(taskDefinitions: FargateTaskDefinition[], props: DatadogECSFargateProps = {}): void { + taskDefinitions.forEach((taskDefinition) => { + this.editFargateTask(taskDefinition, props); + }); + } + + private getCompleteProps( + task: FargateTaskDefinition, + taskLevelProps: DatadogECSFargateProps, + ): DatadogECSFargateInternalProps { + const mergedProps = mergeFargateProps(this.props, taskLevelProps); + const isLinux = isOperatingSystemLinux(task); + const completeProps = { + ...mergedProps, + envVarManager: this.configureEnvVarManager(mergedProps), + isLinux: isLinux, + }; + return completeProps; + } + + private configureEnvVarManager(props: DatadogECSFargateProps): EnvVarManager { + const envVarManager = new EnvVarManager(FargateDefaultEnvVars); + envVarManager.addAll(props.environmentVariables); + + // TODO: Check if there are any other envvars that need to be added + envVarManager.add("DD_API_KEY", props.apiKey); + envVarManager.add("DD_ENV", props.env); + envVarManager.add("DD_SERVICE", props.service); + envVarManager.add("DD_VERSION", props.version); + envVarManager.add("DD_TAGS", props.globalTags); + + if (props.enableDogstatsdOriginDetection) { + envVarManager.add("DD_DOGSTATSD_ORIGIN_DETECTION", "true"); + envVarManager.add("DD_DOGSTATSD_ORIGIN_DETECTION_CLIENT", "true"); + } + + return envVarManager; + } + + /** + * Edits the task definition to include the Datadog agent + * @param task The fargate task definition to be instrumented + * @param taskProps Optional properties for task specific configuration + */ + private editFargateTask(task: FargateTaskDefinition, taskProps: DatadogECSFargateProps = {}): void { + // Setting up props + const props = this.getCompleteProps(task, taskProps); + validateECSProps(props); + + // Add container needed configuration to all application containers + this.applyAgentConfiguration(task, props); + + // Create the agent container + const agentContainer = this.createAgentContainer(task, props); + + // Make the application containers depend on the agent container + if (props.isDatadogEssential && props.isHealthCheckEnabled) { + this.addContainerDependency(task, agentContainer); + } + + if (props.enableLogCollection && props.isLinux) { + // Add the log container configuration to all application containers + agent container + this.applyLinuxLogConfiguration(task, props); + + // Create the log container + const logContainer = this.createLogContainer(task, props); + + // Make the application containers + agent container depend on the log container + if (props.isLogRouterHealthCheckEnabled) { + this.addContainerDependency(task, logContainer); + } + } + + // Required permissions for Agent's ecs_fargate check + this.configureEcsPolicies(task); + } + + private addContainerDependency(task: TaskDefinition, container: ContainerDefinition) { + const containerDefinitions = task.node.children.filter( + (c) => c instanceof ecs.ContainerDefinition, + ) as ecs.ContainerDefinition[]; + for (const containerDefinition of containerDefinitions) { + if (containerDefinition === container) { + continue; + } + + // Only add a dependency if the agent is essential and health checks are enabled + containerDefinition.addContainerDependencies({ + container: container, + condition: ecs.ContainerDependencyCondition.HEALTHY, + }); + } + } + + private applyAgentConfiguration(task: FargateTaskDefinition, props: DatadogECSFargateInternalProps) { + const requiresSocket = + (props.enableDogstatsd && props.enableDogstatsdSocket) || (props.enableAPM && props.enableAPMSocket); + const requiresProtocol = + (props.enableDogstatsd && !props.enableDogstatsdSocket) || (props.enableAPM && !props.enableAPMSocket); + + // Task-level configurations + if (requiresSocket && props.isLinux) { + task.addVolume({ + name: "dd-sockets", + }); + } + + let cwsContainer: ecs.ContainerDefinition; + if (props.enableCWS) { + cwsContainer = task.addContainer("cws-instrumentation", { + containerName: "cws-instrumentation-init", + image: ContainerImage.fromRegistry("datadog/cws-instrumentation:latest"), + user: "0", + essential: false, + command: ["/cws-instrumentation", "setup", "--cws-volume-mount", "/cws-instrumentation-volume"], + }); + task.addVolume({ + name: "cws-instrumentation-volume", + }); + cwsContainer.addMountPoints({ + sourceVolume: "cws-instrumentation-volume", + containerPath: "/cws-instrumentation-volume", + readOnly: false, + }); + } + + const containerDefinitions = task.node.children.filter( + (c) => c instanceof ecs.ContainerDefinition, + ) as ecs.ContainerDefinition[]; + for (const container of containerDefinitions) { + if (props.isLinux) { + // DogstatsD + APM configuration UDS + if (requiresSocket) { + container.addMountPoints({ + containerPath: "/var/run/datadog", + sourceVolume: "dd-sockets", + readOnly: false, + }); + if (props.enableDogstatsd && props.enableDogstatsdSocket) { + container.addEnvironment("DD_DOGSTATSD_URL", "unix:///var/run/datadog/dsd.socket"); + } + if (props.enableAPM && props.enableAPMSocket) { + container.addEnvironment("DD_TRACE_AGENT_URL", "unix:///var/run/datadog/apm.socket"); + } + } + } else { + // Windows configuration + // container.addMountPoints({ + // containerPath: "", + // sourceVolume: "dd-sockets", + // readOnly: false, + // }); + // if (props.enableDogStatsdPipe) { + // container.addEnvironment("DD_DOGSTATSD_PIPE", "\\\\.\\pipe\\datadog.dsd.socket"); + // } + // if (props.enableTracePipe) { + // container.addEnvironment("DD_TRACE_AGENT_PIPE", "\\\\.\\pipe\\datadog.apm.socket"); + // } + } + + // Backup DogstatsD + APM configuration for UDP/TCP + // Works for both Linux and Windows environments + if (requiresProtocol) { + container.addEnvironment("DD_AGENT_HOST", "127.0.0.1"); + } + + // CWS Configuration: + if (props.enableCWS) { + const containerProps = (container as any).props as ecs.ContainerDefinitionProps; + if ( + containerProps === undefined || + containerProps.entryPoint === undefined || + containerProps.entryPoint.length === 0 + ) { + log.debug("No entrypoint found. Not adding CWS configuration."); + continue; + } + + const currentEntryPoint = containerProps.entryPoint as string[]; + currentEntryPoint.unshift(...entryPointPrefixCWS); + (container as any).props.entryPoint = currentEntryPoint; + + if (container.linuxParameters === undefined) { + (container as any).linuxParameters = new ecs.LinuxParameters(this.scope, "LinuxParameters", {}); + } + container.linuxParameters?.addCapabilities(ecs.Capability.SYS_PTRACE); + + container.addMountPoints({ + sourceVolume: "cws-instrumentation-volume", + containerPath: "/cws-instrumentation-volume", + readOnly: false, + }); + + container.addContainerDependencies({ + container: cwsContainer!, + condition: ecs.ContainerDependencyCondition.SUCCESS, + }); + } + + // Universal Service Tagging configuration: + if (props.env) { + container.addEnvironment("DD_ENV", props.env); + container.addDockerLabel("com.datadoghq.tags.env", props.env); + } + if (props.service) { + container.addEnvironment("DD_SERVICE", props.service); + container.addDockerLabel("com.datadoghq.tags.service", props.service); + } + if (props.version) { + container.addEnvironment("DD_VERSION", props.version); + container.addDockerLabel("com.datadoghq.tags.version", props.version); + } + } + } + + private createAgentContainer(task: TaskDefinition, props: DatadogECSFargateInternalProps): ContainerDefinition { + const agentContainer = task.addContainer(`datadog-agent-${task.family}`, { + image: ContainerImage.fromRegistry(`${props.registry}:${props.imageVersion}`), + containerName: "datadog-agent", + environment: props.envVarManager.retrieveAll(), + essential: props.isDatadogEssential, + healthCheck: props.isHealthCheckEnabled ? props.datadogHealthCheck : undefined, + secrets: this.getSecretApiKey(props), + portMappings: [ + { + containerPort: 8125, + hostPort: 8125, + protocol: Protocol.UDP, + }, + { + containerPort: 8126, + hostPort: 8126, + protocol: Protocol.TCP, + }, + ], + memoryLimitMiB: props.memoryLimitMiB, + // workingDirectory: props.isLinux ? undefined : "C:\\", + }); + + // DogStatsD/Trace UDS configuration + if ((props.enableDogstatsd && props.enableDogstatsdSocket) || (props.enableAPM && props.enableAPMSocket)) { + if (props.isLinux) { + agentContainer.addMountPoints({ + containerPath: "/var/run/datadog", + sourceVolume: "dd-sockets", + readOnly: false, + }); + } + } + + return agentContainer; + } + + private createLogContainer(task: TaskDefinition, props: DatadogECSFargateInternalProps): ContainerDefinition { + const fluentbitContainer = task.addFirelensLogRouter(`fluentBit-${task.family}`, { + containerName: "log-router", + image: ecs.ContainerImage.fromRegistry( + `${props.logDriverConfiguration!.registry}:${props.logDriverConfiguration!.imageVersion}`, + ), + essential: props.isLogRouterHealthCheckEnabled, + firelensConfig: { + type: FirelensLogRouterType.FLUENTBIT, + options: { + enableECSLogMetadata: true, + }, + }, + memoryReservationMiB: 50, + healthCheck: props.isLogRouterHealthCheckEnabled ? props.logRouterHealthCheck : undefined, + }); + return fluentbitContainer; + } + + /** + * Applies the fluentbit / awsfirelens configuration to the task definition + * to support log forwarding to datadog. + * @param task + */ + private applyLinuxLogConfiguration(task: TaskDefinition, props: DatadogECSFargateInternalProps) { + const cfnTaskDefinition = task.node.defaultChild as CfnTaskDefinition; + const numberOfContainerDefinitions = task.node.children.filter((c) => c instanceof ecs.ContainerDefinition).length; + for (let index = 0; index < numberOfContainerDefinitions; index++) { + cfnTaskDefinition.addPropertyOverride(`ContainerDefinitions.${index}.LogConfiguration.LogDriver`, "awsfirelens"); + cfnTaskDefinition.addPropertyOverride(`ContainerDefinitions.${index}.LogConfiguration.Options`, { + Name: "datadog", + Host: props.logDriverConfiguration!.hostEndpoint, + dd_service: props.logDriverConfiguration!.serviceName, + dd_source: props.logDriverConfiguration!.sourceName, + dd_message_key: props.logDriverConfiguration!.messageKey, + dd_tags: props.envVarManager.retrieve("DD_TAGS"), //TODO: Should we manually add others like region, env, service, version, etc? + TLS: "on", + provider: "ecs", + apikey: props.apiKey, + retry_limit: "2", + }); + if (props.apiKeySecret) { + cfnTaskDefinition.addPropertyOverride(`ContainerDefinitions.${index}.LogConfiguration.SecretOptions`, [ + { Name: "apikey", ValueFrom: props.apiKeySecret.secretArn }, + ]); + } + } + // TODO: include configuraiton for log filtering (including/excluding logs) + } + + private getSecretApiKey(props: DatadogECSFargateProps): Record | undefined { + if (props.apiKeySecret) { + return { DD_API_KEY: ecs.Secret.fromSecretsManager(props.apiKeySecret) }; + } else if (props.apiKeySecretArn) { + const secret = secretsmanager.Secret.fromSecretCompleteArn(this.scope, "DatadogSecret", props.apiKeySecretArn); + return { DD_API_KEY: ecs.Secret.fromSecretsManager(secret) }; + } else { + return undefined; + } + } + + private configureEcsPolicies(task: TaskDefinition) { + task.addToTaskRolePolicy( + new iam.PolicyStatement({ + actions: ["ecs:ListClusters", "ecs:ListContainerInstances", "ecs:DescribeContainerInstances"], + resources: ["*"], + }), + ); + } +} diff --git a/src/ecs/fargate/interfaces.ts b/src/ecs/fargate/interfaces.ts new file mode 100644 index 000000000..9a6b4d8a1 --- /dev/null +++ b/src/ecs/fargate/interfaces.ts @@ -0,0 +1,35 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +import { HealthCheck } from "aws-cdk-lib/aws-ecs"; +import { DatadogECSBaseProps, EnvVarManager } from "../../index"; + +export interface DatadogECSFargateProps extends DatadogECSBaseProps { + readonly logDriverConfiguration?: DatadogECSFargateLogDriverProps; + readonly logRouterHealthCheck?: HealthCheck; + readonly isLogRouterHealthCheckEnabled?: boolean; +} + +export interface DatadogECSFargateLogDriverProps { + readonly registry?: string; + readonly hostEndpoint?: string; + readonly messageKey?: string; + readonly serviceName?: string; + readonly sourceName?: string; + readonly imageVersion?: string; +} + +/** + * Internal props for the Datadog ECS Fargate construct + */ +export interface DatadogECSFargateInternalProps extends DatadogECSFargateProps { + readonly envVarManager: EnvVarManager; + readonly isLinux: boolean; + readonly entryPointsDefined?: boolean; + readonly entryPoint?: string[]; +} diff --git a/src/ecs/interfaces.ts b/src/ecs/interfaces.ts new file mode 100644 index 000000000..92d31b36c --- /dev/null +++ b/src/ecs/interfaces.ts @@ -0,0 +1,108 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +import { HealthCheck } from "aws-cdk-lib/aws-ecs"; +import * as secrets from "aws-cdk-lib/aws-secretsmanager"; + +export interface DatadogECSBaseProps { + // Must define at least 1 source for the API key + readonly apiKey?: string; + readonly apiKeySecret?: secrets.ISecret; + readonly apiKeySecretArn?: string; + + // Agent container configuration + readonly registry?: string; + readonly imageVersion?: string; + readonly memoryLimitMiB?: number; + + readonly clusterName?: string; + readonly site?: string; + readonly logLevel?: string; + + readonly isDatadogEssential?: boolean; + readonly isHealthCheckEnabled?: boolean; + readonly datadogHealthCheck?: HealthCheck; + + /** + * Datadog Agent environment variables + */ + readonly environmentVariables?: Record; + + // Features to enable + readonly enableLogCollection?: boolean; + readonly enableASM?: boolean; + + /** + * Enables Dogstatsd custom metrics collection + * * * * * * * * * * * * * * * * * * * * * * * + */ + readonly enableDogstatsd?: boolean; + /** + * Enables Dogstatsd origin detection + */ + readonly enableDogstatsdOriginDetection?: boolean; + /** + * Controls the cardinality of custom dogstatsd metrics + */ + readonly dogstatsdCardinality?: Cardinality; + /** + * Enables Dogstatsd traffic over Unix Domain Socket. + * Falls back to UDP configuration for application containers when disabled + */ + readonly enableDogstatsdSocket?: boolean; + + /** + * Enables APM traces collection + * * * * * * * * * * * * * * * * + */ + readonly enableAPM?: boolean; + /** + * Enables APM traces traffic over Unix Domain Socket. + * Falls back to TCP configuration for application containers when disabled + */ + readonly enableAPMSocket?: boolean; + + /** + * Enables CWS (Cloud Workload Security) + * * * * * * * * * * * * * * * * * * * * + */ + readonly enableCWS?: boolean; + + /** + * Enable USM (Universal Service Monitoring) + * * * * * * * * * * * * * * * * * * * * * * + */ + readonly enableUSM?: boolean; + /** + * The task environment name. Used for tagging (UST/USM) + */ + readonly env?: string; + /** + * The task service name. Used for tagging (UST/USM) + */ + readonly service?: string; + /** + * The task version. Used for tagging (UST/USM) + */ + readonly version?: string; + + /** + * Global tags to apply to all data sent by the Agent. + * Overrides any DD_TAGS values in environmentVariables + */ + readonly globalTags?: string; +} + +/** + * Cardinality of metrics + */ +export enum Cardinality { + LOW = "low", + ORCHESTRATOR = "orchestrator", + HIGH = "high", +} diff --git a/src/ecs/utils.ts b/src/ecs/utils.ts new file mode 100644 index 000000000..6a6426ac9 --- /dev/null +++ b/src/ecs/utils.ts @@ -0,0 +1,94 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +import * as ecs from "aws-cdk-lib/aws-ecs"; +import log from "loglevel"; +import { DatadogECSFargateProps } from "./fargate/interfaces"; +import { DatadogECSBaseProps } from "./interfaces"; + +export function mergeFargateProps( + lowerPrecedence: DatadogECSFargateProps, + higherPrecedence: DatadogECSFargateProps, +): DatadogECSFargateProps { + const newProps = { ...lowerPrecedence, ...higherPrecedence }; + newProps.logDriverConfiguration = { + ...lowerPrecedence.logDriverConfiguration, + ...higherPrecedence.logDriverConfiguration, + }; + return newProps; +} + +export function validateECSProps(props: DatadogECSBaseProps): void { + log.debug("Validating props..."); + + if (process.env.DD_CDK_BYPASS_SITE_VALIDATION) { + log.debug("Bypassing site validation..."); + return; + } + + const siteList: string[] = [ + "datadoghq.com", + "datadoghq.eu", + "us3.datadoghq.com", + "us5.datadoghq.com", + "ap1.datadoghq.com", + "ddog-gov.com", + ]; + if ( + props.site !== undefined && + !siteList.includes(props.site.toLowerCase()) && + !(props.site.startsWith("${Token[") && props.site.endsWith("]}")) && + !process.env.DD_CDK_BYPASS_SITE_VALIDATION + ) { + throw new Error( + "Warning: Invalid site URL. Must be either datadoghq.com, datadoghq.eu, us3.datadoghq.com, us5.datadoghq.com, ap1.datadoghq.com, or ddog-gov.com.", + ); + } + + // Agent configuration validation + if (props.registry === undefined) { + throw new Error("The `registry` property must be defined."); + } + if (props.imageVersion === undefined) { + throw new Error("The `version` property must be defined."); + } + + // Health check validation + if (props.isHealthCheckEnabled && props.datadogHealthCheck === undefined) { + throw new Error("The `datadogHealthCheck` property must be defined when `isHealthCheckEnabled` is true."); + } + if (props.isHealthCheckEnabled && props.datadogHealthCheck!.command === undefined) { + throw new Error("The `command` property must be defined in `datadogHealthCheck`."); + } + + // App Sec requires tracing + if (props.enableASM && !props.enableAPM) { + throw new Error("When `enableDatadogASM` is enabled, `enableDatadogTracing` must also be enabled."); + } + + // USM requires env, service, and version tags + if (props.enableUSM && (!props.env || !props.service || !props.version)) { + throw new Error("When `enableUSM` is enabled, `env`, `service`, and `version` must be defined."); + } +} + +export function isOperatingSystemLinux(task: ecs.TaskDefinition): boolean { + const cfnTaskDef = task.node.defaultChild as ecs.CfnTaskDefinition; + const runtimePlatform = cfnTaskDef.runtimePlatform as ecs.CfnTaskDefinition.RuntimePlatformProperty; + + if (runtimePlatform === undefined) { + // TODO: verify assumption if undefined OS, then Linux on Amazon ECS Fargate + return true; + } + + if (runtimePlatform.operatingSystemFamily === undefined) { + return true; + } + + return runtimePlatform.operatingSystemFamily === "LINUX"; +} diff --git a/src/index.ts b/src/index.ts index d7d755bee..fa2aa045c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ export * from "./datadog"; export * from "./datadog-lambda"; +export * from "./ecs/fargate/datadog-ecs-fargate"; export * from "./datadog-step-functions"; export * from "./layer"; export * from "./redirect"; @@ -18,3 +19,8 @@ export * from "./constants"; export * from "./interfaces"; export * from "./redirect"; export * from "./transport"; +export * from "./ecs/interfaces"; +export * from "./ecs/constants"; +export * from "./ecs/fargate/interfaces"; +export * from "./ecs/environment"; +export * from "./ecs/utils"; diff --git a/src/sample/ecs_fargate/ecs_fargate.ts b/src/sample/ecs_fargate/ecs_fargate.ts new file mode 100644 index 000000000..bb1d75476 --- /dev/null +++ b/src/sample/ecs_fargate/ecs_fargate.ts @@ -0,0 +1,132 @@ +import * as cdk from "aws-cdk-lib"; +import * as ec2 from "aws-cdk-lib/aws-ec2"; +import * as ecs from "aws-cdk-lib/aws-ecs"; +import * as iam from "aws-cdk-lib/aws-iam"; +import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; +// import * as autoscaling from 'aws-cdk-lib/aws-autoscaling'; +import { Construct } from "constructs"; + +export class EcsStackBase extends cdk.Stack { + public fargateTaskDefinitions: ecs.TaskDefinition[]; + public apiKeySecret: secretsmanager.Secret; + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + // Create a secret for the Datadog API key + const secret = new secretsmanager.Secret(this, "DatadogSecret-Source", { + secretName: "DatadogSecret-CDK", + description: "Datadog API key", + secretStringValue: cdk.SecretValue.unsafePlainText(process.env.DD_API_KEY!), + }); + this.apiKeySecret = secret; + + // Create a VPC with default configuration + const vpc = new ec2.Vpc(this, "EcsFargateVpc", { + maxAzs: 2, // Default is all AZs in region + }); + + // Create an ECS cluster + const cluster = new ecs.Cluster(this, "EcsFargateCDK", { + clusterName: "EcsFargateCDK", + vpc, + }); + + // const keyPair = ec2.KeyPair.fromKeyPairName(this, 'KeyPair', 'gabe.dossantos.rsa'); + + // cluster.addCapacity('DefaultAutoScalingGroup-Linux', { + // instanceType: new ec2.InstanceType('t3.medium'), + // minCapacity: 1, + // maxCapacity: 1, + // machineImage: ecs.EcsOptimizedImage.amazonLinux2(), + // vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + // associatePublicIpAddress: true, + // keyName: keyPair.keyPairName, + // }); + + // const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'WindowsAutoScalingGroup', { + // vpc, + // instanceType: new ec2.InstanceType('t3.large'), + // machineImage: ec2.MachineImage.latestWindows(ec2.WindowsVersion.WINDOWS_SERVER_2022_ENGLISH_FULL_BASE), + // minCapacity: 1, + // maxCapacity: 1, + // vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + // associatePublicIpAddress: true, + // keyName: keyPair.keyPairName, + // }); + + // // Attach the ASG to the ECS Cluster + // const capacityProvider = new ecs.AsgCapacityProvider(this, 'WindowsCapacityProvider', { + // autoScalingGroup, + // }); + + // cluster.addAsgCapacityProvider(capacityProvider); + + // Create an ECS task execution role + const executionRole = new iam.Role(this, "TaskExecutionRole", { + assumedBy: new iam.ServicePrincipal("ecs-tasks.amazonaws.com"), + managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AmazonECSTaskExecutionRolePolicy")], + }); + + // Create an ECS Fargate task definition with an nginx container + const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, "NginxTaskDef", { + memoryLimitMiB: 2048, + cpu: 256, + executionRole: executionRole, + runtimePlatform: { + operatingSystemFamily: ecs.OperatingSystemFamily.LINUX, + }, + }); + + // Add a dummy container to the task definition + fargateTaskDefinition.addContainer("NginxContainer", { + image: ecs.ContainerImage.fromRegistry("nginx:latest"), + essential: false, + entryPoint: ["/docker-entrypoint.sh"], + }); + + fargateTaskDefinition.addContainer("DogStatsD", { + image: ecs.ContainerImage.fromRegistry("ghcr.io/datadog/apps-dogstatsd:main"), + essential: false, + }); + + fargateTaskDefinition.addContainer("DatadogAPM", { + image: ecs.ContainerImage.fromRegistry("ghcr.io/datadog/apps-tracegen:main"), + essential: false, + }); + + // const ec2windows = new ecs.TaskDefinition(this, 'WindTaskDefEC2', { + // memoryMiB: '2048', + // cpu: '1024', + // executionRole: executionRole, + // compatibility: ecs.Compatibility.EC2, + // }); + // ec2windows.addContainer('WindowContEC2', { + // image: ecs.ContainerImage.fromRegistry('mcr.microsoft.com/dotnet/samples:aspnetapp-nanoserver-ltsc2022'), + // }); + + const fargateWindowsTaskDefinition = new ecs.FargateTaskDefinition(this, "WindowsTaskDef", { + memoryLimitMiB: 4096, + cpu: 2048, + executionRole: executionRole, + runtimePlatform: { + operatingSystemFamily: ecs.OperatingSystemFamily.WINDOWS_SERVER_2022_CORE, + }, + }); + + fargateWindowsTaskDefinition.addContainer("WindowsContainer", { + image: ecs.ContainerImage.fromRegistry("mcr.microsoft.com/dotnet/samples:aspnetapp-nanoserver-ltsc2022"), + }); + + // Create an ECS Fargate service (only Linux bc faster) + new ecs.FargateService(this, "NginxService", { + serviceName: "NginxService", + cluster, + taskDefinition: fargateTaskDefinition, + desiredCount: 1, + assignPublicIp: true, + enableExecuteCommand: true, // only for debugging: to enable ecs exec + }); + + this.fargateTaskDefinitions = [fargateTaskDefinition, fargateWindowsTaskDefinition]; + } +} diff --git a/src/sample/ecs_fargate/index.ts b/src/sample/ecs_fargate/index.ts new file mode 100644 index 000000000..964d39316 --- /dev/null +++ b/src/sample/ecs_fargate/index.ts @@ -0,0 +1,53 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed + * under the Apache License Version 2.0. + * + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2021 Datadog, Inc. + */ + +import { App, Environment, StackProps } from "aws-cdk-lib"; +import { EcsStackBase } from "./ecs_fargate"; +import { DatadogEcsFargate, DatadogECSFargateProps } from "../../index"; + +export class ExampleStack extends EcsStackBase { + constructor(scope: App, id: string, props?: StackProps) { + super(scope, id, props); + + // Define your task definitions to be monitored by Datadog + const fargateTaskDefinitions = this.fargateTaskDefinitions; + + // Configure your Datadog Agent + const datadogProps: DatadogECSFargateProps = { + apiKeySecret: this.apiKeySecret, + environmentVariables: { + DD_TAGS: "owner:gabedos, team:cont-p", + }, + logDriverConfiguration: { + serviceName: "gabe-service", + sourceName: "gabe-source", + }, + enableDogstatsd: true, + enableAPM: true, + enableCWS: true, + enableLogCollection: true, + env: "dev", + service: "gabe-service", + version: "1.0", + }; + + // Create the Datadog Agent configuration and apply to each task definition + const datadog = new DatadogEcsFargate(this, "Datadog", datadogProps); + + datadog.editFargateTasks(fargateTaskDefinitions); + } +} + +const app = new App(); +const env: Environment = { + account: process.env.CDK_DEFAULT_ACCOUNT || process.env.AWS_ACCOUNT_ID, + region: process.env.CDK_DEFAULT_REGION || process.env.AWS_REGION, +}; +const stack = new ExampleStack(app, "ExampleDatadogEcsStack", { env: env }); +console.log("Stack name: " + stack.stackName); +app.synth(); diff --git a/src/sample/index.ts b/src/sample/lambda/index.ts similarity index 85% rename from src/sample/index.ts rename to src/sample/lambda/index.ts index 4ccbb9c56..434b66807 100644 --- a/src/sample/index.ts +++ b/src/sample/lambda/index.ts @@ -13,27 +13,27 @@ import { LambdaRestApi, LogGroupLogDestination } from "aws-cdk-lib/aws-apigatewa import * as lambda from "aws-cdk-lib/aws-lambda"; import * as lambdaNodejs from "aws-cdk-lib/aws-lambda-nodejs"; import { LogGroup } from "aws-cdk-lib/aws-logs"; -import { DatadogLambda } from "../index"; +import { DatadogLambda } from "../../index"; export class ExampleStack extends Stack { constructor(scope: App, id: string, props?: StackProps) { super(scope, id, props); const lambdaFunction = new lambda.Function(this, "HelloHandler", { - runtime: lambda.Runtime.NODEJS_14_X, - code: lambda.Code.fromAsset("./src/sample/lambda"), + runtime: lambda.Runtime.NODEJS_20_X, + code: lambda.Code.fromAsset("./src/sample/lambda/python"), handler: "lambdaFunction.handler", }); const lambdaNodejsFunction = new lambdaNodejs.NodejsFunction(this, "NodeJSHandler", { - runtime: lambda.Runtime.NODEJS_14_X, - entry: "./src/sample/lambda_nodejs/hello_node.js", + runtime: lambda.Runtime.NODEJS_20_X, + entry: "./src/sample/lambda/nodejs/hello_node.js", handler: "handler", }); const lambdaPythonFunction = new lambdaPython.PythonFunction(this, "PythonHandler", { - runtime: lambda.Runtime.PYTHON_3_7, - entry: "./src/sample/lambda/", + runtime: lambda.Runtime.PYTHON_3_12, + entry: "./src/sample/lambda/python/", index: "hello_py.py", handler: "handler", }); @@ -48,8 +48,8 @@ export class ExampleStack extends Stack { }); const lambdaFunction1 = new lambda.Function(this, "HelloHandler1", { - runtime: lambda.Runtime.NODEJS_14_X, - code: lambda.Code.fromAsset("./src/sample/lambda"), + runtime: lambda.Runtime.NODEJS_20_X, + code: lambda.Code.fromAsset("./src/sample/lambda/python"), handler: "lambdaFunction.handler", }); @@ -62,8 +62,8 @@ export class ExampleStack extends Stack { }); const lambdaFunction2 = new lambda.Function(this, "HelloHandler2", { - runtime: lambda.Runtime.PYTHON_3_7, - code: lambda.Code.fromAsset("./src/sample/lambda"), + runtime: lambda.Runtime.PYTHON_3_12, + code: lambda.Code.fromAsset("./src/sample/lambda/python"), handler: "hello_py.handler", tracing: lambda.Tracing.ACTIVE, }); diff --git a/src/sample/index_cdk_v2_test.ts b/src/sample/lambda/index_cdk_v2_test.ts similarity index 89% rename from src/sample/index_cdk_v2_test.ts rename to src/sample/lambda/index_cdk_v2_test.ts index 33e7343b6..5acadcbdd 100644 --- a/src/sample/index_cdk_v2_test.ts +++ b/src/sample/lambda/index_cdk_v2_test.ts @@ -9,15 +9,15 @@ import { App, Stack, StackProps } from "aws-cdk-lib"; import * as lambda from "aws-cdk-lib/aws-lambda"; import * as lambdaNodejs from "aws-cdk-lib/aws-lambda-nodejs"; -import { DatadogLambda } from "../index"; +import { DatadogLambda } from "../../index"; export class ExampleStack extends Stack { constructor(scope: App, id: string, props?: StackProps) { super(scope, id, props); const lambdaNodejsFunction = new lambdaNodejs.NodejsFunction(this, "NodeJSHandler", { - runtime: lambda.Runtime.NODEJS_14_X, - entry: "./src/sample/lambda_nodejs/hello_node.js", + runtime: lambda.Runtime.NODEJS_20_X, + entry: "./src/sample/lambda/nodejs/hello_node.js", handler: "handler", }); diff --git a/src/sample/lambda/hello_py.py b/src/sample/lambda/python/hello_py.py similarity index 100% rename from src/sample/lambda/hello_py.py rename to src/sample/lambda/python/hello_py.py diff --git a/src/sample/lambda_nodejs/hello_node.js b/src/sample/lambda_nodejs/hello_node.js deleted file mode 100644 index 3cf3b3d50..000000000 --- a/src/sample/lambda_nodejs/hello_node.js +++ /dev/null @@ -1,13 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed -// under the Apache License Version 2.0. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2021 Datadog, Inc. - -exports.handler = async function (event) { - console.log("request:", JSON.stringify(event, undefined, 2)); - return { - statusCode: 200, - headers: { "Content-Type": "text/plain" }, - body: `Hello, CDK Nodejs! You've hit ${event.path}\n`, - }; -}; diff --git a/test/ecs/environment.spec.ts b/test/ecs/environment.spec.ts new file mode 100644 index 000000000..c15053845 --- /dev/null +++ b/test/ecs/environment.spec.ts @@ -0,0 +1,59 @@ +import { EnvVarManager } from "../../src"; + +describe("EnvVarManager", () => { + let envVarManager: EnvVarManager; + + beforeEach(() => { + envVarManager = new EnvVarManager(); + }); + + it("should add an environment variable", () => { + envVarManager.add("KEY1", "value1"); + expect(envVarManager.retrieve("KEY1")).toBe("value1"); + }); + + it("should not add an environment variable if the value is undefined", () => { + envVarManager.add("KEY1", undefined); + expect(envVarManager.retrieve("KEY1")).toBeUndefined(); + }); + + it("should overwrite an existing environment variable and record the key", () => { + envVarManager.add("KEY1", "value1"); + envVarManager.add("KEY1", "value2"); + expect(envVarManager.retrieve("KEY1")).toBe("value2"); + expect(envVarManager.retrieveOverwrittenKeys()).toContain("KEY1"); + }); + + it("should add all environment variables from a record", () => { + const envVars = { KEY1: "value1", KEY2: "value2" }; + envVarManager.addAll(envVars); + expect(envVarManager.retrieve("KEY1")).toBe("value1"); + expect(envVarManager.retrieve("KEY2")).toBe("value2"); + }); + + it("should return all stored environment variables", () => { + const envVars = { KEY1: "value1", KEY2: "value2" }; + envVarManager.addAll(envVars); + expect(envVarManager.retrieveAll()).toEqual(envVars); + }); + + it("should return a list of keys that have been overwritten", () => { + envVarManager.add("KEY1", "value1"); + envVarManager.add("KEY1", "value2"); + envVarManager.add("KEY2", "value3"); + envVarManager.add("KEY2", "value4"); + expect(envVarManager.retrieveOverwrittenKeys()).toEqual(["KEY1", "KEY2"]); + }); + + it("should return a string representation of the environment variables", () => { + const envVars = { KEY1: "value1", KEY2: "value2" }; + envVarManager.addAll(envVars); + expect(envVarManager.toString()).toBe(JSON.stringify(envVars)); + }); + + it("should initialize with default environment variables", () => { + const defaultEnvVars = { KEY1: "value1", KEY2: "value2" }; + envVarManager = new EnvVarManager(defaultEnvVars); + expect(envVarManager.retrieveAll()).toEqual(defaultEnvVars); + }); +}); From 7cf5834a8b4c7b0fdc0cb29fb46a005288154426 Mon Sep 17 00:00:00 2001 From: Gabriel Dos Santos Date: Tue, 25 Feb 2025 18:30:31 -0500 Subject: [PATCH 2/2] Simplying imports and cleaning comments --- src/ecs/fargate/datadog-ecs-fargate.ts | 17 +++++----- src/ecs/fargate/interfaces.ts | 3 +- src/index.ts | 7 ++-- src/sample/ecs_fargate/ecs_fargate.ts | 46 ++------------------------ 4 files changed, 16 insertions(+), 57 deletions(-) diff --git a/src/ecs/fargate/datadog-ecs-fargate.ts b/src/ecs/fargate/datadog-ecs-fargate.ts index e7f277254..b71061c3d 100644 --- a/src/ecs/fargate/datadog-ecs-fargate.ts +++ b/src/ecs/fargate/datadog-ecs-fargate.ts @@ -21,15 +21,11 @@ import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager"; import { Construct } from "constructs"; import log from "loglevel"; import { DatadogEcsFargateDefaultProps, FargateDefaultEnvVars } from "./constants"; -import { - DatadogECSFargateInternalProps, - DatadogECSFargateProps, - entryPointPrefixCWS, - isOperatingSystemLinux, - mergeFargateProps, - validateECSProps, -} from "../../index"; +import { DatadogECSFargateInternalProps } from "./interfaces"; +import { DatadogECSFargateProps } from "../../index"; +import { entryPointPrefixCWS } from "../constants"; import { EnvVarManager } from "../environment"; +import { isOperatingSystemLinux, mergeFargateProps, validateECSProps } from "../utils"; export class DatadogEcsFargate extends Construct { scope: Construct; @@ -80,6 +76,11 @@ export class DatadogEcsFargate extends Construct { envVarManager.add("DD_DOGSTATSD_ORIGIN_DETECTION_CLIENT", "true"); } + if (props.enableCWS) { + envVarManager.add("DD_RUNTIME_SECURITY_CONFIG_ENABLED", "true"); + envVarManager.add("DD_RUNTIME_SECURITY_CONFIG_EBPFLESS_ENABLED", "true"); + } + return envVarManager; } diff --git a/src/ecs/fargate/interfaces.ts b/src/ecs/fargate/interfaces.ts index 9a6b4d8a1..72690281b 100644 --- a/src/ecs/fargate/interfaces.ts +++ b/src/ecs/fargate/interfaces.ts @@ -7,7 +7,8 @@ */ import { HealthCheck } from "aws-cdk-lib/aws-ecs"; -import { DatadogECSBaseProps, EnvVarManager } from "../../index"; +import { EnvVarManager } from "../environment"; +import { DatadogECSBaseProps } from "../interfaces"; export interface DatadogECSFargateProps extends DatadogECSBaseProps { readonly logDriverConfiguration?: DatadogECSFargateLogDriverProps; diff --git a/src/index.ts b/src/index.ts index fa2aa045c..0b7c4e8a7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,6 @@ export * from "./datadog"; export * from "./datadog-lambda"; -export * from "./ecs/fargate/datadog-ecs-fargate"; export * from "./datadog-step-functions"; export * from "./layer"; export * from "./redirect"; @@ -20,7 +19,5 @@ export * from "./interfaces"; export * from "./redirect"; export * from "./transport"; export * from "./ecs/interfaces"; -export * from "./ecs/constants"; -export * from "./ecs/fargate/interfaces"; -export * from "./ecs/environment"; -export * from "./ecs/utils"; +export * from "./ecs/fargate/datadog-ecs-fargate"; +export { DatadogECSFargateProps, DatadogECSFargateLogDriverProps } from "./ecs/fargate/interfaces"; diff --git a/src/sample/ecs_fargate/ecs_fargate.ts b/src/sample/ecs_fargate/ecs_fargate.ts index bb1d75476..fe5f8145b 100644 --- a/src/sample/ecs_fargate/ecs_fargate.ts +++ b/src/sample/ecs_fargate/ecs_fargate.ts @@ -22,7 +22,7 @@ export class EcsStackBase extends cdk.Stack { // Create a VPC with default configuration const vpc = new ec2.Vpc(this, "EcsFargateVpc", { - maxAzs: 2, // Default is all AZs in region + maxAzs: 2, }); // Create an ECS cluster @@ -31,44 +31,14 @@ export class EcsStackBase extends cdk.Stack { vpc, }); - // const keyPair = ec2.KeyPair.fromKeyPairName(this, 'KeyPair', 'gabe.dossantos.rsa'); - - // cluster.addCapacity('DefaultAutoScalingGroup-Linux', { - // instanceType: new ec2.InstanceType('t3.medium'), - // minCapacity: 1, - // maxCapacity: 1, - // machineImage: ecs.EcsOptimizedImage.amazonLinux2(), - // vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, - // associatePublicIpAddress: true, - // keyName: keyPair.keyPairName, - // }); - - // const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'WindowsAutoScalingGroup', { - // vpc, - // instanceType: new ec2.InstanceType('t3.large'), - // machineImage: ec2.MachineImage.latestWindows(ec2.WindowsVersion.WINDOWS_SERVER_2022_ENGLISH_FULL_BASE), - // minCapacity: 1, - // maxCapacity: 1, - // vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, - // associatePublicIpAddress: true, - // keyName: keyPair.keyPairName, - // }); - - // // Attach the ASG to the ECS Cluster - // const capacityProvider = new ecs.AsgCapacityProvider(this, 'WindowsCapacityProvider', { - // autoScalingGroup, - // }); - - // cluster.addAsgCapacityProvider(capacityProvider); - // Create an ECS task execution role const executionRole = new iam.Role(this, "TaskExecutionRole", { assumedBy: new iam.ServicePrincipal("ecs-tasks.amazonaws.com"), managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AmazonECSTaskExecutionRolePolicy")], }); - // Create an ECS Fargate task definition with an nginx container - const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, "NginxTaskDef", { + // Create an ECS Fargate task definition + const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, "ExampleFargateTask", { memoryLimitMiB: 2048, cpu: 256, executionRole: executionRole, @@ -94,16 +64,6 @@ export class EcsStackBase extends cdk.Stack { essential: false, }); - // const ec2windows = new ecs.TaskDefinition(this, 'WindTaskDefEC2', { - // memoryMiB: '2048', - // cpu: '1024', - // executionRole: executionRole, - // compatibility: ecs.Compatibility.EC2, - // }); - // ec2windows.addContainer('WindowContEC2', { - // image: ecs.ContainerImage.fromRegistry('mcr.microsoft.com/dotnet/samples:aspnetapp-nanoserver-ltsc2022'), - // }); - const fargateWindowsTaskDefinition = new ecs.FargateTaskDefinition(this, "WindowsTaskDef", { memoryLimitMiB: 4096, cpu: 2048,