-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathappmesh.ts
180 lines (156 loc) · 4.84 KB
/
appmesh.ts
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import { IConnectable } from "aws-cdk-lib/aws-ec2";
import { App, Stack } from "aws-cdk-lib";
import {
Backend,
GatewayRouteSpec,
HttpGatewayRoutePathMatch,
RouteSpec,
VirtualRouter,
VirtualRouterListener,
VirtualService,
VirtualServiceProvider,
} from "aws-cdk-lib/aws-appmesh";
import { AppMesh } from "./appmesh/mesh";
import { AppMeshCluster } from "./appmesh/cluster";
import { AppMeshExpress } from "./appmesh/express";
interface Props {
namespaceName: string;
externalAccess: IConnectable;
}
export class AppMeshApp extends App {
constructor(props: Props) {
super();
const { namespaceName, externalAccess } = props;
// create ourselves an empty stack to hold our resources
const stack = new Stack(this, namespaceName);
/**
* create our ECS Cluster that is configured for App Mesh
*
* the key difference is that the namespace is backed by Route 53
*
* `cluster` our ECS Cluster with underlying default VPC
* `namespace` our Cloud Map namespace created by ourselves
* `securityGroup` security group accessible from our IP to make things easy
**/
const { cluster, namespace, securityGroup } = new AppMeshCluster(
stack,
"Cluster",
{
namespaceName,
externalAccess,
}
);
/**
* configure App Mesh components
*
* `mesh` the App Mesh mesh that services will be added to as nodes,
* routes, services, etc.
* `gateway` the App Mesh Gateway, running on ECS Fargate, that will
* receive external traffic and route it into the service mesh
*/
const { mesh, gateway } = new AppMesh(stack, "Mesh", {
cluster,
securityGroup,
});
const meshThings = {
cluster,
namespace,
mesh,
gateway,
securityGroup,
};
/**
* create two ECS Services, "blue" and "green", running our sample Express.js
* application that are configured for App Mesh
*
* the details of configuring for App Mesh are quite gory -- take a look
* inside the Construct!
*
* thankfull this is precisely the sort of thing that AWS CDK excels at,
* abstracting away gory details
*
* we can use the /downstream endpoint of our sample application to explore
* how these services are able to discover and route traffic to each other
* as they have been connected to the same namespace
**/
const blue = new AppMeshExpress(stack, "Blue", {
serviceName: "blue",
...meshThings,
});
const green = new AppMeshExpress(stack, "Green", {
serviceName: "green",
...meshThings,
});
/**
* configure each service as a "backend" of the other's node so that
* traffic can be routed between them via the mesh
*/
blue.virtualNode.addBackend(Backend.virtualService(green.virtualService));
green.virtualNode.addBackend(Backend.virtualService(blue.virtualService));
/**
* configure a route on the gateway for each service so that
* traffic entering the mesh is routed to that service
*
* this sets up path-based routing:
* - all traffic with path starting with '/blue' -> blue
* - all traffic with path starting with '/green' -> green
*/
gateway.addGatewayRoute("blue", {
routeSpec: GatewayRouteSpec.http({
routeTarget: blue.virtualService,
match: {
path: HttpGatewayRoutePathMatch.startsWith("/blue"),
},
}),
});
gateway.addGatewayRoute("green", {
routeSpec: GatewayRouteSpec.http({
routeTarget: green.virtualService,
match: {
path: HttpGatewayRoutePathMatch.startsWith("/green"),
},
}),
});
/**
* configure a router that divides traffic equally between our
* "blue" and "green" nodes
*/
const router = new VirtualRouter(stack, "Router", {
mesh,
virtualRouterName: "router",
listeners: [VirtualRouterListener.http(80)],
});
router.addRoute("split", {
routeName: "split",
routeSpec: RouteSpec.http({
weightedTargets: [
{
virtualNode: blue.virtualNode,
weight: 50,
},
{
virtualNode: green.virtualNode,
weight: 50,
},
],
}),
});
/**
* wrap our router in a service so that it can be the destination of
* a gateway route:
* - all traffic with path starting with '/split' -> router
*/
const routerService = new VirtualService(stack, "RouterService", {
virtualServiceProvider: VirtualServiceProvider.virtualRouter(router),
virtualServiceName: "router",
});
gateway.addGatewayRoute("split", {
routeSpec: GatewayRouteSpec.http({
routeTarget: routerService,
match: {
path: HttpGatewayRoutePathMatch.startsWith("/split"),
},
}),
});
}
}