@venturekit/infra 0.0.40 → 0.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -0
- package/dist/cdk/app-stack.d.ts +15 -0
- package/dist/cdk/app-stack.d.ts.map +1 -1
- package/dist/cdk/app-stack.js +16 -0
- package/dist/cdk/app-stack.js.map +1 -1
- package/dist/cdk/compute-stack.d.ts +146 -0
- package/dist/cdk/compute-stack.d.ts.map +1 -0
- package/dist/cdk/compute-stack.js +485 -0
- package/dist/cdk/compute-stack.js.map +1 -0
- package/dist/cdk/config-stack.d.ts.map +1 -1
- package/dist/cdk/config-stack.js +14 -0
- package/dist/cdk/config-stack.js.map +1 -1
- package/dist/cdk/data-stack.d.ts.map +1 -1
- package/dist/cdk/data-stack.js +30 -14
- package/dist/cdk/data-stack.js.map +1 -1
- package/dist/cdk/edge-stack.d.ts.map +1 -1
- package/dist/cdk/edge-stack.js +42 -6
- package/dist/cdk/edge-stack.js.map +1 -1
- package/dist/cdk/index.d.ts +7 -1
- package/dist/cdk/index.d.ts.map +1 -1
- package/dist/cdk/index.js +7 -1
- package/dist/cdk/index.js.map +1 -1
- package/dist/cdk/services-stack.d.ts +143 -0
- package/dist/cdk/services-stack.d.ts.map +1 -0
- package/dist/cdk/services-stack.js +562 -0
- package/dist/cdk/services-stack.js.map +1 -0
- package/dist/cdk/shared/service-alarms.d.ts +83 -0
- package/dist/cdk/shared/service-alarms.d.ts.map +1 -0
- package/dist/cdk/shared/service-alarms.js +180 -0
- package/dist/cdk/shared/service-alarms.js.map +1 -0
- package/dist/cdk/shared/ssm-keys.d.ts +104 -0
- package/dist/cdk/shared/ssm-keys.d.ts.map +1 -1
- package/dist/cdk/shared/ssm-keys.js +56 -0
- package/dist/cdk/shared/ssm-keys.js.map +1 -1
- package/dist/venture.d.ts +23 -1
- package/dist/venture.d.ts.map +1 -1
- package/dist/venture.js +52 -0
- package/dist/venture.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier — Services stack: the long-running processes (`services[]`), each
|
|
3
|
+
* as an ECS service on its `compute[]` pool — and the other ventures'
|
|
4
|
+
* services this one reaches through a private link (`external`).
|
|
5
|
+
*
|
|
6
|
+
* Per owned service, whatever the pool's kind: a task definition with the
|
|
7
|
+
* declared containers (images built at deploy from their Dockerfiles, for
|
|
8
|
+
* the pool's architecture, or pulled from a registry), one log group, the
|
|
9
|
+
* database contract the venture's Lambdas get (`DB_HOST` … `DB_TENANT_ROLE`)
|
|
10
|
+
* when the intent names a database, secrets handed over as environment
|
|
11
|
+
* values by the ECS agent, and a topic of alarms.
|
|
12
|
+
*
|
|
13
|
+
* Then per kind:
|
|
14
|
+
*
|
|
15
|
+
* - `instance` — an EC2 service with `host` networking, one task on every
|
|
16
|
+
* machine of the pool (the daemon strategy): the ports are the machines',
|
|
17
|
+
* the doors are the pool's balancers (compute tier), the machines' group
|
|
18
|
+
* admits what the ports declare, persistent volumes are directories on
|
|
19
|
+
* the machines' disks, and the name is the pool's — the machine's
|
|
20
|
+
* wildcard record, or the internal balancer's alias. A rollout stops a
|
|
21
|
+
* machine's task before starting the new one (host ports), one machine
|
|
22
|
+
* at a time on a pool of several.
|
|
23
|
+
* - `serverless` — a Fargate service in the private subnets with a group
|
|
24
|
+
* of its own: `vpc` ports admitted from the VPC, `public` ports reached
|
|
25
|
+
* through an internet-facing Network Load Balancer with an Elastic IP
|
|
26
|
+
* per AZ (client addresses preserved, TLS terminated there when a port
|
|
27
|
+
* asks), EFS under persistent volumes, and the name kept on the task by
|
|
28
|
+
* service discovery.
|
|
29
|
+
*
|
|
30
|
+
* Per external service: an interface VPC endpoint in this venture's VPC,
|
|
31
|
+
* connected to the endpoint service the owner published, admitted from
|
|
32
|
+
* this VPC; the Lambdas are told its name (`SERVICE_<ID>_HOST`) and a URL
|
|
33
|
+
* on the owner's first shared port (`SERVICE_<ID>_URL`). An owner that has
|
|
34
|
+
* not published yet (`external.resolved === null`, the deploy's pre-flight
|
|
35
|
+
* looked) gets a warning and no endpoint until the next deploy.
|
|
36
|
+
*
|
|
37
|
+
* # Lifecycle position
|
|
38
|
+
*
|
|
39
|
+
* The most often deployed tier after `app`: every image change rolls the
|
|
40
|
+
* service that uses it — and only that one, since each image's fingerprint
|
|
41
|
+
* is its own context less what `build.ignore` keeps out.
|
|
42
|
+
*
|
|
43
|
+
* # Public surface (via SSM)
|
|
44
|
+
*
|
|
45
|
+
* - `servicesKeys.serviceName / logGroupName / alarmTopicArn` per owned
|
|
46
|
+
* service; `url` when it has a name; `addresses / loadBalancerDnsName`
|
|
47
|
+
* when its ports are public; `endpointServiceName / sharedPorts / port`
|
|
48
|
+
* when they are shared.
|
|
49
|
+
*
|
|
50
|
+
* # What this stack does NOT do
|
|
51
|
+
*
|
|
52
|
+
* - **No public DNS.** A public port has fixed addresses (one per AZ) and a
|
|
53
|
+
* load balancer name; the operator points a hostname at them where the
|
|
54
|
+
* venture's DNS lives.
|
|
55
|
+
* - **No TLS without a balancer.** A pool of one machine has nothing in
|
|
56
|
+
* front of it to terminate TLS on; the container does it, or an operator
|
|
57
|
+
* reaches the port through an SSM port forward.
|
|
58
|
+
*/
|
|
59
|
+
import * as path from 'node:path';
|
|
60
|
+
import * as cdk from 'aws-cdk-lib';
|
|
61
|
+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
|
|
62
|
+
import { Platform } from 'aws-cdk-lib/aws-ecr-assets';
|
|
63
|
+
import * as ecs from 'aws-cdk-lib/aws-ecs';
|
|
64
|
+
import * as efs from 'aws-cdk-lib/aws-efs';
|
|
65
|
+
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
|
|
66
|
+
import * as logs from 'aws-cdk-lib/aws-logs';
|
|
67
|
+
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
|
|
68
|
+
import * as servicediscovery from 'aws-cdk-lib/aws-servicediscovery';
|
|
69
|
+
import { DATA_SAFETY_CONFIG, assertValid, validateComputeAndServices, } from '@venturekit/core';
|
|
70
|
+
import { readSsmString, writeSsm } from './shared/cross-stack-refs.js';
|
|
71
|
+
import { toLogRetention } from './shared/lambda-helpers.js';
|
|
72
|
+
import { servicesKeys } from './shared/ssm-keys.js';
|
|
73
|
+
import { ServiceAlarms } from './shared/service-alarms.js';
|
|
74
|
+
import { instanceVolumePath, poolOf } from './compute-stack.js';
|
|
75
|
+
/** Where a service's containers log: one group per service, a stream prefix per container. */
|
|
76
|
+
export function serviceLogGroupName(projectName, stage, serviceId) {
|
|
77
|
+
return `/venturekit/${projectName}/${stage}/services/${serviceId}`;
|
|
78
|
+
}
|
|
79
|
+
/** The service's private address, when it has a name and a port to answer on: the first `vpc` or `shared` port, else the first. */
|
|
80
|
+
export function serviceUrl(service, zoneName) {
|
|
81
|
+
if (!service.dns)
|
|
82
|
+
return undefined;
|
|
83
|
+
const ports = (service.containers ?? []).flatMap((c) => c.ports ?? []);
|
|
84
|
+
const port = ports.find((p) => p.expose === 'vpc' || p.expose === 'shared') ?? ports[0];
|
|
85
|
+
return port ? `http://${service.dns}.${zoneName}:${port.port}` : undefined;
|
|
86
|
+
}
|
|
87
|
+
/** The memory floor (MiB) a container on an instance pool gets when its intent names none: counted by the scheduler, no ceiling. */
|
|
88
|
+
export const DEFAULT_MEMORY_RESERVATION_MIB = 128;
|
|
89
|
+
/** A synth warning id per closed public port, so the deploy log says which door admits nobody. */
|
|
90
|
+
export const CLOSED_PORT_WARNING = 'venturekit:services:public-port-closed';
|
|
91
|
+
export class VentureServicesStack extends cdk.Stack {
|
|
92
|
+
services = new Map();
|
|
93
|
+
/** The other ventures' services reached through a private link, by intent id. */
|
|
94
|
+
externals = new Map();
|
|
95
|
+
/** What the app tier injects as `SERVICE_<ID>_URL`: a plain string for an owned service, a token for an external one. */
|
|
96
|
+
serviceUrlsById = new Map();
|
|
97
|
+
/** What the app tier injects as `SERVICE_<ID>_HOST` for external services (a token). */
|
|
98
|
+
serviceHostsById = new Map();
|
|
99
|
+
isStrictRetain;
|
|
100
|
+
constructor(scope, id, props) {
|
|
101
|
+
super(scope, id, props);
|
|
102
|
+
const { projectName, stage, envConfig, infrastructure } = props;
|
|
103
|
+
assertValid(validateComputeAndServices(infrastructure));
|
|
104
|
+
this.isStrictRetain = DATA_SAFETY_CONFIG[envConfig.dataSafety].removalPolicy === 'retain';
|
|
105
|
+
const compute = infrastructure.compute ?? [];
|
|
106
|
+
for (const intent of infrastructure.services ?? []) {
|
|
107
|
+
if (intent.external) {
|
|
108
|
+
if (intent.external.resolved === null) {
|
|
109
|
+
// The pre-flight found nothing published: the owner deploys after
|
|
110
|
+
// this venture on a fresh stage. Nothing to connect to yet; the
|
|
111
|
+
// Lambdas get no SERVICE_<ID>_HOST and the next deploy creates it.
|
|
112
|
+
cdk.Annotations.of(this).addWarningV2(`venturekit:services:external-unpublished:${intent.id}`, `${projectName}-${stage}-${intent.id}: ${intent.external.project} has not published its '${intent.external.intent ?? intent.id}' service on this stage yet, ` +
|
|
113
|
+
`so no endpoint is created and the Lambdas get no SERVICE_${upperSnake(intent.id)}_HOST. Deploy ${intent.external.project}, then this venture again.`);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const external = this.createExternal(intent, props);
|
|
117
|
+
this.externals.set(intent.id, external);
|
|
118
|
+
this.serviceUrlsById.set(intent.id, external.url);
|
|
119
|
+
this.serviceHostsById.set(intent.id, external.host);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const poolIntent = poolOf(intent, compute);
|
|
123
|
+
const pool = poolIntent && props.pools.get(poolIntent.id);
|
|
124
|
+
if (!pool) {
|
|
125
|
+
throw new Error(`[venturekit] services stack: service '${intent.id}' is on pool '${poolIntent?.id ?? intent.compute}' ` +
|
|
126
|
+
`but pools has no entry for it. The CLI generator must wire computeStack.pools into VentureServicesStackProps.pools.`);
|
|
127
|
+
}
|
|
128
|
+
const deployed = this.createService(intent, pool, props);
|
|
129
|
+
this.services.set(intent.id, deployed);
|
|
130
|
+
if (deployed.url)
|
|
131
|
+
this.serviceUrlsById.set(intent.id, deployed.url);
|
|
132
|
+
writeSsm(this, servicesKeys.serviceName(projectName, stage, intent.id), deployed.service.serviceName, {
|
|
133
|
+
description: `ECS service of '${intent.id}' on pool '${pool.intent.id}'.`,
|
|
134
|
+
});
|
|
135
|
+
writeSsm(this, servicesKeys.logGroupName(projectName, stage, intent.id), deployed.logGroup.logGroupName, {
|
|
136
|
+
description: `Log group of every container of '${intent.id}'.`,
|
|
137
|
+
});
|
|
138
|
+
writeSsm(this, servicesKeys.alarmTopicArn(projectName, stage, intent.id), deployed.alarms.topic.topicArn, {
|
|
139
|
+
description: `SNS topic '${intent.id}''s alarms ring.`,
|
|
140
|
+
});
|
|
141
|
+
if (deployed.url) {
|
|
142
|
+
writeSsm(this, servicesKeys.url(projectName, stage, intent.id), deployed.url, {
|
|
143
|
+
description: `Private address of '${intent.id}' (inside the VPC); the app tier injects it as SERVICE_${upperSnake(intent.id)}_URL.`,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const publicAddresses = deployed.addresses.length > 0 ? deployed.addresses : pool.addresses;
|
|
147
|
+
const publicPorts = (intent.containers ?? []).flatMap((c) => (c.ports ?? []).filter((p) => p.expose === 'public'));
|
|
148
|
+
if (publicPorts.length > 0 && publicAddresses.length > 0) {
|
|
149
|
+
writeSsm(this, servicesKeys.addresses(projectName, stage, intent.id), cdk.Fn.join(',', publicAddresses.map((a) => a.ref)), {
|
|
150
|
+
description: `Fixed public addresses of '${intent.id}''s public ports (one per AZ).`,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
const loadBalancer = deployed.loadBalancer ?? (publicPorts.length > 0 ? pool.publicLoadBalancer : undefined);
|
|
154
|
+
if (loadBalancer) {
|
|
155
|
+
writeSsm(this, servicesKeys.loadBalancerDnsName(projectName, stage, intent.id), loadBalancer.loadBalancerDnsName, {
|
|
156
|
+
description: `Load balancer in front of '${intent.id}''s public ports — a CNAME target.`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
const sharedPorts = (intent.containers ?? []).flatMap((c) => (c.ports ?? []).filter((p) => p.expose === 'shared').map((p) => p.port));
|
|
160
|
+
if (sharedPorts.length > 0 && pool.endpointService) {
|
|
161
|
+
writeSsm(this, servicesKeys.endpointServiceName(projectName, stage, intent.id), pool.endpointService.vpcEndpointServiceName, {
|
|
162
|
+
description: `Endpoint service a consumer venture connects to for '${intent.id}' (services[].external).`,
|
|
163
|
+
});
|
|
164
|
+
writeSsm(this, servicesKeys.sharedPorts(projectName, stage, intent.id), sharedPorts.join(','), {
|
|
165
|
+
description: `Ports of '${intent.id}' reachable through the private link.`,
|
|
166
|
+
});
|
|
167
|
+
writeSsm(this, servicesKeys.port(projectName, stage, intent.id), String(sharedPorts[0]), {
|
|
168
|
+
description: `First shared port of '${intent.id}' — what a consumer's SERVICE_<ID>_URL names.`,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
createExternal(intent, props) {
|
|
174
|
+
const { projectName, stage, vpc } = props;
|
|
175
|
+
const owner = intent.external.project;
|
|
176
|
+
const ownerIntent = intent.external.intent ?? intent.id;
|
|
177
|
+
const suffix = logicalSuffix(intent.id);
|
|
178
|
+
const name = `${projectName}-${stage}-${intent.id}`;
|
|
179
|
+
// The owner published these when it deployed (same account, region and
|
|
180
|
+
// stage). `vk deploy`'s pre-flight read them and pinned them on the
|
|
181
|
+
// intent; standalone, they are read at deploy time through
|
|
182
|
+
// CloudFormation, so this synth needs no credentials either way.
|
|
183
|
+
const resolved = intent.external.resolved;
|
|
184
|
+
const serviceName = resolved ? resolved.endpointServiceName : readSsmString(this, servicesKeys.endpointServiceName(owner, stage, ownerIntent));
|
|
185
|
+
const port = resolved ? resolved.port : readSsmString(this, servicesKeys.port(owner, stage, ownerIntent));
|
|
186
|
+
// The endpoint's interfaces live in this VPC's private subnets; what
|
|
187
|
+
// reaches them is decided here — the VPC, on every port, since the
|
|
188
|
+
// owner's balancer only listens on the shared ones anyway.
|
|
189
|
+
const securityGroup = new ec2.SecurityGroup(this, `EndpointSg${suffix}`, {
|
|
190
|
+
vpc,
|
|
191
|
+
description: `${name}: this VPC to ${owner}/${ownerIntent} through the private link`,
|
|
192
|
+
allowAllOutbound: true,
|
|
193
|
+
});
|
|
194
|
+
securityGroup.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.allTcp(), `${owner}/${ownerIntent} from the VPC`);
|
|
195
|
+
const endpoint = new ec2.InterfaceVpcEndpoint(this, `Endpoint${suffix}`, {
|
|
196
|
+
vpc,
|
|
197
|
+
service: new ec2.InterfaceVpcEndpointService(serviceName),
|
|
198
|
+
subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
|
|
199
|
+
securityGroups: [securityGroup],
|
|
200
|
+
privateDnsEnabled: false,
|
|
201
|
+
open: false,
|
|
202
|
+
});
|
|
203
|
+
// `vpcEndpointDnsEntries` are `<hosted zone id>:<dns name>`; the first is the regional name.
|
|
204
|
+
const host = cdk.Fn.select(1, cdk.Fn.split(':', cdk.Fn.select(0, endpoint.vpcEndpointDnsEntries)));
|
|
205
|
+
const url = `http://${host}:${port}`;
|
|
206
|
+
new cdk.CfnOutput(this, `External${suffix}Host`, { value: host, description: `${owner}/${ownerIntent} through the private link; SERVICE_${upperSnake(intent.id)}_HOST in the Lambdas` });
|
|
207
|
+
return { intent, endpoint, host, url };
|
|
208
|
+
}
|
|
209
|
+
createService(intent, pool, props) {
|
|
210
|
+
const { projectName, stage, envConfig, projectDir, vpc } = props;
|
|
211
|
+
const name = `${projectName}-${stage}-${intent.id}`;
|
|
212
|
+
const suffix = logicalSuffix(intent.id);
|
|
213
|
+
const onInstance = pool.kind === 'instance';
|
|
214
|
+
const containers = intent.containers ?? [];
|
|
215
|
+
const removalPolicy = this.isStrictRetain ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY;
|
|
216
|
+
const logGroup = new logs.LogGroup(this, `Logs${suffix}`, {
|
|
217
|
+
logGroupName: serviceLogGroupName(projectName, stage, intent.id),
|
|
218
|
+
retention: toLogRetention(intent.logRetentionDays ?? envConfig.observability.logs.retentionDays),
|
|
219
|
+
removalPolicy,
|
|
220
|
+
});
|
|
221
|
+
// ── The task ─────────────────────────────────────────────────────
|
|
222
|
+
const volumes = intent.volumes ?? [];
|
|
223
|
+
const fileSystems = new Map();
|
|
224
|
+
let taskSecurityGroup;
|
|
225
|
+
let taskDefinition;
|
|
226
|
+
if (onInstance) {
|
|
227
|
+
taskDefinition = new ecs.Ec2TaskDefinition(this, `Task${suffix}`, {
|
|
228
|
+
family: name,
|
|
229
|
+
networkMode: ecs.NetworkMode.HOST,
|
|
230
|
+
// A persistent volume is a directory the compute tier created on the
|
|
231
|
+
// machine's disk; a scratch one is ECS's own, gone with the task.
|
|
232
|
+
volumes: volumes.map((v) => (v.persistent ? { name: v.name, host: { sourcePath: instanceVolumePath(intent.id, v.name) } } : { name: v.name })),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
taskSecurityGroup = new ec2.SecurityGroup(this, `TaskSg${suffix}`, {
|
|
237
|
+
vpc,
|
|
238
|
+
description: `${name} tasks: the declared vpc ports from the VPC, public ones from the load balancer`,
|
|
239
|
+
allowAllOutbound: true,
|
|
240
|
+
});
|
|
241
|
+
for (const v of volumes) {
|
|
242
|
+
if (!v.persistent)
|
|
243
|
+
continue;
|
|
244
|
+
// The volume outlives any one task: a replacement serves what the previous one built.
|
|
245
|
+
const fsSg = new ec2.SecurityGroup(this, `Volume${suffix}${logicalSuffix(v.name)}Sg`, {
|
|
246
|
+
vpc,
|
|
247
|
+
description: `${name} volume ${v.name}: from the task only`,
|
|
248
|
+
allowAllOutbound: false,
|
|
249
|
+
});
|
|
250
|
+
const fileSystem = new efs.FileSystem(this, `Volume${suffix}${logicalSuffix(v.name)}`, {
|
|
251
|
+
vpc,
|
|
252
|
+
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
|
|
253
|
+
securityGroup: fsSg,
|
|
254
|
+
encrypted: true,
|
|
255
|
+
// Read once per task start, written now and then: pay per byte, not for provisioned throughput.
|
|
256
|
+
throughputMode: efs.ThroughputMode.ELASTIC,
|
|
257
|
+
removalPolicy,
|
|
258
|
+
});
|
|
259
|
+
fileSystem.connections.allowDefaultPortFrom(taskSecurityGroup, `${name} task to volume ${v.name}`);
|
|
260
|
+
fileSystems.set(v.name, fileSystem);
|
|
261
|
+
}
|
|
262
|
+
taskDefinition = new ecs.FargateTaskDefinition(this, `Task${suffix}`, {
|
|
263
|
+
family: name,
|
|
264
|
+
cpu: intent.cpu ?? 256,
|
|
265
|
+
memoryLimitMiB: intent.memoryMiB ?? 512,
|
|
266
|
+
runtimePlatform: {
|
|
267
|
+
cpuArchitecture: pool.architecture === 'arm64' ? ecs.CpuArchitecture.ARM64 : ecs.CpuArchitecture.X86_64,
|
|
268
|
+
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
|
|
269
|
+
},
|
|
270
|
+
volumes: volumes.map((v) => {
|
|
271
|
+
const fileSystem = fileSystems.get(v.name);
|
|
272
|
+
return fileSystem ? { name: v.name, efsVolumeConfiguration: { fileSystemId: fileSystem.fileSystemId, transitEncryption: 'ENABLED' } } : { name: v.name };
|
|
273
|
+
}),
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
// ── The database ─────────────────────────────────────────────────
|
|
277
|
+
// The same contract every Lambda of the venture gets; the container
|
|
278
|
+
// fetches the password itself from DB_SECRET_ARN, so the task role is
|
|
279
|
+
// granted that read and nothing else of the secret's.
|
|
280
|
+
const databaseEnv = {};
|
|
281
|
+
if (intent.database) {
|
|
282
|
+
const db = props.databaseEndpointsById?.get(intent.database);
|
|
283
|
+
if (!db) {
|
|
284
|
+
throw new Error(`[venturekit] services stack: service '${intent.id}' declares database '${intent.database}' ` +
|
|
285
|
+
`but databaseEndpointsById has no entry for it. The CLI generator must wire dataStack.databases into VentureServicesStackProps.`);
|
|
286
|
+
}
|
|
287
|
+
databaseEnv.DB_HOST = db.host;
|
|
288
|
+
databaseEnv.DB_PORT = db.port;
|
|
289
|
+
databaseEnv.DB_NAME = db.name;
|
|
290
|
+
databaseEnv.DB_SSL = 'true';
|
|
291
|
+
if (db.secretArn) {
|
|
292
|
+
databaseEnv.DB_SECRET_ARN = db.secretArn;
|
|
293
|
+
secretsmanager.Secret.fromSecretCompleteArn(this, `DbSecret${suffix}`, db.secretArn).grantRead(taskDefinition.taskRole);
|
|
294
|
+
}
|
|
295
|
+
if (db.tenantRole)
|
|
296
|
+
databaseEnv.DB_TENANT_ROLE = db.tenantRole;
|
|
297
|
+
if (taskSecurityGroup) {
|
|
298
|
+
const conn = props.databaseConnectionsById?.get(intent.database);
|
|
299
|
+
if (conn) {
|
|
300
|
+
const dbSg = ec2.SecurityGroup.fromSecurityGroupId(this, `ImportedDbSg${suffix}`, conn.securityGroupId, { mutable: true });
|
|
301
|
+
dbSg.connections.allowFrom(taskSecurityGroup, ec2.Port.tcp(conn.port), `Allow ${name} tasks to connect to db ${intent.database}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
// ── The containers ───────────────────────────────────────────────
|
|
306
|
+
const platform = pool.architecture === 'arm64' ? Platform.LINUX_ARM64 : Platform.LINUX_AMD64;
|
|
307
|
+
const publicPorts = [];
|
|
308
|
+
const sharedPorts = [];
|
|
309
|
+
const vpcPorts = [];
|
|
310
|
+
for (const container of containers) {
|
|
311
|
+
const secrets = {};
|
|
312
|
+
for (const s of container.secrets ?? []) {
|
|
313
|
+
const arn = props.secretArnsById?.get(s.id);
|
|
314
|
+
if (!arn) {
|
|
315
|
+
throw new Error(`[venturekit] services stack: container '${container.name}' of '${intent.id}' names secret '${s.id}' ` +
|
|
316
|
+
`but secretArnsById has no entry for it. The CLI generator must wire configStack.secrets into VentureServicesStackProps.`);
|
|
317
|
+
}
|
|
318
|
+
secrets[s.env] = ecs.Secret.fromSecretsManager(secretsmanager.Secret.fromSecretCompleteArn(this, `Secret${suffix}${logicalSuffix(container.name)}${logicalSuffix(s.id)}`, arn));
|
|
319
|
+
}
|
|
320
|
+
// ECS wants a floor or a ceiling for every container of an EC2 task.
|
|
321
|
+
// Unset, the container gets the smallest floor the scheduler counts
|
|
322
|
+
// and no ceiling — it takes what is free, as the intent promises.
|
|
323
|
+
const memory = onInstance
|
|
324
|
+
? container.memory
|
|
325
|
+
? { memoryReservationMiB: container.memory.reservationMiB ?? (container.memory.limitMiB === undefined ? DEFAULT_MEMORY_RESERVATION_MIB : undefined), memoryLimitMiB: container.memory.limitMiB }
|
|
326
|
+
: { memoryReservationMiB: DEFAULT_MEMORY_RESERVATION_MIB }
|
|
327
|
+
: {};
|
|
328
|
+
const swap = onInstance && container.swap && pool.intent.swapMiB
|
|
329
|
+
? { linuxParameters: new ecs.LinuxParameters(this, `Linux${suffix}${logicalSuffix(container.name)}`, { maxSwap: cdk.Size.mebibytes(pool.intent.swapMiB), swappiness: 60 }) }
|
|
330
|
+
: {};
|
|
331
|
+
const healthCheck = container.healthCheck
|
|
332
|
+
? {
|
|
333
|
+
healthCheck: {
|
|
334
|
+
command: container.healthCheck.test,
|
|
335
|
+
interval: cdk.Duration.seconds(container.healthCheck.intervalSec ?? 30),
|
|
336
|
+
timeout: cdk.Duration.seconds(container.healthCheck.timeoutSec ?? 5),
|
|
337
|
+
retries: container.healthCheck.retries ?? 3,
|
|
338
|
+
startPeriod: cdk.Duration.seconds(container.healthCheck.startPeriodSec ?? 30),
|
|
339
|
+
},
|
|
340
|
+
}
|
|
341
|
+
: {};
|
|
342
|
+
const defined = taskDefinition.addContainer(`Container${suffix}${logicalSuffix(container.name)}`, {
|
|
343
|
+
containerName: container.name,
|
|
344
|
+
image: container.build
|
|
345
|
+
? ecs.ContainerImage.fromAsset(path.resolve(projectDir, container.build.context ?? '.'), {
|
|
346
|
+
file: container.build.dockerfile ?? 'Dockerfile',
|
|
347
|
+
platform,
|
|
348
|
+
ignoreMode: cdk.IgnoreMode.DOCKER,
|
|
349
|
+
exclude: container.build.ignore,
|
|
350
|
+
assetName: `${projectName}-${intent.id}-${container.name}`,
|
|
351
|
+
})
|
|
352
|
+
: ecs.ContainerImage.fromRegistry(container.image),
|
|
353
|
+
logging: ecs.LogDrivers.awsLogs({ logGroup, streamPrefix: container.name }),
|
|
354
|
+
environment: { ...databaseEnv, ...(container.env ?? {}) },
|
|
355
|
+
secrets,
|
|
356
|
+
portMappings: (container.ports ?? []).map((p) => ({ containerPort: p.port, protocol: ecs.Protocol.TCP })),
|
|
357
|
+
essential: container.essential ?? true,
|
|
358
|
+
...memory,
|
|
359
|
+
...swap,
|
|
360
|
+
...healthCheck,
|
|
361
|
+
});
|
|
362
|
+
for (const mount of container.mounts ?? []) {
|
|
363
|
+
defined.addMountPoints({ containerPath: mount.path, sourceVolume: mount.volume, readOnly: mount.readOnly ?? false });
|
|
364
|
+
}
|
|
365
|
+
for (const p of container.ports ?? []) {
|
|
366
|
+
if (p.expose === 'public') {
|
|
367
|
+
publicPorts.push({ container, port: p.port, from: p.from ?? [], tls: p.tls });
|
|
368
|
+
if ((p.from ?? []).length === 0 && !onInstance) {
|
|
369
|
+
cdk.Annotations.of(this).addWarningV2(`${CLOSED_PORT_WARNING}:${intent.id}:${p.port}`, `${name}: port ${p.port} of container ${container.name} is public with no ranges in 'from', so it admits nobody. List the ranges that may reach it.`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else if (p.expose === 'shared') {
|
|
373
|
+
sharedPorts.push(p.port);
|
|
374
|
+
}
|
|
375
|
+
else if (p.expose === 'vpc') {
|
|
376
|
+
vpcPorts.push(p.port);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// ── The service ──────────────────────────────────────────────────
|
|
381
|
+
let service;
|
|
382
|
+
let loadBalancer;
|
|
383
|
+
const addresses = [];
|
|
384
|
+
const targetGroups = [];
|
|
385
|
+
if (onInstance) {
|
|
386
|
+
// One task on every machine of the pool. Host networking: a machine's
|
|
387
|
+
// ports are released by the old task before the new one binds them, so
|
|
388
|
+
// a pool of one goes dark for the switch, a pool of several keeps all
|
|
389
|
+
// but one machine serving.
|
|
390
|
+
const machines = Math.max(1, pool.machines.min);
|
|
391
|
+
service = new ecs.Ec2Service(this, `Service${suffix}`, {
|
|
392
|
+
cluster: pool.cluster,
|
|
393
|
+
serviceName: name,
|
|
394
|
+
taskDefinition,
|
|
395
|
+
daemon: true,
|
|
396
|
+
minHealthyPercent: machines > 1 ? Math.ceil((100 * (machines - 1)) / machines) : 0,
|
|
397
|
+
maxHealthyPercent: 100,
|
|
398
|
+
circuitBreaker: { enable: true, rollback: true },
|
|
399
|
+
propagateTags: ecs.PropagatedTagSource.SERVICE,
|
|
400
|
+
});
|
|
401
|
+
// The pool's balancers front this service's ports; their target groups are what the alarms watch.
|
|
402
|
+
for (const port of [...publicPorts.map((p) => p.port), ...sharedPorts]) {
|
|
403
|
+
const group = pool.targetGroups.get(port);
|
|
404
|
+
if (group)
|
|
405
|
+
targetGroups.push({ id: String(port), port, group });
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
const taskSg = taskSecurityGroup;
|
|
410
|
+
for (const port of vpcPorts) {
|
|
411
|
+
taskSg.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcp(port), `${intent.id} :${port} from the VPC`);
|
|
412
|
+
}
|
|
413
|
+
const nlbSecurityGroup = publicPorts.length > 0
|
|
414
|
+
? new ec2.SecurityGroup(this, `LoadBalancerSg${suffix}`, {
|
|
415
|
+
vpc,
|
|
416
|
+
description: `${name} load balancer: the public ports from their ranges, TLS doors from anywhere`,
|
|
417
|
+
allowAllOutbound: true,
|
|
418
|
+
})
|
|
419
|
+
: undefined;
|
|
420
|
+
if (nlbSecurityGroup) {
|
|
421
|
+
for (const p of publicPorts) {
|
|
422
|
+
for (const cidr of p.from)
|
|
423
|
+
nlbSecurityGroup.addIngressRule(ec2.Peer.ipv4(cidr), ec2.Port.tcp(p.port), `${intent.id}/${p.container.name} :${p.port} from ${cidr}`);
|
|
424
|
+
if (p.tls)
|
|
425
|
+
nlbSecurityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(p.tls.port ?? 443), `${intent.id}/${p.container.name} TLS to :${p.port}`);
|
|
426
|
+
// ECS opens nothing by itself for a network target group.
|
|
427
|
+
taskSg.addIngressRule(nlbSecurityGroup, ec2.Port.tcp(p.port), `load balancer to ${intent.id} :${p.port}`);
|
|
428
|
+
}
|
|
429
|
+
if (intent.health)
|
|
430
|
+
taskSg.addIngressRule(nlbSecurityGroup, ec2.Port.tcp(intent.health.port), `load balancer health checks to ${intent.id} :${intent.health.port}`);
|
|
431
|
+
}
|
|
432
|
+
const fargate = new ecs.FargateService(this, `Service${suffix}`, {
|
|
433
|
+
cluster: pool.cluster,
|
|
434
|
+
serviceName: name,
|
|
435
|
+
taskDefinition: taskDefinition,
|
|
436
|
+
desiredCount: intent.replicas ?? 1,
|
|
437
|
+
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
|
|
438
|
+
securityGroups: [taskSg],
|
|
439
|
+
assignPublicIp: false,
|
|
440
|
+
// A replacement task is healthy before the old one is drained, and a task that cannot start rolls the deployment back instead of flapping.
|
|
441
|
+
minHealthyPercent: 100,
|
|
442
|
+
maxHealthyPercent: 200,
|
|
443
|
+
circuitBreaker: { enable: true, rollback: true },
|
|
444
|
+
...(nlbSecurityGroup ? { healthCheckGracePeriod: cdk.Duration.seconds(60) } : {}),
|
|
445
|
+
propagateTags: ecs.PropagatedTagSource.SERVICE,
|
|
446
|
+
...(intent.dns && pool.namespace
|
|
447
|
+
? {
|
|
448
|
+
cloudMapOptions: {
|
|
449
|
+
cloudMapNamespace: pool.namespace,
|
|
450
|
+
name: intent.dns,
|
|
451
|
+
dnsRecordType: servicediscovery.DnsRecordType.A,
|
|
452
|
+
dnsTtl: cdk.Duration.seconds(30),
|
|
453
|
+
},
|
|
454
|
+
}
|
|
455
|
+
: {}),
|
|
456
|
+
});
|
|
457
|
+
service = fargate;
|
|
458
|
+
if (nlbSecurityGroup) {
|
|
459
|
+
vpc.publicSubnets.forEach((_, i) => {
|
|
460
|
+
const address = new ec2.CfnEIP(this, `Address${suffix}${i + 1}`, { domain: 'vpc', tags: [{ key: 'Name', value: `${name}-${i + 1}` }] });
|
|
461
|
+
address.applyRemovalPolicy(removalPolicy);
|
|
462
|
+
addresses.push(address);
|
|
463
|
+
});
|
|
464
|
+
loadBalancer = new elbv2.NetworkLoadBalancer(this, `LoadBalancer${suffix}`, {
|
|
465
|
+
vpc,
|
|
466
|
+
loadBalancerName: name.slice(0, 32),
|
|
467
|
+
internetFacing: true,
|
|
468
|
+
// One task in one AZ must be reachable through every address.
|
|
469
|
+
crossZoneEnabled: true,
|
|
470
|
+
securityGroups: [nlbSecurityGroup],
|
|
471
|
+
subnetMappings: vpc.publicSubnets.map((subnet, i) => ({ subnet, allocationId: addresses[i].attrAllocationId })),
|
|
472
|
+
});
|
|
473
|
+
const healthCheck = intent.health
|
|
474
|
+
? {
|
|
475
|
+
protocol: elbv2.Protocol.HTTP,
|
|
476
|
+
path: intent.health.path,
|
|
477
|
+
port: String(intent.health.port),
|
|
478
|
+
interval: cdk.Duration.seconds(10),
|
|
479
|
+
timeout: cdk.Duration.seconds(5),
|
|
480
|
+
healthyThresholdCount: 2,
|
|
481
|
+
unhealthyThresholdCount: 2,
|
|
482
|
+
}
|
|
483
|
+
: { protocol: elbv2.Protocol.TCP, interval: cdk.Duration.seconds(10), healthyThresholdCount: 2, unhealthyThresholdCount: 2 };
|
|
484
|
+
for (const p of publicPorts) {
|
|
485
|
+
const id = `${logicalSuffix(p.container.name)}${p.port}`;
|
|
486
|
+
const group = new elbv2.NetworkTargetGroup(this, `Targets${suffix}${id}`, {
|
|
487
|
+
vpc,
|
|
488
|
+
port: p.port,
|
|
489
|
+
protocol: elbv2.Protocol.TCP,
|
|
490
|
+
targetType: elbv2.TargetType.IP,
|
|
491
|
+
preserveClientIp: true,
|
|
492
|
+
// A client whose task is going away should reconnect now, not when its keepalive notices.
|
|
493
|
+
connectionTermination: true,
|
|
494
|
+
deregistrationDelay: cdk.Duration.seconds(30),
|
|
495
|
+
healthCheck,
|
|
496
|
+
targets: [fargate.loadBalancerTarget({ containerName: p.container.name, containerPort: p.port })],
|
|
497
|
+
});
|
|
498
|
+
targetGroups.push({ id, port: p.port, group });
|
|
499
|
+
loadBalancer.addListener(`Listener${suffix}${id}`, { port: p.port, protocol: elbv2.Protocol.TCP, defaultTargetGroups: [group] });
|
|
500
|
+
if (p.tls) {
|
|
501
|
+
loadBalancer.addListener(`Tls${suffix}${id}`, {
|
|
502
|
+
port: p.tls.port ?? 443,
|
|
503
|
+
protocol: elbv2.Protocol.TLS,
|
|
504
|
+
certificates: [elbv2.ListenerCertificate.fromArn(p.tls.certificateArn)],
|
|
505
|
+
sslPolicy: elbv2.SslPolicy.RECOMMENDED_TLS,
|
|
506
|
+
defaultTargetGroups: [group],
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
// ── Who hears when it is not working ─────────────────────────────
|
|
513
|
+
const alarms = new ServiceAlarms(this, `Alarms${suffix}`, { name, email: pool.intent.alarms?.email });
|
|
514
|
+
alarms.taskDown(service, `${name} (${containers.map((c) => c.name).join(', ')})`);
|
|
515
|
+
const logErrors = intent.alarms?.logErrors ?? true;
|
|
516
|
+
if (logErrors !== false)
|
|
517
|
+
alarms.logErrors(logGroup, name, name, typeof logErrors === 'object' ? logErrors : {});
|
|
518
|
+
if (intent.alarms?.silence)
|
|
519
|
+
alarms.silence(logGroup, name, name, intent.alarms.silence);
|
|
520
|
+
for (const { id, port, group } of targetGroups)
|
|
521
|
+
alarms.unhealthyTargets(id, group, `${name} port ${port}`);
|
|
522
|
+
// ── What an operator needs to know ───────────────────────────────
|
|
523
|
+
const url = serviceUrl(intent, pool.zoneName);
|
|
524
|
+
if (url)
|
|
525
|
+
new cdk.CfnOutput(this, `Service${suffix}Url`, { value: url, description: `SERVICE_${upperSnake(intent.id)}_URL for the venture's Lambdas; resolves inside the VPC only` });
|
|
526
|
+
if (publicPorts.length > 0) {
|
|
527
|
+
new cdk.CfnOutput(this, `Service${suffix}PublicPorts`, {
|
|
528
|
+
value: publicPorts.map((p) => `tcp/${p.port}${p.tls ? ` (+tls/${p.tls.port ?? 443})` : ''} from ${p.from.length > 0 ? p.from.join(' ') : 'nobody (closed)'}`).join('; '),
|
|
529
|
+
});
|
|
530
|
+
const fixed = addresses.length > 0 ? addresses : pool.addresses;
|
|
531
|
+
new cdk.CfnOutput(this, `Service${suffix}Addresses`, {
|
|
532
|
+
value: fixed.length > 0 ? cdk.Fn.join(', ', fixed.map((a) => a.ref)) : 'none',
|
|
533
|
+
description: 'One Elastic IP per AZ — point the public hostname at them, or a CNAME at LoadBalancerDnsName',
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
const front = loadBalancer ?? (publicPorts.length > 0 ? pool.publicLoadBalancer : undefined);
|
|
537
|
+
if (front)
|
|
538
|
+
new cdk.CfnOutput(this, `Service${suffix}LoadBalancerDnsName`, { value: front.loadBalancerDnsName });
|
|
539
|
+
if (sharedPorts.length > 0 && pool.endpointService) {
|
|
540
|
+
new cdk.CfnOutput(this, `Service${suffix}EndpointService`, { value: pool.endpointService.vpcEndpointServiceName, description: `Shared ports ${sharedPorts.join(', ')} — what another venture's services[].external resolves to` });
|
|
541
|
+
}
|
|
542
|
+
new cdk.CfnOutput(this, `Service${suffix}LogGroup`, { value: logGroup.logGroupName });
|
|
543
|
+
new cdk.CfnOutput(this, `Service${suffix}Compute`, {
|
|
544
|
+
value: onInstance
|
|
545
|
+
? `instance pool ${pool.intent.id}: one task on each of ${pool.machines.min}–${pool.machines.max} machines (cluster ${pool.cluster.clusterName})`
|
|
546
|
+
: `serverless (${intent.cpu ?? 256} CPU units, ${intent.memoryMiB ?? 512} MiB, ${pool.architecture}, ${intent.replicas ?? 1} cop${(intent.replicas ?? 1) === 1 ? 'y' : 'ies'})`,
|
|
547
|
+
});
|
|
548
|
+
return { intent, pool, service, logGroup, alarms, url, loadBalancer, addresses, fileSystems };
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
function upperSnake(id) {
|
|
552
|
+
return String(id).toUpperCase().replace(/[^A-Z0-9_]/g, '_');
|
|
553
|
+
}
|
|
554
|
+
/** `my-service` → `MyService`, for construct ids. */
|
|
555
|
+
function logicalSuffix(id) {
|
|
556
|
+
return id
|
|
557
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
558
|
+
.filter(Boolean)
|
|
559
|
+
.map((part) => part[0].toUpperCase() + part.slice(1))
|
|
560
|
+
.join('');
|
|
561
|
+
}
|
|
562
|
+
//# sourceMappingURL=services-stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"services-stack.js","sourceRoot":"","sources":["../../src/cdk/services-stack.ts"],"names":[],"mappings":"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"}
|