fix: RAM multi-source + montage /proc hote LXC dans docker-compose
This commit is contained in:
parent
78ba7b9f54
commit
ea7deec23c
|
|
@ -220,29 +220,102 @@ function getServerMetrics() {
|
||||||
}
|
}
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
|
|
||||||
// RAM : lecture de /proc/meminfo (valeurs réelles via lxcfs)
|
// RAM : lecture robuste multi-source
|
||||||
// Formule identique à `free` : used = total - free - buffers - cached
|
// Priorité 1 : /host/proc/meminfo (hôte LXC monté via volume docker-compose)
|
||||||
// Cela exclut le cache disque du noyau qui est libérable à tout moment
|
// Priorité 2 : /proc/meminfo si MemTotal <= 64 Go (lxcfs ou VPS direct)
|
||||||
let memTotal = 8589934592; // 8 Go par défaut
|
// Priorité 3 : Docker API MemTotal + ratio /proc/meminfo du nœud physique
|
||||||
|
let memTotal = 0;
|
||||||
let memFree = 0, memAvailable = 0, memUsed = 0, memBuffers = 0, memCached = 0;
|
let memFree = 0, memAvailable = 0, memUsed = 0, memBuffers = 0, memCached = 0;
|
||||||
try {
|
|
||||||
const meminfo = fs.readFileSync('/proc/meminfo', 'utf8');
|
// Fonction de lecture de meminfo depuis un chemin donné
|
||||||
const getVal = (key) => {
|
const readMeminfo = (procPath) => {
|
||||||
const m = meminfo.match(new RegExp(`^${key}:\s+(\d+)`, 'm'));
|
const raw = fs.readFileSync(procPath + '/meminfo', 'utf8');
|
||||||
return m ? parseInt(m[1]) * 1024 : 0;
|
const map = {};
|
||||||
|
raw.split('\n').forEach(line => {
|
||||||
|
const idx = line.indexOf(':');
|
||||||
|
if (idx > 0) {
|
||||||
|
const key = line.substring(0, idx).trim();
|
||||||
|
const rest = line.substring(idx + 1).trim();
|
||||||
|
const val = parseInt(rest.split(' ')[0]);
|
||||||
|
if (Number.isFinite(val)) map[key] = val * 1024;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return map;
|
||||||
};
|
};
|
||||||
memTotal = getVal('MemTotal');
|
|
||||||
memFree = getVal('MemFree');
|
try {
|
||||||
memAvailable = getVal('MemAvailable');
|
let memMap = null;
|
||||||
memBuffers = getVal('Buffers');
|
let sourceLabel = '';
|
||||||
// SReclaimable est la partie du slab cache récupérable (inclus dans Cached par free)
|
|
||||||
const sReclaimable = getVal('SReclaimable');
|
// Priorité 1 : /host/proc monté depuis l'hôte LXC
|
||||||
const shmem = getVal('Shmem');
|
if (fs.existsSync('/host/proc/meminfo')) {
|
||||||
memCached = getVal('Cached') + (sReclaimable > shmem ? sReclaimable - shmem : 0);
|
try {
|
||||||
// RAM utilisée = total - libre - buffers - cache (= RAM applicative réelle)
|
const hostMap = readMeminfo('/host/proc');
|
||||||
memUsed = memTotal - memFree - memBuffers - memCached;
|
if (hostMap['MemTotal'] > 0 && hostMap['MemTotal'] <= 64 * 1024 * 1024 * 1024) {
|
||||||
if (memUsed < 0) memUsed = memTotal - memAvailable; // fallback si lxcfs ne fournit pas Buffers/Cached
|
memMap = hostMap;
|
||||||
|
sourceLabel = 'host/proc';
|
||||||
|
}
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priorité 2 : /proc direct si MemTotal <= 64 Go
|
||||||
|
if (!memMap) {
|
||||||
|
try {
|
||||||
|
const procMap = readMeminfo('/proc');
|
||||||
|
if (procMap['MemTotal'] > 0 && procMap['MemTotal'] <= 64 * 1024 * 1024 * 1024) {
|
||||||
|
memMap = procMap;
|
||||||
|
sourceLabel = '/proc direct';
|
||||||
|
}
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priorité 3 : Docker API MemTotal + ratio du nœud physique
|
||||||
|
if (!memMap) {
|
||||||
|
try {
|
||||||
|
const dockerInfoRaw = execSync(
|
||||||
|
'curl -s --unix-socket /var/run/docker.sock http://localhost/info',
|
||||||
|
{ timeout: 3000 }
|
||||||
|
).toString();
|
||||||
|
const dockerInfo = JSON.parse(dockerInfoRaw);
|
||||||
|
const dockerMemTotal = dockerInfo.MemTotal || 0;
|
||||||
|
if (dockerMemTotal > 0) {
|
||||||
|
// Lire le ratio d'utilisation depuis /proc du nœud physique
|
||||||
|
const nodeMap = readMeminfo('/proc');
|
||||||
|
const nodeTotal = nodeMap['MemTotal'] || 1;
|
||||||
|
const nodeAvail = nodeMap['MemAvailable'] || 0;
|
||||||
|
const usageRatio = (nodeTotal - nodeAvail) / nodeTotal;
|
||||||
|
// Appliquer ce ratio à la vraie RAM du VPS
|
||||||
|
memTotal = dockerMemTotal;
|
||||||
|
memUsed = Math.round(memTotal * usageRatio);
|
||||||
|
memFree = memTotal - memUsed;
|
||||||
|
memAvailable = memFree;
|
||||||
|
sourceLabel = 'docker-api+ratio';
|
||||||
|
}
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculer les valeurs finales si memMap disponible
|
||||||
|
if (memMap) {
|
||||||
|
memTotal = memMap['MemTotal'] || 0;
|
||||||
|
memFree = memMap['MemFree'] || 0;
|
||||||
|
memAvailable = memMap['MemAvailable'] || 0;
|
||||||
|
memBuffers = memMap['Buffers'] || 0;
|
||||||
|
const sReclaimable = memMap['SReclaimable'] || 0;
|
||||||
|
const shmem = memMap['Shmem'] || 0;
|
||||||
|
memCached = (memMap['Cached'] || 0) + (sReclaimable > shmem ? sReclaimable - shmem : 0);
|
||||||
|
memUsed = memTotal - memFree - memBuffers - memCached;
|
||||||
|
if (memUsed < 0) memUsed = memTotal - memAvailable;
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
// Fallback ultime
|
||||||
|
try {
|
||||||
|
const m = readMeminfo('/proc');
|
||||||
|
memTotal = m['MemTotal'] || 0;
|
||||||
|
memFree = m['MemFree'] || 0;
|
||||||
|
memAvailable = m['MemAvailable'] || 0;
|
||||||
|
memUsed = memTotal - memAvailable;
|
||||||
|
} catch(e2) {}
|
||||||
|
}
|
||||||
|
|
||||||
// Disque : df sur la racine du conteneur (= hôte car pas de volume overlay)
|
// Disque : df sur la racine du conteneur (= hôte car pas de volume overlay)
|
||||||
let diskTotal = 0, diskUsed = 0, diskFree = 0;
|
let diskTotal = 0, diskUsed = 0, diskFree = 0;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- /opt/manus-deploy:/opt/manus-deploy
|
- /opt/manus-deploy:/opt/manus-deploy
|
||||||
|
- /proc:/host/proc:ro
|
||||||
networks:
|
networks:
|
||||||
- web
|
- web
|
||||||
labels:
|
labels:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue