@ossy/deployment-tools 3.0.8 → 3.1.0

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.
Files changed (33) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +160 -113
  3. package/jest.config.js +5 -0
  4. package/package.json +6 -4
  5. package/src/config/platform-config.js +16 -16
  6. package/src/ecs/platform-ecs-services.js +111 -0
  7. package/src/ecs/platform-ecs-services.spec.js +77 -0
  8. package/src/edge/platform-edge-domains.js +101 -0
  9. package/src/edge/platform-edge-domains.spec.js +87 -0
  10. package/src/index.js +33 -1
  11. package/src/infrastructure/dns-stack.js +47 -3
  12. package/src/infrastructure/dns-stack.spec.js +15 -0
  13. package/src/infrastructure/platform-ci-stack.js +151 -0
  14. package/src/infrastructure/platform-ecs-stack.js +326 -0
  15. package/src/infrastructure/platform-edge-stack.js +213 -0
  16. package/src/infrastructure/platform-secrets-stack.js +103 -0
  17. package/src/infrastructure/platform-stage.js +32 -5
  18. package/src/infrastructure/storage-static-stack.js +4 -5
  19. package/src/secrets/platform-secret-services.js +32 -0
  20. package/src/secrets/platform-secret-services.spec.js +40 -0
  21. package/src/secrets/sync-platform-secrets.js +136 -0
  22. package/src/services/platform-services.js +94 -0
  23. package/src/services/platform-services.spec.js +80 -0
  24. package/src/template/platform-template.js +5 -5
  25. package/src/infrastructure/container-deployment-target/aws-profile.js +0 -25
  26. package/src/infrastructure/container-deployment-target/caddy.service.js +0 -117
  27. package/src/infrastructure/container-deployment-target/container-deployment-target.js +0 -222
  28. package/src/infrastructure/container-deployment-target/container-service.js +0 -162
  29. package/src/infrastructure/container-deployment-target/index.js +0 -3
  30. package/src/infrastructure/container-deployment-target/ossy-api.service.js +0 -54
  31. package/src/infrastructure/container-deployment-target/ossy-runtime.service.js +0 -49
  32. package/src/infrastructure/container-deployment-target/user-data-commands.js +0 -31
  33. package/src/infrastructure/deployment-target-stack.js +0 -53
