diff --git a/docs/packaging-and-deployment.md b/docs/packaging-and-deployment.md index 185bd11..9142eef 100644 --- a/docs/packaging-and-deployment.md +++ b/docs/packaging-and-deployment.md @@ -123,18 +123,38 @@ Service definitions are TOML files that tell MCP what to deploy. They live at `~/.config/mcp/services/.toml` on the operator workstation. -### Minimal Example (Single Component) +### Minimal Example (Single Component, L7) + +```toml +name = "myservice" +node = "rift" + +[build.images] +myservice = "Dockerfile" + +[[components]] +name = "web" +image = "mcr.svc.mcp.metacircular.net:8443/myservice:v1.0.0" + +[[components.routes]] +port = 8443 +mode = "l7" +``` + +### API Service Example (L4, Multiple Routes) ```toml name = "myservice" node = "rift" -version = "v1.0.0" [build.images] myservice = "Dockerfile" [[components]] name = "api" +image = "mcr.svc.mcp.metacircular.net:8443/myservice:v1.0.0" +volumes = ["/srv/myservice:/srv/myservice"] +cmd = ["server", "--config", "/srv/myservice/myservice.toml"] [[components.routes]] name = "rest" @@ -152,7 +172,6 @@ mode = "l4" ```toml name = "myservice" node = "rift" -version = "v1.0.0" [build.images] myservice = "Dockerfile.api" @@ -160,6 +179,7 @@ myservice-web = "Dockerfile.web" [[components]] name = "api" +image = "mcr.svc.mcp.metacircular.net:8443/myservice:v1.0.0" volumes = ["/srv/myservice:/srv/myservice"] cmd = ["server", "--config", "/srv/myservice/myservice.toml"] @@ -175,6 +195,7 @@ mode = "l4" [[components]] name = "web" +image = "mcr.svc.mcp.metacircular.net:8443/myservice-web:v1.0.0" volumes = ["/srv/myservice:/srv/myservice"] cmd = ["server", "--config", "/srv/myservice/myservice.toml"] @@ -183,21 +204,16 @@ port = 443 mode = "l7" ``` -### Convention-Derived Defaults +### Conventions -Most fields are optional — MCP derives them from conventions: +A few fields are derived by the agent at deploy time: | Field | Default | Override when... | |-------|---------|------------------| -| Image name | `` (api), `-` (others) | Image name differs from convention | -| Image registry | `mcr.svc.mcp.metacircular.net:8443` (from global MCP config) | Never — always use MCR | -| Version | Service-level `version` field | A component needs a different version | -| Volumes | `/srv/:/srv/` | Additional mounts are needed | -| Network | `mcpnet` | Service needs host networking or a different network | -| User | `0:0` | Never change this for standard services | -| Restart | `unless-stopped` | Service should not auto-restart | -| Source path | `` relative to workspace root | Directory name differs from service name | -| Hostname | `.svc.mcp.metacircular.net` | Service needs a public hostname | +| Source path | `` relative to workspace root | Directory name differs from service name (use `path`) | +| Hostname | `.svc.mcp.metacircular.net` | Service needs a public hostname (use route `hostname`) | + +All other fields must be explicit in the service definition. ### Service Definition Reference @@ -207,7 +223,6 @@ Most fields are optional — MCP derives them from conventions: |-------|----------|---------| | `name` | Yes | Service name (matches project name) | | `node` | Yes | Target node to deploy to | -| `version` | Yes | Image version tag (semver, e.g. `v1.0.0`) | | `active` | No | Whether MCP keeps this running (default: `true`) | | `path` | No | Source directory relative to workspace (default: `name`) | @@ -215,20 +230,20 @@ Most fields are optional — MCP derives them from conventions: | Field | Purpose | |-------|---------| -| `build.images.` | Maps image name to Dockerfile path | +| `build.images.` | Maps build image name to Dockerfile path. The `` must match the repository name in a component's `image` field (the part after the last `/`, before the `:` tag). | **Component fields:** -| Field | Purpose | -|-------|---------| -| `name` | Component name (e.g. `api`, `web`) | -| `image` | Full image reference override | -| `version` | Version override for this component | -| `volumes` | Volume mounts (list of `host:container` strings) | -| `cmd` | Command override (list of strings) | -| `network` | Container network override | -| `user` | Container user override | -| `restart` | Restart policy override | +| Field | Required | Purpose | +|-------|----------|---------| +| `name` | Yes | Component name (e.g. `api`, `web`) | +| `image` | Yes | Full image reference (e.g. `mcr.svc.mcp.metacircular.net:8443/myservice:v1.0.0`) | +| `volumes` | No | Volume mounts (list of `host:container` strings) | +| `cmd` | No | Command override (list of strings) | +| `env` | No | Extra environment variables (list of `KEY=VALUE` strings) | +| `network` | No | Container network (default: none) | +| `user` | No | Container user (e.g. `0:0`) | +| `restart` | No | Restart policy (e.g. `unless-stopped`) | **Route fields (under `[[components.routes]]`):** @@ -248,9 +263,11 @@ Most fields are optional — MCP derives them from conventions: ### Version Pinning -Service definitions **must** pin an explicit semver tag (e.g. `v1.1.0`). -Never use `:latest`. This ensures deployments are reproducible and -`mcp status` shows the actual running version. +Component `image` fields **must** pin an explicit semver tag (e.g. +`mcr.svc.mcp.metacircular.net:8443/myservice:v1.1.0`). Never use +`:latest`. This ensures deployments are reproducible and `mcp status` +shows the actual running version. The version is extracted from the +image tag. --- @@ -385,12 +402,17 @@ addresses** — they will be overridden at deploy time. | Env var | When set | |---------|----------| -| `$PORT` | Component has a single route | -| `$PORT_` | Component has multiple named routes | +| `$PORT` | Component has a single unnamed route | +| `$PORT_` | Component has named routes | Route names are uppercased: `name = "rest"` → `$PORT_REST`, `name = "grpc"` → `$PORT_GRPC`. +**Container listen address:** Services must bind to `0.0.0.0:$PORT` +(or `:$PORT`), not `localhost:$PORT`. Podman port-forwards go through +the container's network namespace — binding to `localhost` inside the +container makes the port unreachable from outside. + Services built with **mcdsl v1.1.0+** handle this automatically — `config.Load` checks `$PORT` → overrides `Server.ListenAddr`, and `$PORT_GRPC` → overrides `Server.GRPCAddr`. These take precedence over @@ -475,6 +497,7 @@ co-located on the same node). | `mcp build ` | Build and push images to MCR | | `mcp sync` | Push all service definitions to agents; auto-build missing images | | `mcp deploy ` | Pull image, (re)create containers, register routes | +| `mcp undeploy ` | Full teardown: remove routes, DNS, certs, and containers | | `mcp stop ` | Remove routes, stop containers | | `mcp start ` | Start previously stopped containers | | `mcp restart ` | Restart containers in place | @@ -504,13 +527,14 @@ git push origin v1.0.0 cat > ~/.config/mcp/services/myservice.toml << 'EOF' name = "myservice" node = "rift" -version = "v1.0.0" [build.images] myservice = "Dockerfile.api" [[components]] name = "api" +image = "mcr.svc.mcp.metacircular.net:8443/myservice:v1.0.0" +volumes = ["/srv/myservice:/srv/myservice"] [[components.routes]] name = "rest"