feat(services): volume mounts + admin volume inventory (C1)

services.volumes JSONB [{type: volume|bind, source, target, read_only}]
mapped into every replica's container config at deploy and reconcile
time, hashed into the runtime spec so mount changes trigger
reconciliation. Mounted via existing docker.HostConfig.Mounts.

- RuntimeSpec.Volumes + specHash + mount.Mount mapping in createReplica
- Create/update service accepts volumes; PUT replaces the whole list
- Replica-count reconcile now goes through the deploy queue — the last
  raw `go` reconcile left that could race a build
- GET /admin/volumes inventories node volumes with in_use flags;
  DELETE /admin/volumes/:name removes unused ones (409 on in-use)
- CLI: services update --volume/--bind/--clear-volumes, volumes
  list|delete; MCP: services_update + volumes_list/delete
- Settings UI: Volumes section with mount editor
- Migration normalizes the nullable baseline column to NOT NULL [].

Verified live: deploy applies mounts to the container, docker
auto-creates named volumes, in-use deletion is refused.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-10-08 16:38:46 +02:00
1 parent 747b714a02
commit 2f8f595d6e
21 files changed
+863 -93

No files matched your search

+18 -1
View File
@@ -37,7 +37,8 @@ Resolution order for every command: `--token`/`--api-url` flags >
auth login|logout|status token auth and profiles
tokens list|create|revoke personal access tokens
projects list|get|create|delete
services list|get|create|delete|start|stop|restart|redeploy
services list|get|create|update|delete|start|stop|restart|redeploy
volumes list|delete docker volume inventory + cleanup (admin)
deploy <service-id> trigger a deployment (--no-cache, --commit-hash, --branch)
deployments list|get|logs|rollback|cancel
logs <service-id> [--follow] runtime logs (SSE follow)
@@ -70,6 +71,22 @@ containr up --project <id> --image ghcr.io/example/app:latest # image, no buil
Set `project_id` on the active profile to omit `--project` (stored in
`~/.containr.yaml` under `profiles.<name>.project_id`).
## Service volumes
`services update` manages mounts; flags replace the whole mount list:
```bash
containr services update <id> --volume data:/data --bind /srv/cfg:/etc/app:ro
containr services update <id> --clear-volumes
```
`type` is `volume` (docker named volume, auto-created) or `bind` (host
path). `target` must be absolute. Mounts apply on the next deploy or
redeploy — `containr deploy <id>` to apply immediately.
`volumes list` shows the node's docker volume inventory with in-use
flags; `volumes delete <name>` removes an unused volume (admin scope).
## MCP server
`containr-mcp` (`go build ./cmd/mcp`) exposes the same API as MCP tools