Managing Containerized Applications with ECS
Relevant source files
The following files were used as context for generating this wiki page:- packages/@aws-cdk/aws-ecs/lib/cluster.ts
- packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts
- packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts
- packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts
- packages/@aws-cdk/aws-ecs/CONTRIBUTING.md
- packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts
- packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts
- packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.ts
The AWS Cloud Development Kit (CDK) provides a powerful, multi-layered approach for defining and managing containerized applications using Amazon Elastic Container Service (ECS). This allows developers to define their infrastructure in code using familiar programming languages. The CDK offers different levels of abstraction, catering to various use cases from simple container deployments to complex, best-practice-oriented architectures.
The primary modules for working with ECS are:
@aws-cdk/aws-ecs: The core L2 construct library for defining fundamental ECS resources like clusters, task definitions, and services.@aws-cdk/aws-ecs-patterns: A library of higher-level constructs that create common container application architectures, such as load-balanced services, with minimal configuration.@aws-cdk-containers/ecs-service-extensions: A library promoting best practices through composable add-ons (extensions) for advanced configurations like service discovery, auto-scaling, and sidecars for logging and tracing.
Sources: packages/@aws-cdk/aws-ecs/CONTRIBUTING.md
Core ECS Constructs (@aws-cdk/aws-ecs)
This module provides the foundational building blocks for any ECS workload. You have fine-grained control over every aspect of your ECS resources.
ECS Component Relationship
The core components of an ECS setup are the Cluster, Task Definition, and Service. The Task Definition acts as a blueprint for your application, the Service maintains a specified number of instances of the Task Definition, and the Cluster is the logical grouping of tasks or services.
This diagram shows the relationship between the main ECS constructs provided by the CDK.
Task Definitions
A Task Definition is required to run Docker containers in Amazon ECS. It specifies aspects like which container images to use, CPU and memory allocation, launch type, networking mode, and IAM roles. The CDK supports task definitions for EC2, Fargate, and External (on-premises) launch types.
Ec2TaskDefinition
This construct is used for tasks that will run on a cluster of EC2 instances.
// Example of creating an Ec2TaskDefinition
const stack = new cdk.Stack();
const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', {
networkMode: ecs.NetworkMode.AWS_VPC,
});
Sources: packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts:43-45
ExternalTaskDefinition
This construct is used for tasks that will run on your on-premises server capacity registered to an ECS cluster. It has limitations compared to EC2/Fargate tasks, such as not supporting volumes or inference accelerators.
Sources: packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts:389-395, packages/@aws-cdk/aws-ecs/test/external/external-task-definition.test.ts:400-405
Container Definitions
Within a task definition, you define one or more containers. The addContainer method is used for this purpose.
Key Container Properties
| Property | Description |
|---|---|
image | The container image. Can be sourced from a public registry, ECR, or a local Docker asset. |
memoryLimitMiB | The amount of memory (in MiB) to reserve for the container. |
cpu | The number of cpu units to reserve for the container. |
logging | The log configuration for the container, such as AwsLogDriver. |
portMappings | The port mappings to expose on the container. |
environment | Environment variables to pass to the container. |
environmentFiles | One or more files containing environment variables. Can be sourced from local assets or an S3 bucket. |
secrets | Secrets to expose to the container from AWS Secrets Manager or SSM Parameter Store. |
healthCheck | The command and configuration for the container health check. |
command | The command that is passed to the container. |
Sources: packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts:223-268
Specifying Container Images
The CDK provides multiple ways to specify the source of a container image.
This diagram illustrates the factory methods for creating a ContainerImage instance.
-
From a Public Registry:
const image = ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample');Sources: packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts:184-187
-
From an ECR Repository:
const repo = new ecr.Repository(stack, 'myECRImage'); const image = ecs.ContainerImage.fromEcrRepository(repo, 'myTag');Sources: packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts:489-492
-
From a Local Asset: The CDK will build the Docker image from a local directory, push it to an ECR repository it creates, and reference it in the container definition.
const image = ecs.ContainerImage.fromAsset(path.join(__dirname, '..', 'demo-image'));Sources: packages/@aws-cdk/aws-ecs/test/ec2/ec2-task-definition.test.ts:619-621
Using Environment Files
You can provide environment variables to a container from files stored locally or in an S3 bucket. The CDK handles uploading local asset files to S3 and granting the necessary permissions.
// S3 bucket to host the environment file
const bucket = new s3.Bucket(stack, 'Bucket');
// Deploy a local file to the S3 bucket
new s3deployment.BucketDeployment(stack, 'EnvFileDeployment', {
destinationBucket: bucket,
sources: [s3deployment.Source.asset(path.join(__dirname, '../demo-envfiles'))],
});
// Reference files from a local asset and an S3 bucket
const containerDefinition = new ecs.ContainerDefinition(stack, 'Container', {
environmentFiles: [
ecs.EnvironmentFile.fromAsset(path.join(__dirname, '../demo-envfiles/test-envfile.env')),
ecs.EnvironmentFile.fromBucket(bucket, 'test-envfile.env'),
],
// ... other properties
});
Sources: packages/@aws-cdk/aws-ecs/test/ec2/integ.environment-file.ts:48-55
High-Level Patterns (@aws-cdk/aws-ecs-patterns)
For common architectural patterns, the @aws-cdk/aws-ecs-patterns library provides higher-level constructs that abstract away much of the boilerplate code. A prime example is ApplicationLoadBalancedFargateService.
ApplicationLoadBalancedFargateService
This construct creates a complete, load-balanced web service running on AWS Fargate. It automatically provisions a VPC (or uses an existing one), an ECS cluster, a task definition, a Fargate service, an Application Load Balancer, a target group, and a listener.
The diagram below shows the resources created by this single construct.
This diagram outlines the AWS resources provisioned by the ApplicationLoadBalancedFargateService construct.
Sources: packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts
Composable Extensions (@aws-cdk-containers/ecs-service-extensions)
This library introduces a powerful, composable pattern for building ECS services. It starts with a base Service and allows you to attach ServiceExtensions to add functionality like service discovery, load balancing, and observability sidecars. This promotes best practices and modularity.
The core idea is that extensions can modify the environment, the task definition, and the service itself.
Service and ServiceExtension Interaction
The Service construct acts as a container for ServiceExtensions. When an extension is added, it can interact with the parent service and other extensions to configure the overall application.
This class diagram shows the relationship between the base Service and the abstract ServiceExtension, along with some concrete implementations.
Sources: packages/@aws-cdk-containers/ecs-service-extensions/lib/service.ts, packages/@aws-cdk/aws-ecs/CONTRIBUTING.md
Conclusion
The AWS CDK offers a flexible and powerful framework for managing containerized applications on ECS. Developers can choose the level of abstraction that best suits their needs:
@aws-cdk/aws-ecsfor fine-grained control over individual ECS resources.@aws-cdk/aws-ecs-patternsfor quickly deploying common application architectures with sensible defaults.@aws-cdk-containers/ecs-service-extensionsfor building complex, best-practice-compliant services using a modular, composable approach.
This layered approach allows teams to start simple and add complexity as required, all within a unified infrastructure-as-code paradigm.