Updated faceai container
All checks were successful
Publish FaceAI Container / publish (push) Successful in 2m23s

This commit is contained in:
MaddoScientisto 2026-04-19 08:05:21 +02:00
commit 07db048310
3 changed files with 136 additions and 18 deletions

View file

@ -84,7 +84,7 @@ The `processor` service is built from `docker/processor.Dockerfile`, which uses
### Persistent Logs ### Persistent Logs
The checked-in local Compose stack now redirects the relevant Node service logs into `faceai/logs` on the host. The checked-in local Compose stack now mirrors the relevant Node service logs to both Docker stdout/stderr and `faceai/logs` on the host.
After `docker compose up --build`, inspect: After `docker compose up --build`, inspect:
@ -95,6 +95,8 @@ After `docker compose up --build`, inspect:
This keeps the useful processor diagnostics outside the Docker-managed runtime volume so they survive container rebuilds and can be inspected directly from the workspace. This keeps the useful processor diagnostics outside the Docker-managed runtime volume so they survive container rebuilds and can be inspected directly from the workspace.
Because the service entrypoints now mirror output instead of redirecting it away, the same startup and runtime messages are also visible through `docker logs regalami-faceai`, `docker logs regalami-faceai-processor`, and Portainer's container log viewer.
The current bundled Linux `face_matcher` binary is a PyInstaller build that requires `GLIBC_2.38` or newer and the `libxcb.so.1` runtime library. The checked-in local processor image satisfies that requirement. The current bundled Linux `face_matcher` binary is a PyInstaller build that requires `GLIBC_2.38` or newer and the `libxcb.so.1` runtime library. The checked-in local processor image satisfies that requirement.
### Run The Browser Test ### Run The Browser Test
@ -211,14 +213,20 @@ services:
image: forgejo.maddoscientisto.net/maddo/faceai-client:latest image: forgejo.maddoscientisto.net/maddo/faceai-client:latest
container_name: regalami-faceai container_name: regalami-faceai
restart: unless-stopped restart: unless-stopped
command: sh -c "mkdir -p /data/logs && npm run start >> /data/logs/backend.log 2>&1" command:
- node
- docker/run-with-log-file.mjs
- /data/logs/backend.log
- npm
- run
- start
environment: environment:
NODE_ENV: production NODE_ENV: production
PORT: 3001 PORT: 3001
FACEAI_FRONTEND_URL: https://ai.regalamiunsorriso.it FACEAI_FRONTEND_URL: https://ai.regalamiunsorriso.it
FACEAI_PUBLIC_BASE_URL: https://ai.regalamiunsorriso.it FACEAI_PUBLIC_BASE_URL: https://ai.regalamiunsorriso.it
FACEAI_LEGACY_RETURN_URL: https://www.regalamiunsorriso.it/faceai_return.php FACEAI_LEGACY_RETURN_URL: https://www.regalamiunsorriso.it/faceai_return.php
FACEAI_SHARED_SECRET: change-this-to-a-long-random-secret FACEAI_SHARED_SECRET: disagio-spaghetti-science-lol-boh
FACEAI_SESSION_COOKIE: rus_faceai_session FACEAI_SESSION_COOKIE: rus_faceai_session
FACEAI_REDIS_URL: redis://redis:6379 FACEAI_REDIS_URL: redis://redis:6379
FACEAI_QUEUE_NAME: faceai-searches FACEAI_QUEUE_NAME: faceai-searches
@ -228,19 +236,32 @@ services:
FACEAI_PKL_ROOT: /data/pkl FACEAI_PKL_ROOT: /data/pkl
FACEAI_ENABLE_LOCAL_LEGACY_STATIC: 0 FACEAI_ENABLE_LOCAL_LEGACY_STATIC: 0
volumes: volumes:
- /var/docker/faceai/runtime:/data/runtime - /mnt/storage/data/faceai/runtime:/data/runtime
- /var/docker/faceai/logs:/data/logs - /mnt/storage/data/faceai/logs:/data/logs
- /mnt/nas12/nas2/RUS:/data/pkl:ro - /mnt/nas12/nas2/RUS:/data/pkl:ro
ports: ports:
- "127.0.0.1:3001:3001" - "127.0.0.1:3001:3001"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3001/health | grep -q '\"ok\":true'"]
interval: 10s
timeout: 5s
retries: 6
start_period: 20s
depends_on: depends_on:
- redis redis:
condition: service_healthy
processor: processor:
image: forgejo.maddoscientisto.net/maddo/faceai-client:latest image: forgejo.maddoscientisto.net/maddo/faceai-client:latest
container_name: regalami-faceai-processor container_name: regalami-faceai-processor
restart: unless-stopped restart: unless-stopped
command: sh -c "mkdir -p /data/logs && npm run start:processor >> /data/logs/processor.log 2>&1" command:
- node
- docker/run-with-log-file.mjs
- /data/logs/processor.log
- npm
- run
- start:processor
environment: environment:
NODE_ENV: production NODE_ENV: production
FACEAI_REDIS_URL: redis://redis:6379 FACEAI_REDIS_URL: redis://redis:6379
@ -252,18 +273,24 @@ services:
FACEAI_WORKER_CONCURRENCY: 2 FACEAI_WORKER_CONCURRENCY: 2
FACEAI_WORKER_TIMEOUT_MS: 300000 FACEAI_WORKER_TIMEOUT_MS: 300000
volumes: volumes:
- /var/docker/faceai/runtime:/data/runtime - /mnt/storage/data/faceai/runtime:/data/runtime
- /var/docker/faceai/logs:/data/logs - /mnt/storage/data/faceai/logs:/data/logs
- /mnt/nas12/nas2/RUS:/data/pkl:ro - /mnt/nas12/nas2/RUS:/data/pkl:ro
- /var/docker/faceai/bin/Face_Recognition_Unix:/opt/face-recognition:ro - /mnt/storage/data/faceai/bin/Face_Recognition_Unix:/opt/face-recognition:ro
depends_on: depends_on:
- redis redis:
condition: service_healthy
redis: redis:
image: redis:7-alpine image: redis:7-alpine
container_name: regalami-faceai-redis container_name: regalami-faceai-redis
restart: unless-stopped restart: unless-stopped
command: redis-server --appendonly no command: redis-server --appendonly no
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 12
``` ```
This pattern assumes a reverse proxy on the host publishes `https://ai.regalamiunsorriso.it` and forwards to `127.0.0.1:3001`. The processor is internal-only and does not expose any public port. This pattern assumes a reverse proxy on the host publishes `https://ai.regalamiunsorriso.it` and forwards to `127.0.0.1:3001`. The processor is internal-only and does not expose any public port.
@ -392,7 +419,9 @@ In the provided Docker Compose stack, that wiring is already done with:
FACEAI_LEGACY_RETURN_URL=http://localhost:8080/faceai_return.php FACEAI_LEGACY_RETURN_URL=http://localhost:8080/faceai_return.php
``` ```
The log wiring is also already done in the checked-in Compose file with a host bind mount for `./logs:/data/logs`, so both the backend and the processor write persistent diagnostics into the workspace. The log wiring is also already done in the checked-in Compose file with a host bind mount for `./logs:/data/logs`, so both the backend and the processor write persistent diagnostics into the workspace while also remaining visible through Docker and Portainer container logs.
The Compose contract now also includes an HTTP healthcheck on the public FaceAI service and a Redis readiness check. That makes `docker compose ps` meaningful during rollout: `faceai` only becomes healthy after `GET /health` returns `{"ok":true}`, and both the public site and the processor wait for Redis readiness before their own startup sequence begins.
The local PHP simulator also needs the legacy bridge feature flag enabled: The local PHP simulator also needs the legacy bridge feature flag enabled:

