docs(arch): draft alknet-docker architecture specs (ADRs 058-063, OQs 048-051)
Greenfield architecture spec set for the alknet-docker crate — a thin, single-host bollard wrapper exposing docker container/image operations as call-protocol ops on the shared alknet/call ALPN, plus a DockerTtyBackend (impl TtyBackend) behind a tty feature for interactive terminal sessions into containers over alknet/tty. Six ADRs: - 058: docker ops on alknet/call (no separate ALPN; raw-carriage handoff dissolved by alknet-tty extraction — interactive attach moved to alknet/tty via DockerTtyBackend, no carriage field on call.requested) - 059: bollard 0.21 (verified current on crates.io) + feature selection (http+pipe+time; no ssl/ssh/websocket/buildkit) - 060: container resource model (ADR-050 application) — alknet.managed/ alknet.owner labels, list owned_only flag, hosted-services operator role via static-resource fallback, handler-driven revoke with autonomous-death tolerance, resource-action vocabulary - 061: DockerTtyBackend in alknet-docker behind tty feature (attach vs exec mode; POC drive_attach_raw as reference) - 062: Docker client + OwnershipStore injection via closure capture (not Capabilities, not OperationContext — matches from_openapi pattern) - 063: exit code on terminal call.responded for non-interactive exec (call.completed stays empty, ADR-012 unchanged) Four spec docs (crates/docker/): README, overview, docker-operations, docker-tty-backend. Four deferred-scope OQs (048-051): network/volume ops, buildkit, system events subscription, create options surface. Updates the tty-backend.md Backend implementations table (DockerTtyBackend row now specced) and the architecture README (doc table, ADR table, current-state paragraph, OQ count). Grounded in the alknet-docker POC (docs/research/alknet-docker/poc-summary.md) which validated the hard parts; the remaining lifecycle ops are mechanical bollard wrapping. Reviewed by architecture-reviewer subagent; criticals (the docker_client injection model conflicting with the Capabilities contract) resolved via ADR-062/063 before commit.
This commit is contained in:
1 parent
5873fa22d6
commit
1ce11717d8
17 files changed
+3196
-9
No files matched your search
@@ -0,0 +1,30 @@
|
||||
# OQ-48: Network and Volume Operation Surface
|
||||
|
||||
- **Origin**:
|
||||
[crates/docker/docker-operations.md](crates/docker/docker-operations.md)
|
||||
§"Operation Surface (v1 scope)" (out-of-scope list).
|
||||
- **Status**: deferred(scope)
|
||||
- **Door type**: Two-way
|
||||
- **Priority**: low
|
||||
- **Blocked on**: a concrete use case for network or volume management
|
||||
over the call protocol. The two container use cases (disposable dev
|
||||
containers, hosted services) don't currently require
|
||||
network/volume CRUD over the call protocol — dev containers use
|
||||
the default bridge network; hosted services are configured via
|
||||
`docker compose` with networks/volumes declared in the compose file.
|
||||
- **Resolution**: Not yet decidable. bollard has the API surface
|
||||
(`network.rs`: `create_network`, `remove_network`, `inspect_network`,
|
||||
`list_networks`, `connect_network`, `disconnect_network`;
|
||||
`volume.rs`: `list_volumes`, `create_volume`, `inspect_volume`,
|
||||
`remove_volume`, `prune_volumes`) — the mapping is mechanical, the
|
||||
same shape as the container lifecycle ops (`Query`/`Mutation`,
|
||||
single `call.responded`). The deferral is scope, not feasibility:
|
||||
v1 is containers + images; networks and volumes are added when a
|
||||
use case forces them (e.g., a coordinator that needs to create
|
||||
isolated networks for dev containers, or a fleet layer that manages
|
||||
volumes across hosts). Adding them is additive (new operations in
|
||||
the registry) and does not break the existing surface.
|
||||
- **Cross-references**:
|
||||
[ADR-058](decisions/058-alknet-docker-on-alknet-call.md) (the shared
|
||||
`alknet/call` registration model new ops would follow),
|
||||
[crates/docker/docker-operations.md](crates/docker/docker-operations.md)
|
||||
@@ -0,0 +1,30 @@
|
||||
# OQ-49: Image Build (buildkit) Scope
|
||||
|
||||
- **Origin**:
|
||||
[crates/docker/docker-operations.md](crates/docker/docker-operations.md)
|
||||
§"Out of scope for v1"; [ADR-059](decisions/059-bollard-021-dependency-and-features.md)
|
||||
§3 (no `buildkit` feature).
|
||||
- **Status**: deferred(scope)
|
||||
- **Door type**: Two-way
|
||||
- **Priority**: low
|
||||
- **Blocked on**: a concrete use case for building images over the
|
||||
call protocol. The two container use cases (disposable dev
|
||||
containers, hosted services) pull pre-built images (`docker/image/pull`)
|
||||
rather than building them. The reverse-proxy and other hosted
|
||||
services build via `docker compose build` (operator-side), not via
|
||||
alknet.
|
||||
- **Resolution**: Not yet decidable. bollard's `build_image` (image.rs:655)
|
||||
and the `buildkit` feature (which pulls tonic +
|
||||
bollard-buildkit-proto) are available but deferred. Build is a large
|
||||
feature (build context upload, layer caching, multi-stage, buildkit
|
||||
progress streaming) and is not needed for the current scope. When a
|
||||
use case forces it, the operation is a `Subscription` (progress
|
||||
events → `call.responded`, build complete → `call.completed`) and
|
||||
the `buildkit` feature is enabled in `Cargo.toml` (two-way-door
|
||||
feature addition, per ADR-059). The v1 surface has `image/pull` +
|
||||
`image/list` + `image/inspect`; `image/build` is added when needed.
|
||||
- **Cross-references**:
|
||||
[ADR-059](decisions/059-bollard-021-dependency-and-features.md)
|
||||
(feature set decision — `buildkit` not enabled),
|
||||
[crates/docker/overview.md](crates/docker/overview.md) §"bollard
|
||||
version and features"
|
||||
@@ -0,0 +1,34 @@
|
||||
# OQ-50: Docker System Events Subscription
|
||||
|
||||
- **Origin**:
|
||||
[crates/docker/docker-operations.md](crates/docker/docker-operations.md)
|
||||
§"Out of scope for v1";
|
||||
[ADR-060](decisions/060-container-resource-model-and-label-namespace.md)
|
||||
§4 (autonomous-death tolerance).
|
||||
- **Status**: deferred(scope)
|
||||
- **Door type**: Two-way
|
||||
- **Priority**: low
|
||||
- **Blocked on**: a concrete use case for prompt stale-ownership
|
||||
cleanup. The base model (ADR-060 §4) tolerates stale ownership
|
||||
entries from autonomous container death (a `--rm` exit, external
|
||||
`docker rm`, daemon restart) — they're inert (a reused container ID
|
||||
gets a fresh `record` on its next `create`). A reaper that
|
||||
subscribes to docker daemon events would clean them promptly, but
|
||||
the promptness gain is marginal for the current use cases.
|
||||
- **Resolution**: Not yet decidable. bollard's `events()`
|
||||
(system.rs:128) returns a `Stream<SystemEventsMessage>` of daemon
|
||||
events (container start/stop/die/destroy, image pull, etc.). A
|
||||
`docker/system/events` `Subscription` operation would surface these
|
||||
as `call.responded` frames; the ownership store could subscribe
|
||||
internally to revoke on `destroy` events. The deferral is scope:
|
||||
the base model works without it; the events subscription is a
|
||||
refinement for when prompt cleanup matters (e.g., a high-churn
|
||||
coordinator that spawns/removes many containers and wants the
|
||||
ownership store to stay tight). Adding it is additive (a new
|
||||
operation + an internal store subscription) and does not break the
|
||||
existing surface.
|
||||
- **Cross-references**:
|
||||
[ADR-060](decisions/060-container-resource-model-and-label-namespace.md)
|
||||
§4 (teardown coupling — stale-entry tolerance is the base model
|
||||
this subscription would refine),
|
||||
[crates/docker/docker-operations.md](crates/docker/docker-operations.md)
|
||||
@@ -0,0 +1,37 @@
|
||||
# OQ-51: Container Create Options Surface
|
||||
|
||||
- **Origin**:
|
||||
[crates/docker/docker-operations.md](crates/docker/docker-operations.md)
|
||||
§"Out of scope for v1";
|
||||
[crates/docker/docker-operations.md](crates/docker/docker-operations.md)
|
||||
§"`docker/container/create`".
|
||||
- **Status**: deferred(scope)
|
||||
- **Door type**: Two-way
|
||||
- **Priority**: medium
|
||||
- **Blocked on**: v1 implementation. The v1 `create` input schema
|
||||
accepts the common fields (image, command, env, labels, name) and
|
||||
the full `CreateContainerOptions` surface (mounts, port bindings,
|
||||
networks, volumes, capabilities, etc.) is deferred to the
|
||||
implementation pass, where the input JSON Schema can be designed
|
||||
against bollard's `Config` struct and tested against real create
|
||||
calls. This is not an architectural decision (the `create` operation
|
||||
is already decided — ADR-060 §5); it's a schema-detail decision
|
||||
best made with the bollard types in hand.
|
||||
- **Resolution**: Not yet decidable. bollard's `create_container`
|
||||
takes a `Config` struct (`container.rs:296`) with ~40 fields
|
||||
(`Image`, `Cmd`, `Env`, `Labels`, `HostConfig` with mounts/ports/
|
||||
networks/etc.). The v1 input schema accepts the high-frequency
|
||||
fields and omits the long tail; the full surface is a JSON Schema
|
||||
design task (which fields are required, which are optional, how
|
||||
`HostConfig` is nested, how the `alknet.*` labels merge with
|
||||
caller labels). The deferral is to the implementation pass, not
|
||||
past it — the schema is finalized when `register_docker_ops` is
|
||||
written and tested. The `OperationSpec.input_schema` is the
|
||||
one-way surface; its exact field set is a two-way-door refinement
|
||||
within it.
|
||||
- **Cross-references**:
|
||||
[ADR-060](decisions/060-container-resource-model-and-label-namespace.md)
|
||||
§5 (`create` records ownership — the architectural decision this
|
||||
OQ defers the schema details of),
|
||||
[crates/docker/docker-operations.md](crates/docker/docker-operations.md)
|
||||
§"`docker/container/create`"
|
||||
Reference in new issue
Block a user