mando-cli: Docker Container Lifecycle
Overview
Implemented real Docker container management for mando up, mando down, and mando volume commands using the bollard 0.19 crate. Previously these commands were stubs or wired to dead code.
DockerClient (src/runtime/docker_client.rs)
Wraps bollard::Docker with container lifecycle methods:
| Method | Purpose |
|---|---|
ensure_running(spec, force) | Pull image if needed, create + start container. If force, recreates existing. |
find_container(name) | Find a mando-labeled container by name |
list_mando_containers(all) | List all containers with mando.managed=true label |
stop_and_remove(name) | Stop (10s timeout) then force-remove container |
stop_all_mando() | Stop and remove all mando-managed containers |
list_volumes_for(prefix) | List Docker volumes matching a name prefix |
remove_volume(name) | Remove a Docker volume |
ensure_image(image) | Inspect locally, pull if missing |
All managed containers get the mando.managed=true label for identification.
Container Specs (src/runtime/infra.rs)
| Service | Image | Ports | Volumes | Required |
|---|---|---|---|---|
| postgres | postgres:16-alpine | 5432:5432 | mando-pgdata | Yes |
| wiremock | wiremock/wiremock:3x-alpine | 8080:8080 | none | No (--only wiremock) |
ContainerSpec struct: name, image, ports Vec<(u16, u16)>, env, volumes (bind mount strings), network.
Containers get restart_policy: unless-stopped and bind to 0.0.0.0.
Command Wiring
mando up [--only <svc>] [--force] — starts required infra + any --only optional services. Shows port mappings in output. Profile-based app service startup not yet implemented.
mando down — stops all mando-managed containers. Reports each stopped container.
mando volume list — shows volumes grouped by service prefix.
mando volume clear [service|all] — removes matching volumes.
bollard 0.19 API Notes
start_container,list_volumes,remove_volumeno longer accept generic type params directly. UseNone::<OptionsType>for the options parameter.ContainerSummaryStateEnumdoesn’t implementDefault— need.map(|s| s.to_string())instead of.unwrap_or_default().VolumeListResponsehas.volumesdirectly (no.bodywrapper).BuildImageOptionsandCreateImageOptionsare deprecated but still work — suppressed with#[allow(deprecated)].
What’s Still Missing
mando up --profile <name>app service startup (noted in up.rs with a warning)- Status command showing container health/state
- Network creation for multi-container communication
See also:
- mando-cli-cleanup-2026-03-31
- mando-cli-v2-state-flow
- mando-cli-mock-down-idempotent-2026-05-06 — canonical 7-step pattern for docker-backed lifecycle commands + idempotent-teardown rule (404 = success in
stop_and_remove) - mando-cli-build-context-filter-2026-05-06 — yaml-driven build context (
context_includes) replacing the naiveappend_dir_all(".", ...)inrunner.rs::build_context_tar - mando-cli-status-readonly-2026-05-06 — read-only
connect_readonly/table_existshelpers; status no longer takes the migration codepath