API Gateway load balanced Fargate service with Cloud Map using CDK construct
About
ApiGatewayLoadBalancedFargateService
is an AWS Cloud Development Kit(CDK) L3 construct that allows you to deploy a web service with Amazon API Gateway and route the traffic through VPC link to the Fargate service running in the VPC private subnets. No application or network load balancer is required. The service discovery capability is provided by the AWS Cloud Map service that comes with ECS service connect.
Sample
new ApiGatewayLoadBalancedFargateService(stack, 'DemoService', {
vpc,
cluster,
taskDefinition,
desiredCount: 2,
vpcLinkIntegration: VpcLinkIntegration.CLOUDMAP,
});
Setup Cloud Development Kit
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:
- package.json
- tsconfig.dev.json
- cdk.json
{
"name": "ecs-fargate-apigateway-cloudmap-cdk",
"repository": {
"type": "git",
"url": "https://github.com/aws-samples/container-patterns.git"
},
"scripts": {
"build": "npx projen build",
"bump": "npx projen bump",
"clobber": "npx projen clobber",
"compat": "npx projen compat",
"compile": "npx projen compile",
"default": "npx projen default",
"docgen": "npx projen docgen",
"eject": "npx projen eject",
"eslint": "npx projen eslint",
"package": "npx projen package",
"package-all": "npx projen package-all",
"package:js": "npx projen package:js",
"post-compile": "npx projen post-compile",
"post-upgrade": "npx projen post-upgrade",
"pre-compile": "npx projen pre-compile",
"release": "npx projen release",
"test": "npx projen test",
"test:watch": "npx projen test:watch",
"unbump": "npx projen unbump",
"upgrade": "npx projen upgrade",
"watch": "npx projen watch",
"projen": "npx projen"
},
"author": {
"name": "Pahud Hsieh",
"email": "pahudnet@gmail.com",
"organization": false
},
"devDependencies": {
"@types/jest": "^29.5.3",
"@types/node": "^16",
"@typescript-eslint/eslint-plugin": "^5",
"@typescript-eslint/parser": "^5",
"aws-cdk": "2.80.0",
"aws-cdk-lib": "2.80.0",
"constructs": "10.0.5",
"eslint": "^8",
"eslint-import-resolver-node": "^0.3.7",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.27.5",
"jest": "^29.6.1",
"jest-junit": "^15",
"jsii": "~5.0.0",
"jsii-diff": "^1.84.0",
"jsii-docgen": "^9.1.1",
"jsii-pacmak": "^1.84.0",
"jsii-rosetta": "~5.0.0",
"npm-check-updates": "^16",
"projen": "^0.71.138",
"standard-version": "^9",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typescript": "^5.1.6"
},
"peerDependencies": {
"@aws-cdk/aws-apigatewayv2-alpha": "2.80.0-alpha.0",
"@aws-cdk/aws-lambda-python-alpha": "2.80.0-alpha.0",
"aws-cdk-lib": "^2.80.0",
"constructs": "^10.0.5"
},
"dependencies": {
"@aws-cdk/aws-apigatewayv2-alpha": "2.80.0-alpha.0",
"@aws-cdk/aws-lambda-python-alpha": "2.80.0-alpha.0"
},
"keywords": [
"cdk"
],
"main": "lib/index.js",
"license": "Apache-2.0",
"version": "0.0.0",
"jest": {
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.ts?(x)",
"<rootDir>/(test|src)/**/*(*.)@(spec|test).ts?(x)"
],
"clearMocks": true,
"collectCoverage": true,
"coverageReporters": [
"json",
"lcov",
"clover",
"cobertura",
"text"
],
"coverageDirectory": "coverage",
"coveragePathIgnorePatterns": [
"/node_modules/"
],
"testPathIgnorePatterns": [
"/node_modules/"
],
"watchPathIgnorePatterns": [
"/node_modules/"
],
"reporters": [
"default",
[
"jest-junit",
{
"outputDirectory": "test-reports"
}
]
],
"preset": "ts-jest",
"globals": {
"ts-jest": {
"tsconfig": "tsconfig.dev.json"
}
}
},
"types": "lib/index.d.ts",
"stability": "stable",
"jsii": {
"outdir": "dist",
"targets": {},
"tsc": {
"outDir": "lib",
"rootDir": "src"
}
},
"//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"."
}
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.dev.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.
Run the following commands to install dependencies and setup your AWS account for the deployment:
yarn install
npx cdk bootstrap
Deploy the sample App
import {
App, Stack,
aws_ecs as ecs,
aws_ec2 as ec2,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { ApiGatewayLoadBalancedFargateService, VpcLinkIntegration } from './agw-balanced-fargate-service';
export class IntegTesting {
readonly stack: Stack[];
constructor() {
const app = new App();
const env = { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT };
const stack = new Stack(app, 'integ-testing', { env });
const vpc = this.getVpc(stack);
const cluster = new ecs.Cluster(stack, 'Cluster', {
vpc,
enableFargateCapacityProviders: true,
});
cluster.addDefaultCapacityProviderStrategy([
{ capacityProvider: 'FARGATE_SPOT', base: 2, weight: 50 },
{ capacityProvider: 'FARGATE', weight: 50 },
]);
const taskDefinition = new ecs.FargateTaskDefinition(stack, 'Task', {
memoryLimitMiB: 512,
cpu: 256,
});
taskDefinition.addContainer('nyancat', {
image: ecs.ContainerImage.fromRegistry('public.ecr.aws/pahudnet/nyancat-docker-image:latest'),
portMappings: [{ containerPort: 80, name: 'default' }],
healthCheck: {
command: ['CMD-SHELL', 'curl -f http://localhost/ || exit 1'],
},
});
new ApiGatewayLoadBalancedFargateService(stack, 'DemoService', {
vpc,
cluster,
taskDefinition,
desiredCount: 2,
vpcLinkIntegration: VpcLinkIntegration.CLOUDMAP,
});
this.stack = [stack];
}
private getVpc(scope: Construct): ec2.IVpc {
return scope.node.tryGetContext('use_default_vpc') === '1' ?
ec2.Vpc.fromLookup(scope, 'Vpc', { isDefault: true }) :
scope.node.tryGetContext('use_vpc_id') != undefined ?
ec2.Vpc.fromLookup(scope, 'Vpc', { vpcId: scope.node.tryGetContext('use_vpc_id') }) :
new ec2.Vpc(scope, 'Vpc', { natGateways: 1 });
}
};
new IntegTesting();
npx cdk diff
Deploy the stack:
npx cdk deploy
You will see an Outputs
section that shows the endpoint URL of the API Gateway. When you load up that URL you should see the nyancat demo animation.
Next Steps
As this sample comes with a L3 construct ApiGatewayLoadBalancedFargateService
, you can modify the typescript under files/src
to create your own CDK application using the provided contruct with custom properties. For example, if you create your sample app and save as sample.ts
, run this command in files
to deploy your CDK app in sample.ts
:
npx cdk -a 'npx ts-node --prefer-ts-exts src/sample.ts' diff
npx cdk -a 'npx ts-node --prefer-ts-exts src/sample.ts' deploy
Clean Up
You can tear down the stack using the following command:
npx cdk destroy