@kapeta/local-cluster-service 0.9.1 → 0.10.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.
@@ -7,8 +7,8 @@ import { Docker } from 'node-docker-api';
7
7
  import { parseKapetaUri } from '@kapeta/nodejs-utils';
8
8
  import ClusterConfiguration from '@kapeta/local-cluster-config';
9
9
  import { Container } from 'node-docker-api/lib/container';
10
- import { getBindHost } from './utils/utils';
11
- import uuid from "node-uuid";
10
+ import uuid from 'node-uuid';
11
+ import md5 from 'md5';
12
12
 
13
13
  type StringMap = { [key: string]: string };
14
14
 
@@ -54,7 +54,7 @@ interface Health {
54
54
  retries?: number;
55
55
  }
56
56
 
57
- const LABEL_PORT_PREFIX = 'kapeta_port-';
57
+ export const CONTAINER_LABEL_PORT_PREFIX = 'kapeta_port-';
58
58
  const NANO_SECOND = 1000000;
59
59
  const HEALTH_CHECK_INTERVAL = 3000;
60
60
  const HEALTH_CHECK_MAX = 20;
@@ -206,24 +206,21 @@ class ContainerManager {
206
206
  tag = 'latest';
207
207
  }
208
208
 
209
- if (tag !== 'latest') {
210
- if (IMAGE_PULL_CACHE[image]) {
211
- const timeSince = Date.now() - IMAGE_PULL_CACHE[image];
212
- if (timeSince < cacheForMS) {
213
- return;
214
- }
209
+ if (IMAGE_PULL_CACHE[image]) {
210
+ const timeSince = Date.now() - IMAGE_PULL_CACHE[image];
211
+ if (timeSince < cacheForMS) {
212
+ return false;
215
213
  }
214
+ }
216
215
 
217
- const imageTagList = (await this.docker().image.list())
218
- .map((image) => image.data as any)
219
- .filter((imageData) => !!imageData.RepoTags)
220
- .map((imageData) => imageData.RepoTags as string[]);
216
+ const imageTagList = (await this.docker().image.list())
217
+ .map((image) => image.data as any)
218
+ .filter((imageData) => !!imageData.RepoTags)
219
+ .map((imageData) => imageData.RepoTags as string[]);
221
220
 
222
- if (imageTagList.some((imageTags) => imageTags.indexOf(image) > -1)) {
223
- console.log('Image found: %s', image);
224
- return;
225
- }
226
- console.log('Image not found: %s', image);
221
+ if (imageTagList.some((imageTags) => imageTags.indexOf(image) > -1)) {
222
+ console.log('Image found: %s', image);
223
+ return false;
227
224
  }
228
225
 
229
226
  console.log('Pulling image: %s', image);
@@ -240,6 +237,8 @@ class ContainerManager {
240
237
  IMAGE_PULL_CACHE[image] = Date.now();
241
238
 
242
239
  console.log('Image pulled: %s', image);
240
+
241
+ return true;
243
242
  }
244
243
 
245
244
  toDockerMounts(mounts: StringMap) {
@@ -266,66 +265,63 @@ class ContainerManager {
266
265
  };
267
266
  }
268
267
 
269
- async run(
270
- image: string,
271
- name: string,
272
- opts: { ports: {}; mounts: {}; env: {}; cmd: string; health: Health }
273
- ): Promise<ContainerInfo> {
274
- const PortBindings: { [key: string]: any } = {};
275
- const Env: string[] = [];
276
- const Labels: StringMap = {
277
- kapeta: 'true',
278
- };
279
-
280
- await this.pull(image);
281
-
282
- const bindHost = getBindHost();
268
+ private applyHash(dockerOpts: any) {
269
+ if (dockerOpts?.Labels?.HASH) {
270
+ delete dockerOpts.Labels.HASH;
271
+ }
283
272
 
284
- const ExposedPorts: { [key: string]: any } = {};
273
+ const hash = md5(JSON.stringify(dockerOpts));
285
274
 
286
- _.forEach(opts.ports, (portInfo: any, containerPort) => {
287
- ExposedPorts['' + containerPort] = {};
288
- PortBindings['' + containerPort] = [
289
- {
290
- HostPort: '' + portInfo.hostPort,
291
- HostIp: bindHost,
292
- },
293
- ];
275
+ if (!dockerOpts.Labels) {
276
+ dockerOpts.Labels = {};
277
+ }
278
+ dockerOpts.Labels.HASH = hash;
279
+ }
294
280
 
295
- Labels[LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
296
- });
281
+ async ensureContainer(opts: any) {
282
+ let imagePulled = false;
283
+ try {
284
+ imagePulled = await this.pull(opts.Image);
285
+ } catch (e) {
286
+ console.warn('Failed to pull image. Continuing...', e);
287
+ }
297
288
 
298
- const Mounts = this.toDockerMounts(opts.mounts);
289
+ this.applyHash(opts);
290
+ if (!opts.name) {
291
+ console.log('Starting unnamed container: %s', opts.Image);
292
+ return this.startContainer(opts);
293
+ }
294
+ const containerInfo = await this.getContainerByName(opts.name);
295
+ if (imagePulled) {
296
+ console.log('New version of image was pulled: %s', opts.Image);
297
+ } else {
298
+ // If image was pulled always recreate
299
+ if (!containerInfo) {
300
+ console.log('Starting new container: %s', opts.name);
301
+ return this.startContainer(opts);
302
+ }
299
303
 
300
- _.forEach(opts.env, (value, name) => {
301
- Env.push(name + '=' + value);
302
- });
304
+ const containerData = containerInfo.native.data as any;
303
305
 
304
- let HealthCheck = undefined;
305
-
306
- if (opts.health) {
307
- HealthCheck = this.toDockerHealth(opts.health);
308
- }
309
- const dockerContainer = await this.startContainer({
310
- name: name,
311
- Image: image,
312
- Hostname: name + '.kapeta',
313
- Labels,
314
- Cmd: opts.cmd,
315
- ExposedPorts,
316
- Env,
317
- HealthCheck,
318
- HostConfig: {
319
- PortBindings,
320
- Mounts,
321
- },
322
- });
306
+ if (containerData?.Labels?.HASH === opts.Labels.HASH) {
307
+ if (!(await containerInfo.isRunning())) {
308
+ console.log('Starting previously created container: %s', opts.name);
309
+ await containerInfo.start();
310
+ } else {
311
+ console.log('Previously created container already running: %s', opts.name);
312
+ }
313
+ return containerInfo.native;
314
+ }
315
+ }
323
316
 
324
- if (opts.health) {
325
- await this.waitForHealthy(dockerContainer);
317
+ if (containerInfo) {
318
+ // Remove the container and start a new one
319
+ console.log('Replacing previously created container: %s', opts.name);
320
+ await containerInfo.remove({ force: true });
326
321
  }
327
322
 
328
- return new ContainerInfo(dockerContainer);
323
+ console.log('Starting new container: %s', opts.name);
324
+ return this.startContainer(opts);
329
325
  }
330
326
 
331
327
  async startContainer(opts: any) {
@@ -423,8 +419,8 @@ class ContainerManager {
423
419
  }
424
420
  }
425
421
 
426
- async remove(container:Container, opts?: { force?: boolean }) {
427
- const newName = 'deleting-' + uuid.v4()
422
+ async remove(container: Container, opts?: { force?: boolean }) {
423
+ const newName = 'deleting-' + uuid.v4();
428
424
  const containerData = container.data as any;
429
425
  // Rename the container first to avoid name conflicts if people start the same container
430
426
  await container.rename({ name: newName });
@@ -537,11 +533,11 @@ export class ContainerInfo {
537
533
  const ports: PortMap = {};
538
534
 
539
535
  _.forEach(inspectResult.Config.Labels, (portType, name) => {
540
- if (!name.startsWith(LABEL_PORT_PREFIX)) {
536
+ if (!name.startsWith(CONTAINER_LABEL_PORT_PREFIX)) {
541
537
  return;
542
538
  }
543
539
 
544
- const hostPort = name.substr(LABEL_PORT_PREFIX.length);
540
+ const hostPort = name.substr(CONTAINER_LABEL_PORT_PREFIX.length);
545
541
 
546
542
  portTypes[hostPort] = portType;
547
543
  });
@@ -559,7 +559,10 @@ export class InstanceManager {
559
559
  }
560
560
  }
561
561
 
562
- if (instance.desiredStatus === DesiredInstanceStatus.RUN && newStatus === InstanceStatus.STOPPED) {
562
+ if (
563
+ instance.desiredStatus === DesiredInstanceStatus.RUN &&
564
+ [InstanceStatus.STOPPED, InstanceStatus.FAILED, InstanceStatus.STOPPING].includes(newStatus)
565
+ ) {
563
566
  //If the instance is stopped but we want it to run, start it
564
567
  try {
565
568
  await this.start(instance.systemId, instance.instanceId);
@@ -569,7 +572,10 @@ export class InstanceManager {
569
572
  return;
570
573
  }
571
574
 
572
- if (instance.desiredStatus === DesiredInstanceStatus.STOP && newStatus === InstanceStatus.READY) {
575
+ if (
576
+ instance.desiredStatus === DesiredInstanceStatus.STOP &&
577
+ [InstanceStatus.READY, InstanceStatus.STARTING, InstanceStatus.UNHEALTHY].includes(newStatus)
578
+ ) {
573
579
  //If the instance is running but we want it to stop, stop it
574
580
  try {
575
581
  await this.stop(instance.systemId, instance.instanceId);
@@ -4,12 +4,14 @@ import md5 from 'md5';
4
4
  import { parseKapetaUri } from '@kapeta/nodejs-utils';
5
5
  import { serviceManager } from './serviceManager';
6
6
  import { storageService } from './storageService';
7
- import { ContainerInfo, containerManager } from './containerManager';
7
+ import { CONTAINER_LABEL_PORT_PREFIX, ContainerInfo, containerManager } from './containerManager';
8
8
  import FSExtra from 'fs-extra';
9
- import { AnyMap, EnvironmentType, OperatorInfo } from './types';
9
+ import { AnyMap, EnvironmentType, OperatorInfo, StringMap } from './types';
10
10
  import { BlockInstance, Resource } from '@kapeta/schemas';
11
11
  import { definitionsManager } from './definitionsManager';
12
- import { normalizeKapetaUri } from './utils/utils';
12
+ import { getBindHost, normalizeKapetaUri } from './utils/utils';
13
+ import _ from 'lodash';
14
+ import { Container } from 'node-docker-api/lib/container';
13
15
 
14
16
  const KIND_OPERATOR = 'core/resource-type-operator';
15
17
 
@@ -191,34 +193,58 @@ class OperatorManager {
191
193
  const mounts = containerManager.createMounts(resourceType, operatorData.mounts);
192
194
 
193
195
  const containerName = containerBaseName + '-' + md5(nameParts.join('_'));
194
- let container = await containerManager.get(containerName);
195
196
 
196
- const isRunning = container ? await container.isRunning() : false;
197
- if (container && !isRunning) {
198
- await container.start();
199
- }
197
+ const PortBindings: { [key: string]: any } = {};
198
+ const Env: string[] = [];
200
199
 
201
- if (!container) {
202
- container = await containerManager.run(operatorData.image, containerName, {
203
- mounts,
204
- ports,
205
- health: operatorData.health,
206
- env: operatorData.env,
207
- cmd: operatorData.cmd,
208
- });
209
- }
200
+ const Labels: StringMap = {
201
+ kapeta: 'true',
202
+ };
210
203
 
211
- try {
212
- if (operatorData.health) {
213
- await containerManager.waitForHealthy(container.native);
214
- } else {
215
- await containerManager.waitForReady(container.native);
216
- }
217
- } catch (e: any) {
218
- console.error(e.message);
204
+ const bindHost = getBindHost();
205
+
206
+ const ExposedPorts: { [key: string]: any } = {};
207
+
208
+ _.forEach(ports, (portInfo: any, containerPort) => {
209
+ ExposedPorts['' + containerPort] = {};
210
+ PortBindings['' + containerPort] = [
211
+ {
212
+ HostPort: '' + portInfo.hostPort,
213
+ HostIp: bindHost,
214
+ },
215
+ ];
216
+
217
+ Labels[CONTAINER_LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
218
+ });
219
+
220
+ const Mounts = containerManager.toDockerMounts(mounts);
221
+
222
+ _.forEach(operatorData.env, (value, name) => {
223
+ Env.push(name + '=' + value);
224
+ });
225
+
226
+ let HealthCheck = undefined;
227
+
228
+ if (operatorData.health) {
229
+ HealthCheck = containerManager.toDockerHealth(operatorData.health);
219
230
  }
220
231
 
221
- return container;
232
+ const container = await containerManager.ensureContainer({
233
+ name: containerName,
234
+ Image: operatorData.image,
235
+ Hostname: containerName + '.kapeta',
236
+ Labels,
237
+ Cmd: operatorData.cmd,
238
+ ExposedPorts,
239
+ Env,
240
+ HealthCheck,
241
+ HostConfig: {
242
+ PortBindings,
243
+ Mounts,
244
+ },
245
+ });
246
+
247
+ return new ContainerInfo(container);
222
248
  }
223
249
  }
224
250
 
@@ -7,9 +7,10 @@ import { containerManager, DockerMounts, toLocalBindVolume } from '../containerM
7
7
  import { LogData } from './LogData';
8
8
  import EventEmitter from 'events';
9
9
  import { clusterService } from '../clusterService';
10
- import { AnyMap, BlockProcessParams, ProcessInfo, InstanceType, StringMap } from '../types';
10
+ import { AnyMap, BlockProcessParams, InstanceType, ProcessInfo, StringMap } from '../types';
11
11
  import { Container } from 'node-docker-api/lib/container';
12
12
  import { definitionsManager } from '../definitionsManager';
13
+ import md5 from 'md5';
13
14
 
14
15
  const KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
15
16
  const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
@@ -169,29 +170,6 @@ export class BlockInstanceRunner {
169
170
  }
170
171
 
171
172
  const containerName = getBlockInstanceContainerName(blockInstance.id);
172
- const logs = new LogData();
173
- logs.addLog(`Starting block ${blockInstance.ref}`);
174
- let containerInfo = await containerManager.getContainerByName(containerName);
175
- let container = containerInfo?.native;
176
-
177
- console.log('Starting dev container', containerName);
178
-
179
- if (containerInfo) {
180
- console.log(`Dev container already exists. Deleting...`);
181
- try {
182
- await containerInfo.remove({
183
- force: true,
184
- });
185
- } catch (e: any) {
186
- throw new Error('Failed to delete existing container: ' + e.message);
187
- }
188
- container = undefined;
189
- containerInfo = undefined;
190
- }
191
-
192
- logs.addLog(`Creating new container for block: ${containerName}`);
193
- console.log('Creating new dev container', containerName, dockerImage);
194
- await containerManager.pull(dockerImage);
195
173
 
196
174
  const startCmd = localContainer.handlers?.onCreate ? localContainer.handlers.onCreate : '';
197
175
  const dockerOpts = localContainer.options ?? {};
@@ -228,8 +206,7 @@ export class BlockInstanceRunner {
228
206
  HealthCheck = containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
229
207
  }
230
208
 
231
- console.log('Starting dev container', containerName, dockerImage);
232
- container = await containerManager.startContainer({
209
+ return this.ensureContainer({
233
210
  Image: dockerImage,
234
211
  name: containerName,
235
212
  WorkingDir: workingDir,
@@ -256,9 +233,15 @@ export class BlockInstanceRunner {
256
233
  },
257
234
  ...dockerOpts,
258
235
  });
236
+ }
237
+
238
+ private async ensureContainer(opts: any) {
239
+ const logs = new LogData();
240
+
241
+ const container = await containerManager.ensureContainer(opts);
259
242
 
260
243
  try {
261
- if (HealthCheck) {
244
+ if (opts.HealthCheck) {
262
245
  await containerManager.waitForHealthy(container);
263
246
  } else {
264
247
  await containerManager.waitForReady(container);
@@ -352,47 +335,25 @@ export class BlockInstanceRunner {
352
335
 
353
336
  const containerName = getBlockInstanceContainerName(blockInstance.id);
354
337
  const logs = new LogData();
355
- const containerInfo = await containerManager.getContainerByName(containerName);
356
- let container = containerInfo?.native;
357
338
 
358
339
  // For windows we need to default to root
359
340
  const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
360
341
 
361
- if (container) {
362
- const containerData = container.data as any;
363
- if (containerData.State === 'running') {
364
- logs.addLog(`Found existing running container for block: ${containerName}`);
365
- } else {
366
- logs.addLog(`Found existing container for block: ${containerName}. Starting now`);
367
- await container.start();
368
- }
369
- } else {
370
- logs.addLog(`Creating new container for block: ${containerName}`);
371
-
372
- container = await containerManager.startContainer({
373
- Image: dockerImage,
374
- name: containerName,
375
- Labels: {
376
- instance: blockInstance.id,
377
- },
378
- Env: [
379
- ...DOCKER_ENV_VARS,
380
- `KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
381
- ...Object.entries(env).map(([key, value]) => `${key}=${value}`),
382
- ],
383
- HostConfig: {
384
- Binds: [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`],
385
- },
386
- });
387
-
388
- try {
389
- await containerManager.waitForReady(container);
390
- } catch (e: any) {
391
- logs.addLog(e.message, 'ERROR');
392
- }
393
- }
394
-
395
- return this._handleContainer(container, logs);
342
+ return this.ensureContainer({
343
+ Image: dockerImage,
344
+ name: containerName,
345
+ Labels: {
346
+ instance: blockInstance.id,
347
+ },
348
+ Env: [
349
+ ...DOCKER_ENV_VARS,
350
+ `KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
351
+ ...Object.entries(env).map(([key, value]) => `${key}=${value}`),
352
+ ],
353
+ HostConfig: {
354
+ Binds: [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`],
355
+ },
356
+ });
396
357
  }
397
358
 
398
359
  /**
@@ -430,130 +391,79 @@ export class BlockInstanceRunner {
430
391
 
431
392
  const dockerImage = spec?.local?.image;
432
393
 
433
- try {
434
- await containerManager.pull(dockerImage);
435
- } catch (e) {
436
- console.warn('Failed to pull image. Continuing...', e);
437
- }
438
-
439
394
  const containerName = getBlockInstanceContainerName(blockInstance.id);
440
395
  const logs = new LogData();
441
- const containerInfo = await containerManager.getContainerByName(containerName);
442
- let container = containerInfo?.native;
443
-
444
- if (container) {
445
- const containerData = container.data as any;
446
- if (containerData.State === 'running') {
447
- logs.addLog(`Found existing running container for block: ${containerName}`);
448
- } else {
449
- if (containerData.State?.ExitCode > 0) {
450
- logs.addLog(`Container exited with code: ${containerData.State.ExitCode}. Deleting...`);
451
- try {
452
- await containerManager.remove(container);
453
- } catch (e) {}
454
- container = undefined;
455
- } else {
456
- logs.addLog(`Found existing container for block: ${containerName}. Starting now`);
457
- try {
458
- await container.start();
459
- } catch (e) {
460
- console.warn('Failed to start container. Deleting...', e);
461
- try {
462
- await containerManager.remove(container);
463
- } catch (e) {}
464
- container = undefined;
465
- }
466
- }
467
- }
468
- }
469
396
 
470
397
  const bindHost = getBindHost();
471
398
 
472
- if (!container) {
473
- const ExposedPorts: AnyMap = {};
474
- const addonEnv: StringMap = {};
475
- const PortBindings: AnyMap = {};
476
- let HealthCheck = undefined;
477
- let Mounts: DockerMounts[] = [];
478
- const promises = Object.entries(spec.local.ports as { [p: string]: { port: string; type: string } }).map(
479
- async ([portType, value]) => {
480
- const dockerPort = `${value.port}/${value.type}`;
481
- ExposedPorts[dockerPort] = {};
482
- addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = value.port;
483
- const publicPort = await serviceManager.ensureServicePort(
484
- this._systemId,
485
- blockInstance.id,
486
- portType
487
- );
488
- PortBindings[dockerPort] = [
489
- {
490
- HostIp: bindHost,
491
- HostPort: `${publicPort}`,
492
- },
493
- ];
494
- }
495
- );
496
-
497
- await Promise.all(promises);
498
-
499
- if (spec.local?.env) {
500
- Object.entries(spec.local.env).forEach(([key, value]) => {
501
- addonEnv[key] = value as string;
502
- });
503
- }
504
-
505
- if (spec.local?.mounts) {
506
- const mounts = containerManager.createMounts(blockUri.id, spec.local.mounts);
507
- Mounts = containerManager.toDockerMounts(mounts);
399
+ const ExposedPorts: AnyMap = {};
400
+ const addonEnv: StringMap = {};
401
+ const PortBindings: AnyMap = {};
402
+ let HealthCheck = undefined;
403
+ let Mounts: DockerMounts[] = [];
404
+ const promises = Object.entries(spec.local.ports as { [p: string]: { port: string; type: string } }).map(
405
+ async ([portType, value]) => {
406
+ const dockerPort = `${value.port}/${value.type}`;
407
+ ExposedPorts[dockerPort] = {};
408
+ addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = value.port;
409
+ const publicPort = await serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
410
+ PortBindings[dockerPort] = [
411
+ {
412
+ HostIp: bindHost,
413
+ HostPort: `${publicPort}`,
414
+ },
415
+ ];
508
416
  }
417
+ );
509
418
 
510
- if (spec.local?.health) {
511
- HealthCheck = containerManager.toDockerHealth(spec.local?.health);
512
- }
419
+ await Promise.all(promises);
513
420
 
514
- // For windows we need to default to root
515
- const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
516
-
517
- logs.addLog(`Creating new container for block: ${containerName}`);
518
- container = await containerManager.startContainer({
519
- Image: dockerImage,
520
- name: containerName,
521
- ExposedPorts,
522
- HealthCheck,
523
- HostConfig: {
524
- Binds: [
525
- `${toLocalBindVolume(kapetaYmlPath)}:/kapeta.yml:ro`,
526
- `${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
527
- ],
528
- PortBindings,
529
- Mounts,
530
- },
531
- Labels: {
532
- instance: blockInstance.id,
533
- },
534
- Env: [
535
- `KAPETA_INSTANCE_NAME=${blockInstance.ref}`,
536
- `KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
537
- ...DOCKER_ENV_VARS,
538
- ...Object.entries({
539
- ...env,
540
- ...addonEnv,
541
- }).map(([key, value]) => `${key}=${value}`),
542
- ],
421
+ if (spec.local?.env) {
422
+ Object.entries(spec.local.env).forEach(([key, value]) => {
423
+ addonEnv[key] = value as string;
543
424
  });
425
+ }
544
426
 
545
- try {
546
- if (HealthCheck) {
547
- await containerManager.waitForHealthy(container);
548
- } else {
549
- await containerManager.waitForReady(container);
550
- }
551
- } catch (e: any) {
552
- logs.addLog(e.message, 'ERROR');
553
- }
427
+ if (spec.local?.mounts) {
428
+ const mounts = containerManager.createMounts(blockUri.id, spec.local.mounts);
429
+ Mounts = containerManager.toDockerMounts(mounts);
554
430
  }
555
431
 
556
- const out = await this._handleContainer(container, logs, true);
432
+ if (spec.local?.health) {
433
+ HealthCheck = containerManager.toDockerHealth(spec.local?.health);
434
+ }
435
+
436
+ // For windows we need to default to root
437
+ const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
438
+
439
+ logs.addLog(`Creating new container for block: ${containerName}`);
440
+ const out = await this.ensureContainer({
441
+ Image: dockerImage,
442
+ name: containerName,
443
+ ExposedPorts,
444
+ HealthCheck,
445
+ HostConfig: {
446
+ Binds: [
447
+ `${toLocalBindVolume(kapetaYmlPath)}:/kapeta.yml:ro`,
448
+ `${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
449
+ ],
450
+ PortBindings,
451
+ Mounts,
452
+ },
453
+ Labels: {
454
+ instance: blockInstance.id,
455
+ },
456
+ Env: [
457
+ `KAPETA_INSTANCE_NAME=${blockInstance.ref}`,
458
+ `KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
459
+ ...DOCKER_ENV_VARS,
460
+ ...Object.entries({
461
+ ...env,
462
+ ...addonEnv,
463
+ }).map(([key, value]) => `${key}=${value}`),
464
+ ],
465
+ });
466
+
557
467
  const portTypes = spec.local.ports ? Object.keys(spec.local.ports) : [];
558
468
  if (portTypes.length > 0) {
559
469
  out.portType = portTypes[0];