View file

@ -2,8 +2,17 @@ services:
faceai: faceai:
image: node:20-alpine image: node:20-alpine
container_name: regalami-faceai container_name: regalami-faceai
restart: unless-stopped
working_dir: /app working_dir: /app
command: sh -c "mkdir -p /data/logs && npm run start --workspace @regalami/faceai-backend >> /data/logs/backend.log 2>&1" command:
- node
- docker/run-with-log-file.mjs
- /data/logs/backend.log
- npm
- run
- start
- --workspace
- "@regalami/faceai-backend"
environment: environment:
PORT: 3001 PORT: 3001
FACEAI_FRONTEND_URL: http://localhost:3001 FACEAI_FRONTEND_URL: http://localhost:3001
@ -12,7 +21,7 @@ services:
FACEAI_PKL_ROOT: /data/pkl FACEAI_PKL_ROOT: /data/pkl
FACEAI_ENABLE_LOCAL_LEGACY_STATIC: 1 FACEAI_ENABLE_LOCAL_LEGACY_STATIC: 1
FACEAI_LOCAL_LEGACY_STATIC_ROOT: /legacy-www FACEAI_LOCAL_LEGACY_STATIC_ROOT: /legacy-www
FACEAI_SHARED_SECRET: change-me FACEAI_SHARED_SECRET: disagio-spaghetti-science-lol-boh
FACEAI_SESSION_COOKIE: rus_faceai_session FACEAI_SESSION_COOKIE: rus_faceai_session
FACEAI_REDIS_URL: redis://redis:6379 FACEAI_REDIS_URL: redis://redis:6379
FACEAI_RUNTIME_ROOT: /data/runtime FACEAI_RUNTIME_ROOT: /data/runtime
@ -26,8 +35,15 @@ services:
- faceai-runtime:/data/runtime - faceai-runtime:/data/runtime
ports: ports:
- "3001:3001" - "3001:3001"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3001/health | grep -q '\"ok\":true'"]
interval: 10s
timeout: 5s
retries: 6
start_period: 20s
depends_on: depends_on:
- redis redis:
condition: service_healthy
processor: processor:
build: build:
@ -35,8 +51,17 @@ services:
dockerfile: docker/processor.Dockerfile dockerfile: docker/processor.Dockerfile
image: regalami-faceai-processor-local image: regalami-faceai-processor-local
container_name: regalami-faceai-processor container_name: regalami-faceai-processor
restart: unless-stopped
working_dir: /app working_dir: /app
command: sh -c "mkdir -p /data/logs && npm run start --workspace @regalami/faceai-processor >> /data/logs/processor.log 2>&1" command:
- node
- docker/run-with-log-file.mjs
- /data/logs/processor.log
- npm
- run
- start
- --workspace
- "@regalami/faceai-processor"
environment: environment:
FACEAI_REDIS_URL: redis://redis:6379 FACEAI_REDIS_URL: redis://redis:6379
FACEAI_QUEUE_NAME: faceai-searches FACEAI_QUEUE_NAME: faceai-searches
@ -52,27 +77,38 @@ services:
- ../test_pkl:/data/pkl:ro - ../test_pkl:/data/pkl:ro
- faceai-runtime:/data/runtime - faceai-runtime:/data/runtime
depends_on: depends_on:
- redis redis:
condition: service_healthy
redis: redis:
image: redis:7-alpine image: redis:7-alpine
container_name: regalami-faceai-redis container_name: regalami-faceai-redis
restart: unless-stopped
command: redis-server --appendonly no command: redis-server --appendonly no
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 12
legacy-php: legacy-php:
image: php:8.3-apache image: php:8.3-apache
container_name: regalami-legacy-php container_name: regalami-legacy-php
restart: unless-stopped
environment: environment:
FACEAI_FEATURE_ENABLED: 1 FACEAI_FEATURE_ENABLED: 1
FACEAI_BACKEND_INTERNAL_URL: http://faceai:3001 FACEAI_BACKEND_INTERNAL_URL: http://faceai:3001
FACEAI_FRONTEND_URL: http://localhost:3001 FACEAI_FRONTEND_URL: http://localhost:3001
FACEAI_SHARED_SECRET: change-me FACEAI_SHARED_SECRET: disagio-spaghetti-science-lol-boh
FACEAI_ALLOW_DEV_HANDOFF: 1 FACEAI_ALLOW_DEV_HANDOFF: 1
FACEAI_IDENTITY_COOKIE: rus_faceai_identity FACEAI_IDENTITY_COOKIE: rus_faceai_identity
volumes: volumes:
- ../www:/var/www/html - ../www:/var/www/html
ports: ports:
- "8080:80" - "8080:80"
depends_on:
faceai:
condition: service_healthy
volumes: volumes:
faceai-runtime: faceai-runtime:

