From 95c1541d059be6ead88008e22437a9e7dbffcb78 Mon Sep 17 00:00:00 2001 From: ndrpp Date: Fri, 27 Mar 2026 11:31:44 +0200 Subject: [PATCH 01/10] feat: improve c2d docker image security --- src/components/c2d/compute_engine_docker.ts | 25 +++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index 224414f86..c074041fc 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -55,6 +55,9 @@ import { dockerRegistrysAuth, dockerRegistryAuth } from '../../@types/OceanNode. import { EncryptMethod } from '../../@types/fileObject.js' import { ZeroAddress } from 'ethers' +const C2D_CONTAINER_UID = 1000 +const C2D_CONTAINER_GID = 1000 + export class C2DEngineDocker extends C2DEngine { private envs: ComputeEnvironment[] = [] @@ -1637,6 +1640,12 @@ export class C2DEngineDocker extends C2DEngine { const mountVols: any = { '/data': {} } const hostConfig: HostConfig = { NetworkMode: 'none', // no network inside the container + ReadonlyRootfs: true, + PidsLimit: 512, + Tmpfs: { + '/tmp': 'rw,noexec,nosuid,size=256m', + '/run': 'rw,noexec,nosuid,size=64m' + }, Mounts: [ { Type: 'volume', @@ -1675,9 +1684,10 @@ export class C2DEngineDocker extends C2DEngine { AttachStdin: false, AttachStdout: true, AttachStderr: true, - Tty: true, + Tty: false, OpenStdin: false, StdinOnce: false, + User: `${C2D_CONTAINER_UID}:${C2D_CONTAINER_GID}`, Volumes: mountVols, HostConfig: hostConfig } @@ -1692,8 +1702,10 @@ export class C2DEngineDocker extends C2DEngine { containerInfo.HostConfig.Devices = advancedConfig.Devices if (advancedConfig.GroupAdd) containerInfo.HostConfig.GroupAdd = advancedConfig.GroupAdd - if (advancedConfig.SecurityOpt) - containerInfo.HostConfig.SecurityOpt = advancedConfig.SecurityOpt + containerInfo.HostConfig.SecurityOpt = [ + 'no-new-privileges', + ...(advancedConfig.SecurityOpt ?? []) + ] if (advancedConfig.Binds) containerInfo.HostConfig.Binds = advancedConfig.Binds containerInfo.HostConfig.CapDrop = ['ALL'] for (const cap of advancedConfig.CapDrop ?? []) { @@ -2740,7 +2752,12 @@ export class C2DEngineDocker extends C2DEngine { gzip: true, file: destination, sync: true, - C: folderToTar + C: folderToTar, + map: (header) => { + header.uid = C2D_CONTAINER_UID + header.gid = C2D_CONTAINER_GID + return header + } }, ['./'] ) From e546140521de1ba14f117300b22ea765bba0cb32 Mon Sep 17 00:00:00 2001 From: ndrpp Date: Fri, 27 Mar 2026 12:05:50 +0200 Subject: [PATCH 02/10] fix: build issue --- src/components/c2d/compute_engine_docker.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index c074041fc..ffee83fac 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -659,7 +659,7 @@ export class C2DEngineDocker extends C2DEngine { private async cleanUpUnknownLocks(chain: string, currentTimestamp: bigint) { try { - const nodeAddress = await this.getKeyManager().getEthAddress() + const nodeAddress = this.getKeyManager().getEthAddress() const jobIds: any[] = [] const tokens: string[] = [] const payer: string[] = [] @@ -1414,7 +1414,7 @@ export class C2DEngineDocker extends C2DEngine { if (!jobRes[0].isRunning) return null try { const job = jobRes[0] - const container = await this.docker.getContainer(job.jobId + '-algoritm') + const container = this.docker.getContainer(job.jobId + '-algoritm') const details = await container.inspect() if (details.State.Running === false) return null return await container.logs({ @@ -1765,7 +1765,7 @@ export class C2DEngineDocker extends C2DEngine { let container let details try { - container = await this.docker.getContainer(job.jobId + '-algoritm') + container = this.docker.getContainer(job.jobId + '-algoritm') details = await container.inspect() } catch (e) { console.error( @@ -1867,7 +1867,7 @@ export class C2DEngineDocker extends C2DEngine { job.statusText = C2DStatusText.JobSettle let container try { - container = await this.docker.getContainer(job.jobId + '-algoritm') + container = this.docker.getContainer(job.jobId + '-algoritm') } catch (e) { CORE_LOGGER.debug('Could not retrieve container: ' + e.message) job.isRunning = false @@ -2056,7 +2056,7 @@ export class C2DEngineDocker extends C2DEngine { this.releaseCpus(job.jobId) try { - const container = await this.docker.getContainer(job.jobId + '-algoritm') + const container = this.docker.getContainer(job.jobId + '-algoritm') if (container) { if (job.status !== C2DStatusNumber.AlgorithmFailed) { writeFileSync( @@ -2748,24 +2748,25 @@ export class C2DEngineDocker extends C2DEngine { const destination = jobFolderPath + '/tarData/upload.tar.gz' try { tar.create( + // map is a valid runtime option but missing from type definitions { gzip: true, file: destination, sync: true, C: folderToTar, - map: (header) => { + map: (header: any) => { header.uid = C2D_CONTAINER_UID header.gid = C2D_CONTAINER_GID return header } - }, + } as any, ['./'] ) // check if tar.gz actually exists if (existsSync(destination)) { // now, upload it to the container - const container = await this.docker.getContainer(job.jobId + '-algoritm') + const container = this.docker.getContainer(job.jobId + '-algoritm') try { // await container2.putArchive(destination, { @@ -2851,7 +2852,7 @@ export class C2DEngineDocker extends C2DEngine { } // delete output folders - await this.deleteOutputFolder(job) + this.deleteOutputFolder(job) // delete the job await this.db.deleteJob(job.jobId) return true From c2a3c05da0412224fbaab66f0bdd369bb2f07049 Mon Sep 17 00:00:00 2001 From: ndrpp Date: Fri, 27 Mar 2026 15:20:28 +0200 Subject: [PATCH 03/10] fix: make directories world writable --- src/components/c2d/compute_engine_docker.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index ffee83fac..74a5e432b 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -2757,6 +2757,11 @@ export class C2DEngineDocker extends C2DEngine { map: (header: any) => { header.uid = C2D_CONTAINER_UID header.gid = C2D_CONTAINER_GID + // Docker's putArchive applies chmod but not chown — set directories + // world-writable so the container user (uid 1000) can write to them + if (header.type === 'Directory') { + header.mode = 0o777 + } return header } } as any, From b9d1cd722d0de479084569e500acf029ac8629c1 Mon Sep 17 00:00:00 2001 From: ndrpp Date: Fri, 27 Mar 2026 16:11:35 +0200 Subject: [PATCH 04/10] fix: use init container to setup permissions before running user image --- src/components/c2d/compute_engine_docker.ts | 55 +++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index 74a5e432b..f4726e77a 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -1519,6 +1519,52 @@ export class C2DEngineDocker extends C2DEngine { } } + private async ensureImage(image: string): Promise { + try { + await this.docker.getImage(image).inspect() + } catch { + CORE_LOGGER.info(`Image ${image} not found locally, pulling...`) + const pullStream = await this.docker.pull(image) + await new Promise((resolve, reject) => { + this.docker.modem.followProgress(pullStream, (err: any) => { + if (err) reject(err) + else resolve() + }) + }) + } + } + + private async initializeVolumePermissions(volumeName: string): Promise { + let initContainer: Dockerode.Container | null = null + try { + await this.ensureImage('busybox') + initContainer = await this.docker.createContainer({ + Image: 'busybox', + Cmd: [ + 'sh', + '-c', + 'mkdir -p /data/inputs /data/outputs /data/transformations /data/ddos /data/logs && chmod 777 /data /data/inputs /data/outputs /data/transformations /data/ddos /data/logs' + ], + HostConfig: { + NetworkMode: 'none', + Mounts: [{ Type: 'volume', Source: volumeName, Target: '/data' }] + } + }) + await initContainer.start() + await initContainer.wait() + return true + } catch (e) { + CORE_LOGGER.error(`Failed to initialize volume permissions: ${e.message}`) + return false + } finally { + if (initContainer) { + try { + await initContainer.remove() + } catch {} + } + } + } + private async createDockerVolume( volume: VolumeCreateOptions, retry: boolean = false @@ -1635,6 +1681,15 @@ export class C2DEngineDocker extends C2DEngine { await this.cleanupJob(job) return } + if (!(await this.initializeVolumePermissions(volume.Name))) { + job.status = C2DStatusNumber.VolumeCreationFailed + job.statusText = C2DStatusText.VolumeCreationFailed + job.isRunning = false + job.dateFinished = String(Date.now() / 1000) + await this.db.updateJob(job) + await this.cleanupJob(job) + return + } // create the container const mountVols: any = { '/data': {} } From 56ec16636a0a84b2a6651b508ac1cb3bc0e15d83 Mon Sep 17 00:00:00 2001 From: ndrpp Date: Fri, 27 Mar 2026 16:48:36 +0200 Subject: [PATCH 05/10] fix: add logs to check status of init volume --- src/components/c2d/compute_engine_docker.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index f4726e77a..5e2217d3e 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -1551,7 +1551,14 @@ export class C2DEngineDocker extends C2DEngine { } }) await initContainer.start() - await initContainer.wait() + const { StatusCode } = await initContainer.wait() + if (StatusCode !== 0) { + CORE_LOGGER.error( + `Volume permission init container exited with code ${StatusCode} for volume ${volumeName}` + ) + return false + } + CORE_LOGGER.info(`Volume permissions initialized successfully for ${volumeName}`) return true } catch (e) { CORE_LOGGER.error(`Failed to initialize volume permissions: ${e.message}`) From 3acda9f05743ec4ff57e916872fd2c1e1ef20b33 Mon Sep 17 00:00:00 2001 From: ndrpp Date: Mon, 30 Mar 2026 09:43:07 +0300 Subject: [PATCH 06/10] fix: try changing permissions at job start --- src/components/c2d/compute_engine_docker.ts | 147 ++++++++++---------- 1 file changed, 75 insertions(+), 72 deletions(-) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index 5e2217d3e..3096a2b44 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -54,6 +54,7 @@ import { getOceanTokenAddressForChain } from '../../utils/address.js' import { dockerRegistrysAuth, dockerRegistryAuth } from '../../@types/OceanNode.js' import { EncryptMethod } from '../../@types/fileObject.js' import { ZeroAddress } from 'ethers' +import { chmodSync } from 'node:fs' const C2D_CONTAINER_UID = 1000 const C2D_CONTAINER_GID = 1000 @@ -1519,58 +1520,58 @@ export class C2DEngineDocker extends C2DEngine { } } - private async ensureImage(image: string): Promise { - try { - await this.docker.getImage(image).inspect() - } catch { - CORE_LOGGER.info(`Image ${image} not found locally, pulling...`) - const pullStream = await this.docker.pull(image) - await new Promise((resolve, reject) => { - this.docker.modem.followProgress(pullStream, (err: any) => { - if (err) reject(err) - else resolve() - }) - }) - } - } - - private async initializeVolumePermissions(volumeName: string): Promise { - let initContainer: Dockerode.Container | null = null - try { - await this.ensureImage('busybox') - initContainer = await this.docker.createContainer({ - Image: 'busybox', - Cmd: [ - 'sh', - '-c', - 'mkdir -p /data/inputs /data/outputs /data/transformations /data/ddos /data/logs && chmod 777 /data /data/inputs /data/outputs /data/transformations /data/ddos /data/logs' - ], - HostConfig: { - NetworkMode: 'none', - Mounts: [{ Type: 'volume', Source: volumeName, Target: '/data' }] - } - }) - await initContainer.start() - const { StatusCode } = await initContainer.wait() - if (StatusCode !== 0) { - CORE_LOGGER.error( - `Volume permission init container exited with code ${StatusCode} for volume ${volumeName}` - ) - return false - } - CORE_LOGGER.info(`Volume permissions initialized successfully for ${volumeName}`) - return true - } catch (e) { - CORE_LOGGER.error(`Failed to initialize volume permissions: ${e.message}`) - return false - } finally { - if (initContainer) { - try { - await initContainer.remove() - } catch {} - } - } - } + // private async ensureImage(image: string): Promise { + // try { + // await this.docker.getImage(image).inspect() + // } catch { + // CORE_LOGGER.info(`Image ${image} not found locally, pulling...`) + // const pullStream = await this.docker.pull(image) + // await new Promise((resolve, reject) => { + // this.docker.modem.followProgress(pullStream, (err: any) => { + // if (err) reject(err) + // else resolve() + // }) + // }) + // } + // } + + // private async initializeVolumePermissions(volumeName: string): Promise { + // let initContainer: Dockerode.Container | null = null + // try { + // await this.ensureImage('busybox') + // initContainer = await this.docker.createContainer({ + // Image: 'busybox', + // Cmd: [ + // 'sh', + // '-c', + // 'mkdir -p /data/inputs /data/outputs /data/transformations /data/ddos /data/logs && chmod 777 /data /data/inputs /data/outputs /data/transformations /data/ddos /data/logs' + // ], + // HostConfig: { + // NetworkMode: 'none', + // Mounts: [{ Type: 'volume', Source: volumeName, Target: '/data' }] + // } + // }) + // await initContainer.start() + // const { StatusCode } = await initContainer.wait() + // if (StatusCode !== 0) { + // CORE_LOGGER.error( + // `Volume permission init container exited with code ${StatusCode} for volume ${volumeName}` + // ) + // return false + // } + // CORE_LOGGER.info(`Volume permissions initialized successfully for ${volumeName}`) + // return true + // } catch (e) { + // CORE_LOGGER.error(`Failed to initialize volume permissions: ${e.message}`) + // return false + // } finally { + // if (initContainer) { + // try { + // await initContainer.remove() + // } catch {} + // } + // } + // } private async createDockerVolume( volume: VolumeCreateOptions, @@ -1688,15 +1689,15 @@ export class C2DEngineDocker extends C2DEngine { await this.cleanupJob(job) return } - if (!(await this.initializeVolumePermissions(volume.Name))) { - job.status = C2DStatusNumber.VolumeCreationFailed - job.statusText = C2DStatusText.VolumeCreationFailed - job.isRunning = false - job.dateFinished = String(Date.now() / 1000) - await this.db.updateJob(job) - await this.cleanupJob(job) - return - } + // if (!(await this.initializeVolumePermissions(volume.Name))) { + // job.status = C2DStatusNumber.VolumeCreationFailed + // job.statusText = C2DStatusText.VolumeCreationFailed + // job.isRunning = false + // job.dateFinished = String(Date.now() / 1000) + // await this.db.updateJob(job) + // await this.cleanupJob(job) + // return + // } // create the container const mountVols: any = { '/data': {} } @@ -2815,17 +2816,17 @@ export class C2DEngineDocker extends C2DEngine { gzip: true, file: destination, sync: true, - C: folderToTar, - map: (header: any) => { - header.uid = C2D_CONTAINER_UID - header.gid = C2D_CONTAINER_GID - // Docker's putArchive applies chmod but not chown — set directories - // world-writable so the container user (uid 1000) can write to them - if (header.type === 'Directory') { - header.mode = 0o777 - } - return header - } + C: folderToTar + // map: (header: any) => { + // header.uid = C2D_CONTAINER_UID + // header.gid = C2D_CONTAINER_GID + // // Docker's putArchive applies chmod but not chown — set directories + // // world-writable so the container user (uid 1000) can write to them + // if (header.type === 'Directory') { + // header.mode = 0o777 + // } + // return header + // } } as any, ['./'] ) @@ -2895,6 +2896,8 @@ export class C2DEngineDocker extends C2DEngine { if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }) } + // update directory permissions to allow read/write from job containers + chmodSync(dir, 0o777) } return true } catch (e) { From fb7e3a2e456f0a12369d4aa24a3025f49ef30c5a Mon Sep 17 00:00:00 2001 From: ndrpp Date: Mon, 30 Mar 2026 11:46:25 +0300 Subject: [PATCH 07/10] fix: allow root cache as tmpfs --- src/components/c2d/compute_engine_docker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index 3096a2b44..94b1ad26b 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -1707,7 +1707,8 @@ export class C2DEngineDocker extends C2DEngine { PidsLimit: 512, Tmpfs: { '/tmp': 'rw,noexec,nosuid,size=256m', - '/run': 'rw,noexec,nosuid,size=64m' + '/run': 'rw,noexec,nosuid,size=64m', + '~/.cache': 'rw,noexec,nosuid,size=256m' }, Mounts: [ { From 079d7a60bf347a31dac7d6246c5aba8298699948 Mon Sep 17 00:00:00 2001 From: ndrpp Date: Mon, 30 Mar 2026 11:58:41 +0300 Subject: [PATCH 08/10] fix: use absolute path --- src/components/c2d/compute_engine_docker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index 94b1ad26b..b20c7bac0 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -1708,7 +1708,7 @@ export class C2DEngineDocker extends C2DEngine { Tmpfs: { '/tmp': 'rw,noexec,nosuid,size=256m', '/run': 'rw,noexec,nosuid,size=64m', - '~/.cache': 'rw,noexec,nosuid,size=256m' + '/home/ubuntu/.cache': 'rw,noexec,nosuid,size=256m' }, Mounts: [ { From 125032fd646dedad70525b6a06d22077d022044c Mon Sep 17 00:00:00 2001 From: ndrpp Date: Mon, 30 Mar 2026 12:20:42 +0300 Subject: [PATCH 09/10] chore: review --- src/components/c2d/compute_engine_docker.ts | 80 ++------------------- 1 file changed, 4 insertions(+), 76 deletions(-) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index b20c7bac0..abc664014 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -1520,59 +1520,6 @@ export class C2DEngineDocker extends C2DEngine { } } - // private async ensureImage(image: string): Promise { - // try { - // await this.docker.getImage(image).inspect() - // } catch { - // CORE_LOGGER.info(`Image ${image} not found locally, pulling...`) - // const pullStream = await this.docker.pull(image) - // await new Promise((resolve, reject) => { - // this.docker.modem.followProgress(pullStream, (err: any) => { - // if (err) reject(err) - // else resolve() - // }) - // }) - // } - // } - - // private async initializeVolumePermissions(volumeName: string): Promise { - // let initContainer: Dockerode.Container | null = null - // try { - // await this.ensureImage('busybox') - // initContainer = await this.docker.createContainer({ - // Image: 'busybox', - // Cmd: [ - // 'sh', - // '-c', - // 'mkdir -p /data/inputs /data/outputs /data/transformations /data/ddos /data/logs && chmod 777 /data /data/inputs /data/outputs /data/transformations /data/ddos /data/logs' - // ], - // HostConfig: { - // NetworkMode: 'none', - // Mounts: [{ Type: 'volume', Source: volumeName, Target: '/data' }] - // } - // }) - // await initContainer.start() - // const { StatusCode } = await initContainer.wait() - // if (StatusCode !== 0) { - // CORE_LOGGER.error( - // `Volume permission init container exited with code ${StatusCode} for volume ${volumeName}` - // ) - // return false - // } - // CORE_LOGGER.info(`Volume permissions initialized successfully for ${volumeName}`) - // return true - // } catch (e) { - // CORE_LOGGER.error(`Failed to initialize volume permissions: ${e.message}`) - // return false - // } finally { - // if (initContainer) { - // try { - // await initContainer.remove() - // } catch {} - // } - // } - // } - private async createDockerVolume( volume: VolumeCreateOptions, retry: boolean = false @@ -1689,26 +1636,18 @@ export class C2DEngineDocker extends C2DEngine { await this.cleanupJob(job) return } - // if (!(await this.initializeVolumePermissions(volume.Name))) { - // job.status = C2DStatusNumber.VolumeCreationFailed - // job.statusText = C2DStatusText.VolumeCreationFailed - // job.isRunning = false - // job.dateFinished = String(Date.now() / 1000) - // await this.db.updateJob(job) - // await this.cleanupJob(job) - // return - // } // create the container const mountVols: any = { '/data': {} } const hostConfig: HostConfig = { NetworkMode: 'none', // no network inside the container ReadonlyRootfs: true, + // limit number of Pids container can spawn, to avoid flooding PidsLimit: 512, Tmpfs: { + '/home/ubuntu/.cache': 'rw,noexec,nosuid,size=512m', '/tmp': 'rw,noexec,nosuid,size=256m', - '/run': 'rw,noexec,nosuid,size=64m', - '/home/ubuntu/.cache': 'rw,noexec,nosuid,size=256m' + '/run': 'rw,noexec,nosuid,size=64m' }, Mounts: [ { @@ -2812,23 +2751,12 @@ export class C2DEngineDocker extends C2DEngine { const destination = jobFolderPath + '/tarData/upload.tar.gz' try { tar.create( - // map is a valid runtime option but missing from type definitions { gzip: true, file: destination, sync: true, C: folderToTar - // map: (header: any) => { - // header.uid = C2D_CONTAINER_UID - // header.gid = C2D_CONTAINER_GID - // // Docker's putArchive applies chmod but not chown — set directories - // // world-writable so the container user (uid 1000) can write to them - // if (header.type === 'Directory') { - // header.mode = 0o777 - // } - // return header - // } - } as any, + }, ['./'] ) // check if tar.gz actually exists From 92513eea5a52a4fb8c00f332cd71932071fd8a09 Mon Sep 17 00:00:00 2001 From: ndrpp Date: Mon, 30 Mar 2026 12:39:23 +0300 Subject: [PATCH 10/10] feat: disable readonly root fs --- src/components/c2d/compute_engine_docker.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index abc664014..abbe5871c 100755 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -1641,14 +1641,8 @@ export class C2DEngineDocker extends C2DEngine { const mountVols: any = { '/data': {} } const hostConfig: HostConfig = { NetworkMode: 'none', // no network inside the container - ReadonlyRootfs: true, // limit number of Pids container can spawn, to avoid flooding PidsLimit: 512, - Tmpfs: { - '/home/ubuntu/.cache': 'rw,noexec,nosuid,size=512m', - '/tmp': 'rw,noexec,nosuid,size=256m', - '/run': 'rw,noexec,nosuid,size=64m' - }, Mounts: [ { Type: 'volume',