@kapeta/local-cluster-service 0.19.5 → 0.19.7

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.
@@ -3,13 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.containerManager = exports.toLocalBindVolume = exports.getExtraHosts = exports.ContainerInfo = exports.HEALTH_CHECK_TIMEOUT = exports.CONTAINER_LABEL_PORT_PREFIX = void 0;
6
+ exports.containerManager = exports.toLocalBindVolume = exports.getExtraHosts = exports.ContainerInfo = exports.HEALTH_CHECK_TIMEOUT = exports.COMPOSE_LABEL_SERVICE = exports.COMPOSE_LABEL_PROJECT = exports.CONTAINER_LABEL_PORT_PREFIX = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const storageService_1 = require("./storageService");
9
9
  const os_1 = __importDefault(require("os"));
10
10
  const lodash_1 = __importDefault(require("lodash"));
11
11
  const fs_extra_1 = __importDefault(require("fs-extra"));
12
- const node_docker_api_1 = require("node-docker-api");
12
+ const dockerode_1 = __importDefault(require("dockerode"));
13
13
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
14
14
  const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
15
15
  const node_uuid_1 = __importDefault(require("node-uuid"));
@@ -18,15 +18,45 @@ const utils_1 = require("./utils/utils");
18
18
  const nodejs_api_client_1 = require("@kapeta/nodejs-api-client");
19
19
  const taskManager_1 = require("./taskManager");
20
20
  const node_events_1 = require("node:events");
21
+ const StreamValues_1 = __importDefault(require("stream-json/streamers/StreamValues"));
21
22
  exports.CONTAINER_LABEL_PORT_PREFIX = 'kapeta_port-';
22
23
  const NANO_SECOND = 1000000;
23
24
  const HEALTH_CHECK_INTERVAL = 3000;
24
25
  const HEALTH_CHECK_MAX = 20;
26
+ exports.COMPOSE_LABEL_PROJECT = 'com.docker.compose.project';
27
+ exports.COMPOSE_LABEL_SERVICE = 'com.docker.compose.service';
25
28
  exports.HEALTH_CHECK_TIMEOUT = HEALTH_CHECK_INTERVAL * HEALTH_CHECK_MAX * 2;
