Files
ModelForge/docs/operations/SERVER_AGENT_DEPLOYMENT.md

116 lines
6.0 KiB
Markdown

# Remote Server Agent Deployment
## Prerequisites
The remote server needs Docker Engine with Compose v2, an NVIDIA driver, NVIDIA Container Toolkit,
and outbound HTTPS access to the central ModelForge API. It needs no inbound SSH path from
ModelForge, no public agent port, no Docker socket mount and no privileged container.
The container deliberately uses a persisted UUID because host `/etc/machine-id` is not mounted.
Hostname/OS/CPU/RAM describe the agent's Linux execution environment; without container resource
limits this normally represents the server, while configured CPU/memory limits represent the
capacity actually available to future workloads. Storage facts cover only the named ModelForge data
volumes. This avoids unsafe host-root mounts and keeps the semantics operationally honest.
The Compose service drops all Linux capabilities, enables `no-new-privileges`, uses a read-only root
filesystem and opens only a bounded in-memory `/tmp`. It publishes no port. Set
`MODELFORGE_AGENT_HOSTNAME` to the real compute-node hostname. On Unraid or another appliance, set
the four `MODELFORGE_AGENT_*_VOLUME` variables to narrow, dedicated absolute bind paths when state
must survive Docker image/volume recreation; never point one at the host root.
Expose the control-plane API through a trusted HTTPS reverse proxy. Use an internal CA by installing
that CA in the agent image/host trust store; do not disable TLS verification outside an isolated
local smoke test.
For a private CA that should be trusted only by ModelForge, combine the base file with
`docker-compose.node-agent.private-ca.yml`. Set `MODELFORGE_AGENT_CA_CERT_PATH` to the public CA
certificate, plus `MODELFORGE_AGENT_CONTROL_PLANE_HOST_ALIAS` and
`MODELFORGE_AGENT_CONTROL_PLANE_HOST_ADDRESS` when private DNS is unavailable. The overlay mounts
only that public certificate read-only and scopes the host mapping to the agent container.
## 1. Configure the control plane
Set a high-entropy `MODELFORGE_OPERATOR_API_KEY`, keep `MODELFORGE_HARDWARE_REFRESH_ON_STARTUP=false`,
and start the base stack. Create an enrollment token from **Compute nodes → Enroll node**, or:
```bash
curl -sS -X POST https://modelforge.example/api/v1/admin/node-enrollments \
-H "X-ModelForge-Admin-Token: $MODELFORGE_OPERATOR_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"expires_in_seconds":900,"display_name":"server01","role":"primary-inference","labels":{"site":"office"},"production_eligible":false,"lab_eligible":true,"benchmark_eligible":true}'
```
The response shows the enrollment secret once. Leave `production_eligible` false until the actual
node has passed hardware, identity, recovery and security acceptance. Eligibility is scheduler
metadata; setting it true does not launch a runtime or bypass later promotion evidence.
## 2. Start the agent on the GPU server
Copy/clone this repository to the server. Create `.env` without committing it:
```dotenv
MODELFORGE_AGENT_CONTROL_PLANE_URL=https://modelforge.example
MODELFORGE_AGENT_ENROLLMENT_TOKEN=<one-time-token>
MODELFORGE_AGENT_DISPLAY_NAME=Server 01
MODELFORGE_AGENT_HOSTNAME=server01
MODELFORGE_AGENT_TLS_VERIFY=true
MODELFORGE_AGENT_STATE_VOLUME=/mnt/user/appdata/modelforge-node-agent/state
MODELFORGE_AGENT_HF_CACHE_VOLUME=/mnt/cache/appdata/modelforge-node-agent/hf-cache
MODELFORGE_AGENT_ARTIFACT_VOLUME=/mnt/cache/appdata/modelforge-node-agent/artifacts
MODELFORGE_AGENT_QUARANTINE_VOLUME=/mnt/cache/appdata/modelforge-node-agent/quarantine
MODELFORGE_HF_TOKEN=<optional-secret-for-gated-repositories>
```
Then run:
```bash
docker compose -f docker-compose.node-agent.yml up -d --build
docker compose -f docker-compose.node-agent.yml logs --tail=100 node-agent
```
With the private-CA overlay, use both files for every lifecycle command:
```bash
docker compose -f docker-compose.node-agent.yml \
-f docker-compose.node-agent.private-ca.yml up -d --build
```
After the node appears online, remove `MODELFORGE_AGENT_ENROLLMENT_TOKEN` from `.env` and recreate
the service. The node-scoped credential persists in `node-agent-state`:
```bash
docker compose -f docker-compose.node-agent.yml up -d --force-recreate node-agent
```
Do not delete the state volume during ordinary upgrades; doing so discards identity and credential.
Use the UI/API to revoke the old credential before deliberately re-enrolling.
For M3, register the host cache path as a storage root and map it to
`/data/artifacts/model-registry`. The host path and container path are deliberately separate facts.
Never substitute `/mnt/user` when the cache capacity guard fails. The agent advertises
`artifact.acquire.v1`, polls one typed job at a time, and retains job-scoped partials below the
approved root for bounded retry. Keep the optional Hub token only in secret environment/config;
do not place it in Compose files or logs.
## 3. Verify and operate
Confirm the UI shows the expected hostname, agent/protocol version, heartbeat age, CPU/RAM/storage,
GPU UUID/model/VRAM/driver and measured telemetry. Restart the agent and confirm node and accelerator
UUIDs remain unchanged. Stop it long enough to observe `stale` then `offline`, restart it and confirm
`online` plus a return audit event.
For temporary outages the agent retains its identity/credential and retries with bounded exponential
backoff. Rotate with the authenticated admin rotation endpoint, securely replace
`/data/state/node-credential` with its one-time response, and recreate the agent. Revoke without a
replacement when a credential may be compromised. Disable a node to make it ineligible and immediately
reject further publications. Upgrades are ordinary image
rebuild/recreate operations; protocol-incompatible agents are visibly rejected instead of silently
downgraded.
## RTX 4080 acceptance checklist
On the actual target server, capture: `nvidia-smi` model/UUID/driver output, node-agent container
status, `/api/v1/hardware/nodes/{id}` output with secrets removed, a restart identity comparison,
stale/offline/recovery evidence, and UI screenshots. The release verdict may not claim RTX 4080
validation until these observations exist.