@@ -1,222 +0,0 @@
1
- const { Construct } = require('constructs')
2
- const {
3
- Instance,
4
- InstanceType,
5
- InstanceClass,
6
- InstanceSize,
7
- GenericLinuxImage,
8
- Vpc,
9
- SecurityGroup,
10
- Peer,
11
- Port,
12
- UserData,
13
- KeyPair,
14
- BlockDeviceVolume,
15
- CfnEIP,
16
- CfnEIPAssociation
17
- } = require('aws-cdk-lib/aws-ec2')
18
- const { Role, ServicePrincipal, Policy, PolicyStatement, Effect } = require('aws-cdk-lib/aws-iam')
19
- const { Source, BucketDeployment } = require('aws-cdk-lib/aws-s3-deployment')
20
- const { getInstallNodeJs, getInstallNpm, getInstallDocker } = require('./user-data-commands')
21
- const { CaddyService } = require('./caddy.service')
22
- const { OssyRuntimeService } = require('./ossy-runtime.service')
23
- const { OssyApiService } = require('./ossy-api.service')
24
- const { fromConfig: buildContainerServices } = require('./container-service')
25
- const { SupportedRegions } = require('../../config')
26
-
27
- /**
28
- * ContainerServerProps
29
- * @namespace ContainerServer
30
- * @typedef {Object} ContainerServerProps
31
- * @property {PlatformConfig} config - platform config
32
- * @property {Bucket} bucket - s3 bucket
33
- */
34
-
35
- const InstanceImages = {
36
- UBUNTU: 'ami-067bcf851477ebb78' // Ubuntu Server 24.04 LTS (HVM), eu-north-1
37
- }
38
-
39
- /**
40
- * @class
41
- */
42
- class ContainerDeploymentTarget extends Construct {
43
-
44
- /**
45
- * @param {object} scope - scope
46
- * @param {string} id - id
47
- * @param {ContainerServerProps} props - ContainerServerProps
48
- */
49
- constructor(scope, id, props) {
50
- super(scope, id)
51
-
52
- const vpc = Vpc.fromLookup(this, 'VPC', { isDefault: true })
53
- const securityGroup = new SecurityGroup(this, 'SecurityGroup', { vpc, allowAllOutbound: true })
54
-
55
- securityGroup.addIngressRule(
56
- Peer.anyIpv4(),
57
- Port.tcp(22),
58
- 'allow SSH access from anywhere'
59
- )
60
-
61
- securityGroup.addIngressRule(
62
- Peer.anyIpv4(),
63
- Port.tcp(80),
64
- 'allow HTTP traffic from anywhere'
65
- )
66
-
67
- securityGroup.addIngressRule(
68
- Peer.anyIpv4(),
69
- Port.tcp(443),
70
- 'allow HTTPS traffic from anywhere'
71
- )
72
-
73
- // Build container services from config — opens additional security group ports for TCP/UDP services
74
- const containerServices = buildContainerServices(props.config.services)
75
-
76
- containerServices.forEach(service => {
77
- service.securityGroupPorts.forEach(({ port, protocol }) => {
78
- const portRule = protocol === 'udp' ? Port.udp(port) : Port.tcp(port)
79
- securityGroup.addIngressRule(Peer.anyIpv4(), portRule, `${service.name} ${protocol.toUpperCase()} ${port}`)
80
- })
81
- })
82
-
83
- const platformConfigDeployment = new BucketDeployment(this, 'PlatformConfigDeployment', {
84
- sources: [Source.jsonData('platform-config.json', { ...props.config, env: undefined })],
85
- destinationBucket: props.bucket,
86
- // Default prune:true would delete every other object (e.g. media/*) on each infra deploy.
87
- prune: false
88
- })
89
-
90
- const role = new Role(this, 'role', {
91
- assumedBy: new ServicePrincipal('ec2.amazonaws.com')
92
- })
93
-
94
- role.attachInlinePolicy(new Policy(this, 'policy', {
95
- statements: [
96
- new PolicyStatement({
97
- effect: Effect.ALLOW,
98
- actions: [
99
- 'route53:ListResourceRecordSets',
100
- 'route53:GetChange',
101
- 'route53:ChangeResourceRecordSets'
102
- ],
103
- resources: [
104
- `arn:aws:route53:::hostedzone/*`,
105
- 'arn:aws:route53:::change/*'
106
- ]
107
- }),
108
- new PolicyStatement({
109
- effect: Effect.ALLOW,
110
- actions: [
111
- 'route53:ListHostedZonesByName',
112
- 'route53:ListHostedZones'
113
- ],
114
- resources: ['*']
115
- }),
116
- ]
117
- }))
118
-
119
- const userData = UserData.forLinux()
120
-
121
- // Write platform env vars to /etc/environment so all systemd services pick them up.
122
- const envLines = Object.entries(props.config.env ?? {}).map(([k, v]) => `${k}=${v}`)
123
-
124
- userData.addCommands(
125
- 'sudo groupadd docker',
126
- 'sudo usermod -aG docker ubuntu',
127
- 'newgrp docker',
128
- 'sudo apt update -y',
129
- ...getInstallNodeJs(),
130
- ...getInstallNpm(),
131
- ...getInstallDocker(),
132
- 'sudo apt-get install awscli --yes',
133
- // Write all platform env vars before starting any service
134
- `sudo tee /etc/environment << 'ENVEOF'\n${envLines.join('\n')}\nENVEOF`,
135
- // Create shared Docker network for inter-container communication
136
- 'docker network create ossy-network || true',
137
- ...CaddyService.install(containerServices.filter(s => s.caddyBlock !== null)),
138
- ...OssyRuntimeService.install(),
139
- ...OssyApiService.install(),
140
- ...containerServices.flatMap(s => s.install())
141
- )
142
-
143
- userData.addS3DownloadCommand({
144
- bucket: props.bucket,
145
- bucketKey: 'platform-config.json',
146
- localFile: '/home/ubuntu/platform-config.json'
147
- })
148
-
149
- userData.addCommands(
150
- 'sudo systemctl daemon-reload',
151
- ...CaddyService.enable(),
152
- ...CaddyService.start(),
153
- ...OssyRuntimeService.enable(),
154
- ...OssyRuntimeService.start(),
155
- ...OssyApiService.enable(),
156
- ...OssyApiService.start(),
157
- ...containerServices.flatMap(s => [...s.enable(), ...s.start()])
158
- )
159
-
160
- const instanceClassMap = {
161
- t2: InstanceClass.T2,
162
- t3: InstanceClass.T3,
163
- t3a: InstanceClass.T3A,
164
- t4g: InstanceClass.T4G,
165
- m5: InstanceClass.M5,
166
- m6i: InstanceClass.M6I,
167
- c5: InstanceClass.C5,
168
- c6i: InstanceClass.C6I,
169
- }
170
-
171
- const instanceSizeMap = {
172
- nano: InstanceSize.NANO,
173
- micro: InstanceSize.MICRO,
174
- small: InstanceSize.SMALL,
175
- medium: InstanceSize.MEDIUM,
176
- large: InstanceSize.LARGE,
177
- xlarge: InstanceSize.XLARGE,
178
- '2xlarge': InstanceSize.XLARGE2,
179
- }
180
-
181
- const instanceClass = instanceClassMap[props.config.awsInstanceClass ?? 't3']
182
- const instanceSize = instanceSizeMap[props.config.awsInstanceSize ?? 'small']
183
-
184
- if (!instanceClass) throw new Error(`[ContainerDeploymentTarget] Unknown awsInstanceClass: ${props.config.awsInstanceClass}`)
185
- if (!instanceSize) throw new Error(`[ContainerDeploymentTarget] Unknown awsInstanceSize: ${props.config.awsInstanceSize}`)
186
-
187
- const ec2Instance = new Instance(this, 'Ec2Instance', {
188
- vpc,
189
- securityGroup,
190
- userData,
191
- role,
192
- instanceType: InstanceType.of(instanceClass, instanceSize),
193
- machineImage: new GenericLinuxImage({
194
- [SupportedRegions.North]: InstanceImages.UBUNTU
195
- }),
196
- blockDevices: [
197
- {
198
- deviceName: '/dev/sda1',
199
- volume: BlockDeviceVolume.ebs(50)
200
- }
201
- ],
202
- keyPair: KeyPair.fromKeyPairName(this, 'KeyPair', props.config.awsKeyPairName)
203
- })
204
-
205
- props.bucket.grantRead(ec2Instance, '*')
206
-
207
- // Elastic IP gives the instance a stable public IP that survives instance replacements,
208
- // preventing CloudFormation cross-stack export conflicts when the EC2 instance is updated.
209
- const eip = new CfnEIP(this, 'ElasticIp', { domain: 'vpc' })
210
- new CfnEIPAssociation(this, 'EipAssociation', {
211
- instanceId: ec2Instance.instanceId,
212
- allocationId: eip.attrAllocationId
213
- })
214
-
215
- this.instancePublicIp = eip.attrPublicIp
216
-
217
- }
218
- }
219
-
220
- module.exports = {
221
- ContainerDeploymentTarget
222
- }
@@ -1,162 +0,0 @@
1
- /**
2
- * @typedef {'http'|'tcp'} ServiceType
3
- *
4
- * @typedef {Object} HttpServiceConfig
5
- * @property {'http'} [type] - defaults to 'http'
6
- * @property {string} name - unique name, used for container name and systemd unit
7
- * @property {string} domain - domain this service handles (Caddy block + Route53)
8
- * @property {string} image - Docker image to run
9
- *
10
- * @typedef {Object} TcpServiceConfig
11
- * @property {'tcp'} type - marks this as a raw TCP/UDP service (no HTTP/Caddy)
12
- * @property {string} name - unique name, used for container name and systemd unit
13
- * @property {string} image - Docker image to run
14
- * @property {number[]} ports - ports to expose directly (same inside and outside container)
15
- * @property {'tcp'|'udp'|'both'} [protocol] - defaults to 'tcp'
16
- *
17
- * @typedef {HttpServiceConfig|TcpServiceConfig} ContainerServiceConfig
18
- */
19
-
20
- const BASE_HTTP_PORT = 3002 // 3000 = platform runtime, 3001 = API
21
-
22
- // ---------------------------------------------------------------------------
23
- // HTTP service — reverse-proxied through Caddy, container listens on port 3000
24
- // ---------------------------------------------------------------------------
25
-
26
- class HttpContainerService {
27
- constructor({ name, domain, image }, httpIndex) {
28
- this.name = name
29
- this.domain = domain
30
- this.image = image
31
- this.hostPort = BASE_HTTP_PORT + httpIndex
32
- }
33
-
34
- get systemdUnitFile() {
35
- return `
36
- [Unit]
37
- Description=Container service: ${this.name} (${this.domain})
38
- After=network.target docker.service
39
- Requires=docker.service
40
-
41
- [Service]
42
- EnvironmentFile=/etc/environment
43
- ExecStartPre=-/usr/bin/docker rm -f ${this.name}
44
- ExecStartPre=/usr/bin/docker pull ${this.image}
45
- ExecStart=/usr/bin/docker run --name ${this.name} \\
46
- --network ossy-network \\
47
- -p ${this.hostPort}:3000 \\
48
- --env-file /etc/environment \\
49
- ${this.image}
50
- ExecStop=/usr/bin/docker stop ${this.name}
51
- Restart=on-failure
52
- RestartSec=5
53
-
54
- [Install]
55
- WantedBy=multi-user.target
56
- `
57
- }
58
-
59
- get caddyBlock() {
60
- return `
61
- ${this.domain} {
62
- tls {
63
- dns route53 {
64
- max_retries 10
65
- }
66
- }
67
- reverse_proxy localhost:${this.hostPort}
68
- }`
69
- }
70
-
71
- /** Ports to open in the EC2 security group. HTTP services use Caddy on 80/443 — no extra rules needed. */
72
- get securityGroupPorts() {
73
- return []
74
- }
75
-
76
- get unitName() { return `${this.name}.service` }
77
- install() { return [`sudo tee /etc/systemd/system/${this.unitName} > /dev/null << 'EOF'\n${this.systemdUnitFile}\nEOF`] }
78
- enable() { return [`sudo systemctl enable ${this.name}`] }
79
- start() { return [`sudo systemctl start ${this.name}`] }
80
- }
81
-
82
- // ---------------------------------------------------------------------------
83
- // TCP/UDP service — bypasses Caddy, ports exposed directly on the host.
84
- // Used for game servers and any other raw socket services.
85
- // ---------------------------------------------------------------------------
86
-
87
- class TcpContainerService {
88
- constructor({ name, image, ports, protocol = 'tcp' }) {
89
- this.name = name
90
- this.image = image
91
- this.ports = ports
92
- this.protocol = protocol // 'tcp' | 'udp' | 'both'
93
- }
94
-
95
- get systemdUnitFile() {
96
- const portMappings = this.ports.map(p => `-p ${p}:${p}`).join(' \\\n ')
97
- return `
98
- [Unit]
99
- Description=Container service: ${this.name} (${this.protocol.toUpperCase()} ${this.ports.join(', ')})
100
- After=network.target docker.service
101
- Requires=docker.service
102
-
103
- [Service]
104
- EnvironmentFile=/etc/environment
105
- ExecStartPre=-/usr/bin/docker rm -f ${this.name}
106
- ExecStartPre=/usr/bin/docker pull ${this.image}
107
- ExecStart=/usr/bin/docker run --name ${this.name} \\
108
- --network ossy-network \\
109
- ${portMappings} \\
110
- --env-file /etc/environment \\
111
- ${this.image}
112
- ExecStop=/usr/bin/docker stop ${this.name}
113
- Restart=on-failure
114
- RestartSec=5
115
-
116
- [Install]
117
- WantedBy=multi-user.target
118
- `
119
- }
120
-
121
- /** TCP services bypass Caddy — no Caddy block. */
122
- get caddyBlock() { return null }
123
-
124
- /** Each port needs an explicit security group ingress rule. */
125
- get securityGroupPorts() {
126
- return this.ports.flatMap(port => {
127
- if (this.protocol === 'both') return [{ port, protocol: 'tcp' }, { port, protocol: 'udp' }]
128
- return [{ port, protocol: this.protocol }]
129
- })
130
- }
131
-
132
- get unitName() { return `${this.name}.service` }
133
- install() { return [`sudo tee /etc/systemd/system/${this.unitName} > /dev/null << 'EOF'\n${this.systemdUnitFile}\nEOF`] }
134
- enable() { return [`sudo systemctl enable ${this.name}`] }
135
- start() { return [`sudo systemctl start ${this.name}`] }
136
- }
137
-
138
- // ---------------------------------------------------------------------------
139
- // Factory
140
- // ---------------------------------------------------------------------------
141
-
142
- /**
143
- * Build service instances from the `services` array in platforms.json.
144
- * HTTP services auto-assign host ports starting at 3002 (counted separately
145
- * from TCP services so reordering TCP entries doesn't shift HTTP ports).
146
- *
147
- * @param {ContainerServiceConfig[]} services
148
- * @returns {(HttpContainerService|TcpContainerService)[]}
149
- */
150
- const fromConfig = (services = []) => {
151
- let httpIndex = 0
152
- return services.map(s => {
153
- if (s.type === 'tcp') return new TcpContainerService(s)
154
- return new HttpContainerService(s, httpIndex++)
155
- })
156
- }
157
-
158
- module.exports = {
159
- HttpContainerService,
160
- TcpContainerService,
161
- fromConfig
162
- }
@@ -1,3 +0,0 @@
1
- const { ContainerDeploymentTarget } = require('./container-deployment-target')
2
-
3
- module.exports = { ContainerDeploymentTarget }
@@ -1,54 +0,0 @@
1
- const systemdServiceFile = `
2
- [Unit]
3
- Description=Ossy API
4
- After=network.target docker.service
5
- Requires=docker.service
6
-
7
- [Service]
8
- EnvironmentFile=/etc/environment
9
- ExecStartPre=-/usr/bin/docker rm -f ossy-api
10
- ExecStartPre=/usr/bin/docker pull ghcr.io/ossy-se/api:latest
11
- ExecStart=/usr/bin/docker run --name ossy-api \\
12
- --network ossy-network \\
13
- -p 3001:3000 \\
14
- -e DB_URL=\${DB_URL} \\
15
- -e DB_NAME=\${DB_NAME} \\
16
- -e TOKEN_SECRET=\${TOKEN_SECRET} \\
17
- -e MEDIA_REPOSITORY=\${MEDIA_REPOSITORY} \\
18
- -e MEDIA_CDN_DOMAIN_NAME=\${MEDIA_CDN_DOMAIN_NAME} \\
19
- -e AWS_ACCESS_KEY_ID=\${AWS_ACCESS_KEY_ID} \\
20
- -e AWS_SECRET_ACCESS_KEY=\${AWS_SECRET_ACCESS_KEY} \\
21
- ghcr.io/ossy-se/api:latest
22
- ExecStop=/usr/bin/docker stop ossy-api
23
- Restart=on-failure
24
- RestartSec=5
25
-
26
- [Install]
27
- WantedBy=multi-user.target
28
- `
29
-
30
- // The image is pulled automatically on every start via ExecStartPre, so the
31
- // service always runs the latest published version. To redeploy: systemctl restart ossy-api
32
-
33
- /**
34
- * @class
35
- */
36
- class OssyApiService {
37
-
38
- static install() {
39
- return [`sudo tee /etc/systemd/system/ossy-api.service > /dev/null << 'EOF'\n${systemdServiceFile}\nEOF`]
40
- }
41
-
42
- static enable() {
43
- return ['sudo systemctl enable ossy-api']
44
- }
45
-
46
- static start() {
47
- return ['sudo systemctl start ossy-api']
48
- }
49
-
50
- }
51
-
52
- module.exports = {
53
- OssyApiService
54
- }
@@ -1,49 +0,0 @@
1
- const systemdServiceFile = `
2
- [Unit]
3
- Description=Ossy Runtime
4
- After=network.target docker.service
5
- Requires=docker.service
6
-
7
- [Service]
8
- EnvironmentFile=/etc/environment
9
- ExecStartPre=-/usr/bin/docker rm -f ossy-runtime
10
- ExecStartPre=/usr/bin/docker pull ghcr.io/ossy-se/platform:latest
11
- ExecStart=/usr/bin/docker run --name ossy-runtime \\
12
- --network ossy-network \\
13
- -p 3000:3000 \\
14
- -e OSSY_API_KEY=\${OSSY_API_KEY} \\
15
- -e OSSY_API_URL=http://ossy-api:3001/api/v0 \\
16
- ghcr.io/ossy-se/platform:latest
17
- ExecStop=/usr/bin/docker stop ossy-runtime
18
- Restart=on-failure
19
- RestartSec=5
20
-
21
- [Install]
22
- WantedBy=multi-user.target
23
- `
24
-
25
- // The image is pulled automatically on every start via ExecStartPre, so the
26
- // service always runs the latest published version. To redeploy: systemctl restart ossy-runtime
27
-
28
- /**
29
- * @class
30
- */
31
- class OssyRuntimeService {
32
-
33
- static install() {
34
- return [`sudo tee /etc/systemd/system/ossy-runtime.service > /dev/null << 'EOF'\n${systemdServiceFile}\nEOF`]
35
- }
36
-
37
- static enable() {
38
- return ['sudo systemctl enable ossy-runtime']
39
- }
40
-
41
- static start() {
42
- return ['sudo systemctl start ossy-runtime']
43
- }
44
-
45
- }
46
-
47
- module.exports = {
48
- OssyRuntimeService
49
- }
@@ -1,31 +0,0 @@
1
- const getInstallDocker = () => [
2
- 'apt-get remove docker docker-engine docker.io containerd runc',
3
- `apt-get install \
4
- apt-transport-https \
5
- ca-certificates \
6
- curl \
7
- gnupg-agent \
8
- software-properties-common -y`,
9
- 'curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -',
10
- `sudo add-apt-repository \
11
- "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
12
- $(lsb_release -cs) \
13
- stable"`,
14
- 'sudo apt-get update',
15
- 'sudo apt-get install docker-ce docker-ce-cli containerd.io -y'
16
- ]
17
-
18
- const getInstallNodeJs = () => [
19
- 'curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -',
20
- 'sudo apt-get -y install nodejs'
21
- ]
22
-
23
- const getInstallNpm = () => [
24
- 'sudo apt install npm'
25
- ]
26
-
27
- module.exports = {
28
- getInstallDocker,
29
- getInstallNodeJs,
30
- getInstallNpm
31
- }
@@ -1,53 +0,0 @@
1
- /* eslint-disable no-new */
2
- const { CfnOutput, Stack } = require('aws-cdk-lib')
3
- const { ContainerDeploymentTarget } = require('./container-deployment-target')
4
-
5
- /**
6
- * DeploymentTargetStackProps
7
- * @typedef {Object} DeploymentTargetStackProps
8
- * @property {PlatformConfig} config - platform config
9
- * @property {import('aws-cdk-lib/aws-s3').IBucket} bucket - static assets bucket (from StorageStaticStack)
10
- * @property {string} cdnDomainName - CloudFront domain name (from StorageStaticStack)
11
- */
12
-
13
- /**
14
- * DeploymentTargetStack provisions the EC2 instance (with Elastic IP) that runs the
15
- * platform services. The S3 bucket lives in StorageStaticStack so that EC2 replacements
16
- * never trigger CloudFormation cross-stack export conflicts on storage resources.
17
- *
18
- * MEDIA_REPOSITORY and MEDIA_CDN_DOMAIN_NAME are derived from the actual bucket and CDN
19
- * resources rather than being hardcoded in platforms.json.
20
- */
21
- class DeploymentTargetStack extends Stack {
22
- constructor(scope, id, props) {
23
- super(scope, id, props)
24
-
25
- if (!props?.config) {
26
- throw ('[DeploymentTargetStack] No config provided')
27
- }
28
-
29
- const containerDeploymentTarget = new ContainerDeploymentTarget(this, 'ContainerDeploymentTarget', {
30
- config: {
31
- ...props.config,
32
- env: {
33
- ...props.config.env,
34
- MEDIA_REPOSITORY: props.bucket.bucketName,
35
- MEDIA_CDN_DOMAIN_NAME: `https://${props.cdnDomainName}`
36
- }
37
- },
38
- bucket: props.bucket
39
- })
40
-
41
- this.containerDeploymentTargetPublicIp = containerDeploymentTarget.instancePublicIp
42
-
43
- new CfnOutput(this, 'ContainerDeploymentTargetPublicIp', {
44
- value: containerDeploymentTarget.instancePublicIp,
45
- description: 'Public IP of the EC2 instance (Elastic IP)',
46
- exportName: `${props.config.platformName}-ContainerDeploymentTargetPublicIp`
47
- })
48
- }
49
- }
50
-
51
- module.exports = {
52
- DeploymentTargetStack
53
- }