View file

@ -0,0 +1,53 @@
import fs from 'node:fs';
import fsp from 'node:fs/promises';
import path from 'node:path';
import process from 'node:process';
import { spawn } from 'node:child_process';
const [, , logPath, ...commandArgs] = process.argv;
if (!logPath || commandArgs.length === 0) {
process.stderr.write('Usage: node docker/run-with-log-file.mjs <log-path> <command> [args...]\n');
process.exit(1);
}
await fsp.mkdir(path.dirname(logPath), { recursive: true });
const logStream = fs.createWriteStream(logPath, { flags: 'a' });
const child = spawn(commandArgs[0], commandArgs.slice(1), {
cwd: process.cwd(),
env: process.env,
stdio: ['inherit', 'pipe', 'pipe']
});
function writeChunk(target, chunk) {
target.write(chunk);
logStream.write(chunk);
}
child.stdout.on('data', (chunk) => {
writeChunk(process.stdout, chunk);
});
child.stderr.on('data', (chunk) => {
writeChunk(process.stderr, chunk);
});
child.on('error', (error) => {
const message = `${error.stack || error.message}\n`;
writeChunk(process.stderr, message);
logStream.end(() => {
process.exit(1);
});
});
child.on('close', (code, signal) => {
logStream.end(() => {
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 1);
});
});