-
Notifications
You must be signed in to change notification settings - Fork 84
Expand file tree
/
Copy pathecs-service.ts
More file actions
116 lines (106 loc) · 3.35 KB
/
Copy pathecs-service.ts
File metadata and controls
116 lines (106 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env node
import { App, Duration, Stack, StackProps } from "aws-cdk-lib";
import {
aws_certificatemanager as acm,
aws_cloudwatch as cloudwatch,
aws_ec2 as ec2,
aws_ecr as ecr,
aws_ecs as ecs,
aws_ecs_patterns as patterns,
aws_elasticloadbalancingv2 as elb,
aws_route53 as route53,
aws_ssm as ssm,
} from "aws-cdk-lib";
interface TriviaBackendStackProps extends StackProps {
domainName: string;
domainZone: string;
}
class TriviaBackendStack extends Stack {
constructor(parent: App, name: string, props: TriviaBackendStackProps) {
super(parent, name, props);
// Network infrastructure
const vpc = new ec2.Vpc(this, "VPC", { maxAzs: 2 });
const cluster = new ecs.Cluster(this, "Cluster", {
clusterName: props.domainName.replace(/\./g, "-"),
vpc,
containerInsightsV2: ecs.ContainerInsights.ENABLED,
});
// Configuration parameters
const domainZone = route53.HostedZone.fromLookup(this, "Zone", {
domainName: props.domainZone,
});
const imageRepo = ecr.Repository.fromRepositoryName(
this,
"Repo",
"reinvent-trivia-backend"
);
const tag = process.env.IMAGE_TAG ? process.env.IMAGE_TAG : "latest";
const image = ecs.ContainerImage.fromEcrRepository(imageRepo, tag);
// Lookup pre-existing TLS certificate
const certificateArn = ssm.StringParameter.fromStringParameterAttributes(
this,
"CertArnParameter",
{
parameterName: "CertificateArn-" + props.domainName,
}
).stringValue;
const certificate = acm.Certificate.fromCertificateArn(
this,
"Cert",
certificateArn
);
// Fargate service + load balancer
const service = new patterns.ApplicationLoadBalancedFargateService(
this,
"Service",
{
cluster,
taskImageOptions: { image },
desiredCount: 3,
domainName: props.domainName,
domainZone,
certificate,
propagateTags: ecs.PropagatedTagSource.SERVICE,
minHealthyPercent: 100,
maxHealthyPercent: 200,
}
);
// Enable AZ rebalancing
const cfnService = service.service.node.defaultChild as ecs.CfnService;
cfnService.availabilityZoneRebalancing = "ENABLED";
// Alarms: monitor 500s and unhealthy hosts on target groups
new cloudwatch.Alarm(this, "TargetGroupUnhealthyHosts", {
alarmName: this.stackName + "-Unhealthy-Hosts",
metric: service.targetGroup.metrics.unhealthyHostCount(),
threshold: 1,
evaluationPeriods: 2,
});
new cloudwatch.Alarm(this, "TargetGroup5xx", {
alarmName: this.stackName + "-Http-500",
metric: service.targetGroup.metrics.httpCodeTarget(
elb.HttpCodeTarget.TARGET_5XX_COUNT,
{ period: Duration.minutes(1) }
),
threshold: 1,
evaluationPeriods: 1,
});
}
}
const app = new App();
new TriviaBackendStack(app, "TriviaBackendTest", {
domainName: "api-test.reinvent-trivia.com",
domainZone: "reinvent-trivia.com",
env: { account: process.env["CDK_DEFAULT_ACCOUNT"], region: "us-east-1" },
tags: {
project: "reinvent-trivia",
},
});
new TriviaBackendStack(app, "TriviaBackendProd", {
domainName: "api.reinvent-trivia.com",
domainZone: "reinvent-trivia.com",
env: { account: process.env["CDK_DEFAULT_ACCOUNT"], region: "us-east-1" },
tags: {
project: "reinvent-trivia",
},
});
app.synth();