26
- const promisifyStream = (stream, handler) => new Promise((resolve, reject) => {
27
- stream.on('data', handler);
28
- stream.on('end', resolve);
29
- stream.on('error', reject);
29
+ var DockerPullEventTypes;
30
+ (function (DockerPullEventTypes) {
31
+ DockerPullEventTypes["PreparingPhase"] = "Preparing";
32
+ DockerPullEventTypes["WaitingPhase"] = "Waiting";
33
+ DockerPullEventTypes["PullingFsPhase"] = "Pulling fs layer";
34
+ DockerPullEventTypes["DownloadingPhase"] = "Downloading";
35
+ DockerPullEventTypes["DownloadCompletePhase"] = "Download complete";
36
+ DockerPullEventTypes["ExtractingPhase"] = "Extracting";
37
+ DockerPullEventTypes["VerifyingChecksumPhase"] = "Verifying Checksum";
38
+ DockerPullEventTypes["AlreadyExistsPhase"] = "Already exists";
39
+ DockerPullEventTypes["PullCompletePhase"] = "Pull complete";
40
+ })(DockerPullEventTypes || (DockerPullEventTypes = {}));
41
+ const processJsonStream = (purpose, stream, handler) => new Promise((resolve, reject) => {
42
+ const jsonStream = StreamValues_1.default.withParser();
43
+ jsonStream.on('data', (data) => {
44
+ try {
45
+ handler(data.value);
46
+ }
47
+ catch (e) {
48
+ console.error('Failed while processing data for stream: %s', purpose, e);
49
+ }
50
+ });
51
+ jsonStream.on('end', () => {
52
+ console.log('Docker stream ended: %s', purpose);
53
+ resolve();
54
+ });
55
+ jsonStream.on('error', (err) => {
56
+ console.error('Docker stream failed: %s', purpose, err);
57
+ reject(err);
58
+ });
59
+ stream.pipe(jsonStream);
30
60
  });
31
61
  class ContainerManager {
32
62
  _docker;
@@ -64,9 +94,9 @@ class ContainerManager {
64
94
  ];
65
95
  for (const opts of connectOptions) {
66
96
  try {
67
- const client = new node_docker_api_1.Docker({
97
+ const client = new dockerode_1.default({
68
98
  ...opts,
69
- timeout: 10000,
99
+ timeout: 15 * 60 * 1000, //15 minutes should be enough for any operation
70
100
  });
71
101
  await client.ping();
72
102
  this._docker = client;
@@ -143,13 +173,12 @@ class ContainerManager {
143
173
  return this._docker;
144
174
  }
145
175
  async getContainerByName(containerName) {
146
- const containers = await this.docker().container.list({ all: true });
176
+ const containers = await this.docker().listContainers({ all: true });
147
177
  const out = containers.find((container) => {
148
- const containerData = container.data;
149
- return containerData.Names.indexOf(`/${containerName}`) > -1;
178
+ return container.Names.indexOf(`/${containerName}`) > -1;
150
179
  });
151
180
  if (out) {
152
- return new ContainerInfo(out);
181
+ return this.get(out.Id);
153
182
  }
154
183
  return undefined;
155
184
  }
@@ -158,8 +187,7 @@ class ContainerManager {
158
187
  if (!tag) {
159
188
  tag = 'latest';
160
189
  }
161
- const imageTagList = (await this.docker().image.list())
162
- .map((image) => image.data)
190
+ const imageTagList = (await this.docker().listImages({}))
163
191
  .filter((imageData) => !!imageData.RepoTags)
164
192
  .map((imageData) => imageData.RepoTags);
165
193
  if (imageTagList.some((imageTags) => imageTags.indexOf(image) > -1)) {
@@ -184,66 +212,61 @@ class ContainerManager {
184
212
  serveraddress: 'docker.kapeta.com',
185
213
  }
186
214
  : {};
187
- const stream = (await this.docker().image.create(auth, {
188
- fromImage: imageName,
189
- tag: tag,
190
- }));
215
+ const stream = await this.docker().pull(image, {
216
+ authconfig: auth,
217
+ });
191
218
  const chunks = {};
192
219
  let lastEmitted = Date.now();
193
- await promisifyStream(stream, (rawData) => {
194
- const lines = rawData.toString().trim().split('\n');
195
- lines.forEach((line) => {
196
- const data = JSON.parse(line);
197
- if (![
198
- 'Waiting',
199
- 'Downloading',
200
- 'Extracting',
201
- 'Download complete',
202
- 'Pull complete',
203
- 'Already exists',
204
- ].includes(data.status)) {
205
- return;
206
- }
207
- if (!chunks[data.id]) {
208
- chunks[data.id] = {
209
- downloading: {
210
- total: 0,
211
- current: 0,
212
- },
213
- extracting: {
214
- total: 0,
215
- current: 0,
216
- },
217
- done: false,
220
+ await processJsonStream(`image:pull:${image}`, stream, (data) => {
221
+ if (!chunks[data.id]) {
222
+ chunks[data.id] = {
223
+ downloading: {
224
+ total: 0,
225
+ current: 0,
226
+ },
227
+ extracting: {
228
+ total: 0,
229
+ current: 0,
230
+ },
231
+ done: false,
232
+ };
233
+ }
234
+ const chunk = chunks[data.id];
235
+ switch (data.status) {
236
+ case DockerPullEventTypes.PreparingPhase:
237
+ case DockerPullEventTypes.WaitingPhase:
238
+ case DockerPullEventTypes.PullingFsPhase:
239
+ //Do nothing
240
+ break;
241
+ case DockerPullEventTypes.DownloadingPhase:
242
+ case DockerPullEventTypes.VerifyingChecksumPhase:
243
+ chunk.downloading = {
244
+ total: data.progressDetail?.total ?? 0,
245
+ current: data.progressDetail?.current ?? 0,
218
246
  };
219
- }
220
- const chunk = chunks[data.id];
221
- switch (data.status) {
222
- case 'Downloading':
223
- chunk.downloading = data.progressDetail;
224
- break;
225
- case 'Extracting':
226
- chunk.extracting = data.progressDetail;
227
- break;
228
- case 'Download complete':
229
- chunk.downloading.current = chunks[data.id].downloading.total;
230
- break;
231
- case 'Pull complete':
232
- chunk.extracting.current = chunks[data.id].extracting.total;
233
- chunk.done = true;
234
- break;
235
- case 'Already exists':
236
- // Force layer to be done
237
- chunk.downloading.current = 1;
238
- chunk.downloading.total = 1;
239
- chunk.extracting.current = 1;
240
- chunk.extracting.total = 1;
241
- chunk.done = true;
242
- break;
243
- }
244
- });
245
- if (Date.now() - lastEmitted < 1000) {
246
- return;
247
+ break;
248
+ case DockerPullEventTypes.ExtractingPhase:
249
+ chunk.extracting = {
250
+ total: data.progressDetail?.total ?? 0,
251
+ current: data.progressDetail?.current ?? 0,
252
+ };
253
+ break;
254
+ case DockerPullEventTypes.DownloadCompletePhase:
255
+ chunk.downloading.current = chunks[data.id].downloading.total;
256
+ break;
257
+ case DockerPullEventTypes.PullCompletePhase:
258
+ chunk.extracting.current = chunks[data.id].extracting.total;
259
+ chunk.done = true;
260
+ break;
261
+ }
262
+ if (data.status === DockerPullEventTypes.AlreadyExistsPhase ||
263
+ data.status.includes('Image is up to date') ||
264
+ data.status.includes('Downloaded newer image')) {
265
+ chunk.downloading.current = 1;
266
+ chunk.downloading.total = 1;
267
+ chunk.extracting.current = 1;
268
+ chunk.extracting.total = 1;
269
+ chunk.done = true;
247
270
  }
248
271
  const chunkList = Object.values(chunks);
249
272
  let totals = {
@@ -255,6 +278,7 @@ class ContainerManager {
255
278
  total: 0,
256
279
  current: 0,
257
280
  },
281
+ percent: 0,
258
282
  total: chunkList.length,
259
283
  done: 0,
260
284
  };
@@ -275,14 +299,17 @@ class ContainerManager {
275
299
  totals.done++;
276
300
  }
277
301
  });
278
- const progress = totals.total > 0 ? (totals.done / totals.total) * 100 : 0;
302
+ totals.percent = totals.total > 0 ? (totals.done / totals.total) * 100 : 0;
279
303
  task.metadata = {
280
304
  ...task.metadata,
281
305
  image,
282
- progress,
306
+ progress: totals.percent,
283
307
  status: totals,
284
308
  timeTaken: Date.now() - timeStarted,
285
309
  };
310
+ if (Date.now() - lastEmitted < 1000) {
311
+ return;
312
+ }
286
313
  task.emitUpdate();
287
314
  lastEmitted = Date.now();
288
315
  //console.log('Pulling image %s: %s % [done: %s, total: %s]', image, Math.round(percent), totals.done, totals.total);
@@ -299,6 +326,7 @@ class ContainerManager {
299
326
  name: taskName,
300
327
  image,
301
328
  progress: -1,
329
+ group: 'docker:pull', //It's faster to pull images one at a time
302
330
  });
303
331
  await task.wait();
304
332
  return true;
@@ -344,32 +372,32 @@ class ContainerManager {
344
372
  console.log('Starting unnamed container: %s', opts.Image);
345
373
  return this.startContainer(opts);
346
374
  }
347
- const containerInfo = await this.getContainerByName(opts.name);
375
+ const container = await this.getContainerByName(opts.name);
348
376
  if (imagePulled) {
377
+ // If image was pulled always recreate
349
378
  console.log('New version of image was pulled: %s', opts.Image);
350
379
  }
351
380
  else {
352
- // If image was pulled always recreate
353
- if (!containerInfo) {
381
+ if (!container) {
354
382
  console.log('Starting new container: %s', opts.name);
355
383
  return this.startContainer(opts);
356
384
  }
357
- const containerData = containerInfo.native.data;
358
- if (containerData?.Labels?.HASH === opts.Labels.HASH) {
359
- if (!(await containerInfo.isRunning())) {
385
+ const containerData = await container.inspect();
386
+ if (containerData?.Config.Labels?.HASH === opts.Labels.HASH) {
387
+ if (!(await container.isRunning())) {
360
388
  console.log('Starting previously created container: %s', opts.name);
361
- await containerInfo.start();
389
+ await container.start();
362
390
  }
363
391
  else {
364
392
  console.log('Previously created container already running: %s', opts.name);
365
393
  }
366
- return containerInfo.native;
394
+ return container.native;
367
395
  }
368
396
  }
369
- if (containerInfo) {
397
+ if (container) {
370
398
  // Remove the container and start a new one
371
399
  console.log('Replacing previously created container: %s', opts.name);
372
- await containerInfo.remove({ force: true });
400
+ await container.remove({ force: true });
373
401
  }
374
402
  console.log('Starting new container: %s', opts.name);
375
403
  return this.startContainer(opts);
@@ -385,7 +413,7 @@ class ContainerManager {
385
413
  }
386
414
  opts.HostConfig.ExtraHosts = opts.HostConfig.ExtraHosts.concat(extraHosts);
387
415
  }
388
- const dockerContainer = await this.docker().container.create(opts);
416
+ const dockerContainer = await this.docker().createContainer(opts);
389
417
  await dockerContainer.start();
390
418
  return dockerContainer;
391
419
  }
@@ -414,30 +442,28 @@ class ContainerManager {
414
442
  async _isReady(container) {
415
443
  let info;
416
444
  try {
417
- info = await container.status();
445
+ info = await container.inspect();
418
446
  }
419
447
  catch (err) {
420
448
  return false;
421
449
  }
422
- const infoData = info?.data;
423
- const state = infoData?.State;
424
- if (state?.Status === 'exited' || state?.Status === 'removing' || state?.Status === 'dead') {
450
+ const state = info.State;
451
+ if (state.Status === 'exited' || state?.Status === 'removing' || state?.Status === 'dead') {
425
452
  throw new Error('Container exited unexpectedly');
426
453
  }
427
- if (infoData?.State?.Health) {
454
+ if (state.Health) {
428
455
  // If container has health info - wait for it to become healthy
429
- return infoData.State.Health.Status === 'healthy';
456
+ return state.Health.Status === 'healthy';
430
457
  }
431
458
  else {
432
- return infoData?.State?.Running ?? false;
459
+ return state.Running ?? false;
433
460
  }
434
461
  }
435
462
  async remove(container, opts) {
436
463
  const newName = 'deleting-' + node_uuid_1.default.v4();
437
- const containerData = container.data;
438
464
  // Rename the container first to avoid name conflicts if people start the same container
439
465
  await container.rename({ name: newName });
440
- await container.delete({ force: !!opts?.force });
466
+ await container.remove({ force: !!opts?.force });
441
467
  }
442
468
  /**
443
469
  *
@@ -447,15 +473,15 @@ class ContainerManager {
447
473
  async get(name) {
448
474
  let dockerContainer = null;
449
475
  try {
450
- dockerContainer = await this.docker().container.get(name);
451
- await dockerContainer.status();
476
+ dockerContainer = await this.docker().getContainer(name);
477
+ await dockerContainer.stats();
452
478
  }
453
479
  catch (err) {
454
480
  //Ignore
455
481
  dockerContainer = null;
456
482
  }
457
483
  if (!dockerContainer) {
458
- return null;
484
+ return undefined;
459
485
  }
460
486
  return new ContainerInfo(dockerContainer);
461
487
  }
@@ -647,12 +673,12 @@ class ContainerInfo {
647
673
  _container;
648
674
  /**
649
675
  *
650
- * @param {Container} dockerContainer
676
+ * @param {Docker.Container} dockerContainer
651
677
  */
652
678
  constructor(dockerContainer) {
653
679
  /**
654
680
  *
655
- * @type {Container}
681
+ * @type {Docker.Container}
656
682
  * @private
657
683
  */
658
684
  this._container = dockerContainer;
@@ -668,12 +694,21 @@ class ContainerInfo {
668
694
  return inspectResult.State.Running || inspectResult.State.Restarting;
669
695
  }
670
696
  async start() {
697
+ if (await this.isRunning()) {
698
+ return;
699
+ }
671
700
  await this._container.start();
672
701
  }
673
702
  async restart() {
703
+ if (!(await this.isRunning())) {
704
+ return this.start();
705
+ }
674
706
  await this._container.restart();
675
707
  }
676
708
  async stop() {
709
+ if (!(await this.isRunning())) {
710
+ return;
711
+ }
677
712
  await this._container.stop();
678
713
  }
679
714
  async remove(opts) {
@@ -688,16 +723,15 @@ class ContainerInfo {
688
723
  }
689
724
  async inspect() {
690
725
  try {
691
- const result = await this._container.status();
692
- return result ? result.data : null;
726
+ return await this._container.inspect();
693
727
  }
694
728
  catch (err) {
695
- return null;
729
+ return undefined;
696
730
  }
697
731
  }
698
732
  async status() {
699
733
  const result = await this.inspect();
700
- return result.State;
734
+ return result?.State;
701
735
  }
702
736
  async getPorts() {
703
737
  const inspectResult = await this.inspect();
@@ -742,17 +776,13 @@ class ContainerInfo {
742
776
  }
743
777
  }
744
778
  async getLogs() {
745
- const logStream = (await this.native.logs({
779
+ const logs = await this.native.logs({
746
780
  stdout: true,
747
781
  stderr: true,
748
782
  follow: false,
749
783
  timestamps: true,
750
- }));
751
- const chunks = [];
752
- await promisifyStream(logStream, (data) => {
753
- chunks.push(data);
754
784
  });
755
- const out = readLogBuffer(Buffer.concat(chunks));
785
+ const out = readLogBuffer(logs);
756
786
  if (out.length === 0) {
757
787
  out.push({
758
788
  time: Date.now(),
@@ -262,6 +262,9 @@ class InstanceManager {
262
262
  if (instance.status === types_1.InstanceStatus.STOPPED) {
263
263
  return;
264
264
  }
265
+ if (instance.status === types_1.InstanceStatus.STOPPING) {
266
+ return;
267
+ }
265
268
  if (changeDesired && instance.desiredStatus !== types_1.DesiredInstanceStatus.EXTERNAL) {
266
269
  instance.desiredStatus = types_1.DesiredInstanceStatus.STOP;
267
270
  }
@@ -392,18 +395,18 @@ class InstanceManager {
392
395
  const startTime = Date.now();
393
396
  try {
394
397
  const processInfo = await runner.start(blockRef, instanceId, instanceConfig);
395
- instance.status = types_1.InstanceStatus.READY;
398
+ instance.status = types_1.InstanceStatus.STARTING;
396
399
  return this.saveInternalInstance({
397
400
  ...instance,
398
401
  type: processInfo.type,
399
402
  pid: processInfo.pid ?? -1,
400
403
  health: null,
401
404
  portType: processInfo.portType,
402
- status: types_1.InstanceStatus.READY,
405
+ status: types_1.InstanceStatus.STARTING,
403
406
  });
404
407
  }
405
408
  catch (e) {
406
- console.warn('Failed to start instance: ', systemId, instanceId, blockRef, e.message);
409
+ console.warn('Failed to start instance: ', systemId, instanceId, blockRef, e);
407
410
  const logs = [
408
411
  {
409
412
  source: 'stdout',
@@ -550,7 +553,7 @@ class InstanceManager {
550
553
  await this.start(instance.systemId, instance.instanceId);
551
554
  }
552
555
  catch (e) {
553
- console.warn('Failed to start instance', instance.systemId, instance.instanceId, e);
556
+ console.warn('Failed to start previously stopped instance', instance.systemId, instance.instanceId, e);
554
557
  }
555
558
  return;
556
559
  }
@@ -594,31 +597,38 @@ class InstanceManager {
594
597
  return types_1.InstanceStatus.STOPPED;
595
598
  }
596
599
  const state = await container.status();
597
- if (state.Status === 'running') {
598
- if (state.Health?.Status === 'healthy') {
599
- return types_1.InstanceStatus.READY;
600
- }
601
- if (state.Health?.Status === 'starting') {
602
- return types_1.InstanceStatus.STARTING;
603
- }
604
- if (state.Health?.Status === 'unhealthy') {
605
- return types_1.InstanceStatus.UNHEALTHY;
600
+ if (!state) {
601
+ return types_1.InstanceStatus.STOPPED;
602
+ }
603
+ const statusType = state.Status;
604
+ if (statusType === 'running') {
605
+ if (state.Health?.Status) {
606
+ const healthStatusType = state.Health.Status;
607
+ if (healthStatusType === 'healthy' || healthStatusType === 'none') {
608
+ return types_1.InstanceStatus.READY;
609
+ }
610
+ if (healthStatusType === 'starting') {
611
+ return types_1.InstanceStatus.STARTING;
612
+ }
613
+ if (healthStatusType === 'unhealthy') {
614
+ return types_1.InstanceStatus.UNHEALTHY;
615
+ }
606
616
  }
607
617
  return types_1.InstanceStatus.READY;
608
618
  }
609
- if (state.Status === 'created') {
619
+ if (statusType === 'created') {
610
620
  return types_1.InstanceStatus.STARTING;
611
621
  }
612
- if (state.Status === 'exited' || state.Status === 'dead') {
622
+ if (statusType === 'exited' || statusType === 'dead') {
613
623
  return types_1.InstanceStatus.STOPPED;
614
624
  }
615
- if (state.Status === 'removing') {
625
+ if (statusType === 'removing') {
616
626
  return types_1.InstanceStatus.BUSY;
617
627
  }
618
- if (state.Status === 'restarting') {
628
+ if (statusType === 'restarting') {
619
629
  return types_1.InstanceStatus.BUSY;
620
630
  }
621
- if (state.Status === 'paused') {
631
+ if (statusType === 'paused') {
622
632
  return types_1.InstanceStatus.BUSY;
623
633
  }
624
634
  return types_1.InstanceStatus.STOPPED;
@@ -146,8 +146,11 @@ class OperatorManager {
146
146
  const containerName = `kapeta-resource-${(0, md5_1.default)(nameParts.join('_'))}`;
147
147
  const PortBindings = {};
148
148
  const Env = [];
149
+ const systemUri = (0, nodejs_utils_1.parseKapetaUri)(systemId);
149
150
  const Labels = {
150
151
  kapeta: 'true',
152
+ [containerManager_1.COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
153
+ [containerManager_1.COMPOSE_LABEL_SERVICE]: [resourceType, version].join('_').replace(/[^a-z0-9]/gi, '_'),
151
154
  };
152
155
  const operatorMetadata = operator.getDefinitionInfo().definition.metadata;
153
156
  const bindHost = (0, utils_1.getBindHost)();
@@ -90,7 +90,9 @@ class TaskManager {
90
90
  });
91
91
  this._tasks.push(task);
92
92
  socketManager_1.socketManager.emitGlobal(EVENT_TASK_ADDED, task.toData());
93
- this.invokeTask(task).catch(() => { });
93
+ this.invokeTask(task).catch((err) => {
94
+ console.warn(`Task ${task.id} failed`, err);
95
+ });
94
96
  return task;
95
97
  }
96
98
  async waitFor(filter) {
@@ -145,6 +147,7 @@ class TaskManager {
145
147
  task.emitUpdate();
146
148
  }
147
149
  catch (e) {
150
+ console.warn(`Task ${task.id} failed while waiting for it to resolve`, e);
148
151
  task.errorMessage = e.message;
149
152
  task.status = TaskStatus.FAILED;
150
153
  task.future.reject(e);
@@ -135,22 +135,34 @@ class BlockInstanceRunner {
135
135
  const dockerOpts = localContainer.options ?? {};
136
136
  const homeDir = localContainer.userHome ? localContainer.userHome : '/root';
137
137
  const workingDir = localContainer.workingDir ? localContainer.workingDir : '/workspace';
138
+ const customHostConfigs = localContainer.HostConfig ?? {};
139
+ const customLabels = localContainer.Labels ?? {};
140
+ const customEnvs = localContainer.Env ?? [];
141
+ delete localContainer.HostConfig;
142
+ delete localContainer.Labels;
143
+ delete localContainer.Env;
138
144
  const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion);
139
145
  let HealthCheck = undefined;
140
146
  if (localContainer.healthcheck) {
141
147
  HealthCheck = containerManager_1.containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
142
148
  }
149
+ const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
143
150
  return this.ensureContainer({
151
+ ...dockerOpts,
144
152
  Image: dockerImage,
145
153
  name: containerName,
146
154
  WorkingDir: workingDir,
147
155
  Labels: {
156
+ ...customLabels,
148
157
  instance: blockInstance.id,
158
+ [containerManager_1.COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
159
+ [containerManager_1.COMPOSE_LABEL_SERVICE]: blockInfo.id.replace(/[^a-z0-9]/gi, '_'),
149
160
  },
150
161
  HealthCheck,
151
162
  ExposedPorts,
152
163
  Cmd: startCmd ? startCmd.split(/\s+/g) : [],
153
164
  Env: [
165
+ ...customEnvs,
154
166
  ...DOCKER_ENV_VARS,
155
167
  `KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
156
168
  ...Object.entries({
@@ -159,13 +171,13 @@ class BlockInstanceRunner {
159
171
  }).map(([key, value]) => `${key}=${value}`),
160
172
  ],
161
173
  HostConfig: {
174
+ ...customHostConfigs,
162
175
  Binds: [
163
176
  `${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${homeDir}/.kapeta`,
164
177
  `${(0, containerManager_1.toLocalBindVolume)(baseDir)}:${workingDir}`,
165
178
  ],
166
179
  PortBindings,
167
180
  },
168
- ...dockerOpts,
169
181
  });
170
182
  }
171
183
  async _startDockerProcess(blockInstance, blockInfo, env, assetVersion) {
@@ -186,12 +198,15 @@ class BlockInstanceRunner {
186
198
  const containerName = (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id);
187
199
  // For windows we need to default to root
188
200
  const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
201
+ const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
189
202
  return this.ensureContainer({
190
203
  Image: dockerImage,
191
204
  name: containerName,
192
205
  ExposedPorts,
193
206
  Labels: {
194
207
  instance: blockInstance.id,
208
+ [containerManager_1.COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
209
+ [containerManager_1.COMPOSE_LABEL_SERVICE]: blockInfo.id.replace(/[^a-z0-9]/gi, '_'),
195
210
  },
196
211
  Env: [
197
212
  ...DOCKER_ENV_VARS,
@@ -264,6 +279,7 @@ class BlockInstanceRunner {
264
279
  }
265
280
  // For windows we need to default to root
266
281
  const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
282
+ const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
267
283
  logs.addLog(`Creating new container for block: ${containerName}`);
268
284
  const out = await this.ensureContainer({
269
285
  Image: dockerImage,
@@ -280,6 +296,8 @@ class BlockInstanceRunner {
280
296
  },
281
297
  Labels: {
282
298
  instance: blockInstance.id,
299
+ [containerManager_1.COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
300
+ [containerManager_1.COMPOSE_LABEL_SERVICE]: blockUri.id.replace(/[^a-z0-9]/gi, '_'),
283
301
  },
284
302
  Env: [
285
303
  `KAPETA_INSTANCE_NAME=${blockInstance.ref}`,