Public facing, load balanced website on EC2

Nathan Peck profile picture
Nathan Peck
Senior Developer Advocate at AWS

About

This pattern shows how to setup an AWS Cloud Development Kit (CDK) application for building a container image and deploying it to EC2 capacity, fronted by an Application Load Balancer that serves as the ingress for the application. The container application will be managed by Amazon Elastic Container Service (ECS).

Development Environment

To use this pattern you need TypeScript and Node. First, ensure that you have Node.js installed on your development machine. Then create the following files:

File: package.jsonLanguage: json
{
  "name": "ec2-service-with-alb",
  "version": "1.0.0",
  "description": "EC2 Service with Application Load Balancer",
  "private": true,
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "cdk": "cdk"
  },
  "license": "Apache-2.0",
  "devDependencies": {
    "@types/node": "^8.10.38",
    "aws-cdk": "*",
    "typescript": "~4.6.0"
  },
  "dependencies": {
    "aws-cdk-lib": "^2.0.0",
    "constructs": "^10.0.0"
  }
}

The files above serve the following purpose:

  • package.json - This file is used by NPM or Yarn to identify and install all the required dependencies:
  • tsconfig.json - Configures the TypeScript settings for the project:
  • cdk.json - Tells CDK what command to run, and provides a place to pass other contextual settings to CDK.

CDK Application

Now you can create an index.ts file that has the actual code for the CDK application:

File: index.tsLanguage: ts
import ecs = require('aws-cdk-lib/aws-ecs');
import ec2 = require('aws-cdk-lib/aws-ec2');
import elbv2 = require('aws-cdk-lib/aws-elasticloadbalancingv2');
import cdk = require('aws-cdk-lib');

const app = new cdk.App();
const stack = new cdk.Stack(app, 'sample-aws-ecs-integ-ecs');

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

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

// Create Task Definition
const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef');
const container = taskDefinition.addContainer('web', {
  image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
  memoryLimitMiB: 256,
});

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

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

// Create ALB
const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', {
  vpc,
  internetFacing: true
});
const listener = lb.addListener('PublicListener', { port: 80, open: true });

// Attach ALB to ECS Service
listener.addTargets('ECS', {
  port: 8080,
  targets: [service.loadBalancerTarget({
    containerName: 'web',
    containerPort: 80
  })],
  // include health check (default is none)
  healthCheck: {
    interval: cdk.Duration.seconds(60),
    path: "/health",
    timeout: cdk.Duration.seconds(5),
  }
});

new cdk.CfnOutput(stack, 'LoadBalancerDNS', { value: lb.loadBalancerDnsName, });

app.synth();

Use the following commands to interact with your CDK application:

  • npm run-script cdk diff - Show a preview of resources to be deployed
  • npm run-script cdk deploy - Deploy the resources onto your AWS account
  • npm run-script cdk destroy - Tear down the deployed stack

Next steps

  • The sample application is launching EC2 capacity of type t2.micro. You will probably want a bigger EC2 instance type
  • The sample application is deploying a sample app straight off of Docker Hub. Check out the CDK docs for ContainerImage.fromAsset() to see how to make CDK build your local application.
  • You may wish to add port 443 to the load balancer, and configure an SSL certificate for HTTPS traffic

Alternative Patterns

Not quite right for you? Try another way to do this:

AWS CloudFormation  Public facing website hosted on EC2 instances

Instead of programmatic generation of CloudFormation YAML, you can use CloudFormation directly.