indus / services /docker.js
mk6783336's picture
Indus backend first deploy
05026f0
const Docker = require('dockerode');
const fs = require('fs');
let docker;
try {
docker = new Docker();
} catch (e) {
console.warn('Docker not available — container features disabled');
}
async function getOrCreateContainer(projectId, userId, workDir) {
if (!docker) throw new Error('Docker not available');
const name = `indus-${projectId}`;
// Check if already running
try {
const container = docker.getContainer(name);
const info = await container.inspect();
if (info.State.Running) return container;
await container.start();
return container;
} catch (e) {
// Container doesn't exist yet
}
// Create workspace directory on host
fs.mkdirSync(workDir, { recursive: true });
// Create fresh container
const container = await docker.createContainer({
Image: 'indus-base:latest',
name,
Tty: true,
OpenStdin: true,
WorkingDir: '/workspace',
HostConfig: {
Memory: 512 * 1024 * 1024, // 512MB RAM
MemorySwap: 512 * 1024 * 1024, // No swap
CpuQuota: 50000, // 50% of one CPU
NetworkMode: 'bridge',
Binds: [`${workDir}:/workspace`], // Mount user files
AutoRemove: false,
},
});
await container.start();
console.log(`Container created: ${name}`);
return container;
}
async function stopContainer(projectId) {
if (!docker) return;
try {
const container = docker.getContainer(`indus-${projectId}`);
await container.stop({ t: 5 });
console.log(`Container stopped: indus-${projectId}`);
} catch (e) { }
}
async function removeContainer(projectId) {
if (!docker) return;
try {
const container = docker.getContainer(`indus-${projectId}`);
await container.remove({ force: true });
console.log(`Container removed: indus-${projectId}`);
} catch (e) { }
}
async function execInContainer(projectId, command) {
if (!docker) throw new Error('Docker not available');
const container = docker.getContainer(`indus-${projectId}`);
const exec = await container.exec({
Cmd: ['bash', '-c', command],
AttachStdout: true,
AttachStderr: true,
});
const stream = await exec.start({ Detach: false });
return new Promise((resolve, reject) => {
let output = '';
stream.on('data', (chunk) => { output += chunk.toString(); });
stream.on('end', () => resolve(output));
stream.on('error', reject);
});
}
module.exports = {
getOrCreateContainer,
stopContainer,
removeContainer,
execInContainer,
};