mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 06:59:42 +02:00
feat(docker): resource templates, GPU, elastic disk, bridge-hooks listener
- One-click "Run in Docker" gains an expandable settings panel with a Template picker (Small 2G/1 · Medium 4G/2 default · Large 8G/4 · GPU 8G/4/all) plus memory/cpu/gpu/network/image/mount-creds overrides. Any tweak creates a dedicated per-case host; the plain checkbox keeps using the shared `default` host. - GPU passthrough: `gpus` on DockerHost/SessionDocker -> `--gpus <value>` in create args (needs the NVIDIA container toolkit). Elastic disk: no `--storage-opt` cap, so container storage grows as data flows in. - CODEMAN_DOCKER_BRIDGE_HOOKS=1: opt-in second listener on the docker bridge gateway (auto-detected 172.17.0.1, override CODEMAN_DOCKER_BRIDGE_HOST) that serves ONLY the hook endpoints and delegates into the secret-gated pipeline, so in-container hooks fire on a loopback-only server. Non-hook paths -> 403; host-internal, not LAN. Verified live: Large template applies real 8GB/4CPU limits; a secret-authenticated hook POST from inside a container now reaches the handler (was connection-refused); non-hook paths return 403; template UI + GPU field verified via Playwright. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -179,6 +179,7 @@ export function dockerConfigHash(
|
||||
| 'network'
|
||||
| 'networkName'
|
||||
| 'resources'
|
||||
| 'gpus'
|
||||
| 'mountCredentials'
|
||||
| 'extraCreateArgs'
|
||||
>
|
||||
@@ -190,6 +191,7 @@ export function dockerConfigHash(
|
||||
network: docker.network,
|
||||
networkName: docker.networkName ?? null,
|
||||
resources: docker.resources ?? null,
|
||||
gpus: docker.gpus ?? null,
|
||||
mountCredentials: docker.mountCredentials,
|
||||
extraCreateArgs: docker.extraCreateArgs ?? null,
|
||||
});
|
||||
@@ -215,6 +217,7 @@ export function toSessionDocker(host: DockerHost, dockerCase: DockerCase): Sessi
|
||||
network: host.network ?? 'bridge',
|
||||
networkName: host.networkName,
|
||||
resources: host.resources ?? DEFAULT_DOCKER_RESOURCES,
|
||||
gpus: host.gpus,
|
||||
mountCredentials: host.mountCredentials ?? true,
|
||||
hooksEnabled: host.hooksEnabled ?? true,
|
||||
resumeOnStart: host.resumeOnStart ?? true,
|
||||
@@ -360,6 +363,10 @@ export function buildDockerCreateArgs(ctx: DockerCreateContext): string[] {
|
||||
|
||||
args.push(
|
||||
...resourceFlags(docker.resources),
|
||||
// GPU passthrough (needs the NVIDIA container toolkit on the host). No storage
|
||||
// cap is set, so the container's writable layer + volumes grow elastically as
|
||||
// data flows in (bounded only by host disk).
|
||||
...(docker.gpus ? ['--gpus', shellescape(docker.gpus)] : []),
|
||||
'--cap-drop',
|
||||
'ALL',
|
||||
'--security-opt',
|
||||
@@ -545,6 +552,29 @@ export async function checkDockerTmuxAvailable(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the host's IP on the default docker bridge (the address a container
|
||||
* reaches as `host.docker.internal`), so the server can bind a hooks-only listener
|
||||
* there and in-container hooks can call back. Defaults to the conventional
|
||||
* 172.17.0.1 when the inspect fails but docker is up; null when docker is absent.
|
||||
* No-op canned value under VITEST.
|
||||
*/
|
||||
export async function detectDockerBridgeGateway(engine: DockerEngine = 'docker'): Promise<string | null> {
|
||||
if (IS_TEST_MODE) return '172.17.0.1';
|
||||
const bin = engine === 'podman' ? 'podman' : 'docker';
|
||||
try {
|
||||
const { stdout } = await execFileAsync(
|
||||
bin,
|
||||
['network', 'inspect', 'bridge', '--format', '{{(index .IPAM.Config 0).Gateway}}'],
|
||||
{ timeout: DOCKER_PROBE_TIMEOUT_MS }
|
||||
);
|
||||
const ip = stdout.trim();
|
||||
return /^\d{1,3}(\.\d{1,3}){3}$/.test(ip) ? ip : '172.17.0.1';
|
||||
} catch {
|
||||
return null; // docker not available — nothing to bind
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instance-scoped boot reaper: `docker rm -f` any MANAGED container that belongs
|
||||
* to THIS instance (by the `codeman.instance` label) but whose case is no longer
|
||||
|
||||
Reference in New Issue
Block a user