From f0bd70ff6efb189e58a3ac85208ef812939c991b Mon Sep 17 00:00:00 2001 From: chenxing Date: Tue, 4 Aug 2026 22:56:08 +0800 Subject: [PATCH] fix(deploy): discover workspace source via container inspect (not mountinfo) --- scripts/deploy-via-docker.js | 44 +++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/scripts/deploy-via-docker.js b/scripts/deploy-via-docker.js index d8df796..b6de5c4 100644 --- a/scripts/deploy-via-docker.js +++ b/scripts/deploy-via-docker.js @@ -19,6 +19,15 @@ const fs = require('fs'); const SOCKET = '/var/run/docker.sock'; const HOST_STATIC = '/data/www/userbase'; const HELPER_IMAGE = 'node:20'; // already cached on host (used by the job) +const WS_MOUNT = '/workspace/admin/userbase'; + +// The job container's ID, derived from its cgroup (robust regardless of hostname). +function getContainerId() { + const cg = fs.readFileSync('/proc/self/cgroup', 'utf8'); + const m = cg.match(/[0-9a-f]{64}/); + if (!m) throw new Error('cannot determine container id from cgroup'); + return m[0]; +} function dockerReq(method, path, bodyObj) { return new Promise((resolve, reject) => { @@ -42,29 +51,28 @@ function dockerReq(method, path, bodyObj) { }); } -// Locate the host path backing the workspace mountpoint (a docker volume _data dir). -function findWorkspaceSource(mountpoint) { - const txt = fs.readFileSync('/proc/self/mountinfo', 'utf8'); - for (const line of txt.split('\n')) { - const parts = line.trim().split(/\s+/); - if (parts.length < 5) continue; - const mp = parts[4]; - if (mp === mountpoint || mp.endsWith(mountpoint)) { - const dash = parts.indexOf('-'); - if (dash !== -1 && parts.length > dash + 2) { - return parts[dash + 2]; - } +// Locate the host path backing the workspace mount by inspecting THIS container +// via the Docker daemon (docker.sock). This is far more reliable than parsing +// /proc/self/mountinfo (which reports the underlying block device, not the bind +// source). The job container's hostname is its short ID. +async function findWorkspaceSource() { + const id = getContainerId(); + const r = await dockerReq('GET', `/containers/${id}/json`); + if (r.status >= 400) { + throw new Error('inspect self failed: ' + r.status + ' ' + r.body); + } + const info = JSON.parse(r.body); + const mounts = info.Mounts || []; + for (const m of mounts) { + if (m.Destination === WS_MOUNT) { + return m.Source; // host path of the docker volume _data dir } } - return null; + throw new Error('workspace mount ' + WS_MOUNT + ' not found in container inspect'); } async function main() { - const wsMount = '/workspace/admin/userbase'; - const wsSource = findWorkspaceSource(wsMount); - if (!wsSource) { - throw new Error('Could not find workspace source in /proc/self/mountinfo'); - } + const wsSource = await findWorkspaceSource(); console.log('workspace source (host path):', wsSource); // Inside the helper, the workspace is bound at /src (see Binds below).