Skip to content

Why Compose is generated

Onebox does not read a Compose file you wrote. The contract is a declaration of what the application is; the Compose file, the container names and the routing labels are all derived from it.

Under the ownership boundary, Onebox owns the runtime. Reading a runtime you wrote inverts that: you own it, and Onebox merely operates something it did not design and cannot fully reason about.

The Compose file and Onebox annotations could disagree, with nothing to arbitrate between them.

Onebox could not choose the container name, the volume name, the router rule or the network, because you already would have. So it could not guarantee they are consistent, collision-free, or stable across releases.

strategy: rolling needs a health check to gate it. Reading a health check from an authored file would leave Onebox unable to guarantee that the rollout is gated.

  • Derived, stable names. Workload containers use the uniform <app>-<component>-<replica> grammar, such as shop-web-1; managed services are onebox-<service>, such as onebox-postgres; persistent and provider resources include shop_default, onebox_postgres_data, onebox_services, and onebox-ingress. The application and service networks are declared external and created under Onebox’s ownership fence, so Compose cannot remove a live shared network during release teardown. A full ob destroy --volumes removes them; if an unmanaged endpoint remains attached, destruction stops without deleting Onebox’s recovery state or releasing host ownership. Once a resource exists its name cannot change without migration, and a foreign resource already holding a derived name is refused, not adopted.
  • Digest binding. The rendered Compose is bound into the plan, so what was reviewed is what executes.
  • Refusals that mean something. strategy_ungated, route_collision, stateful_replicas are all statements about the generated runtime, which is the only thing that will actually run.
  • Typed routing. Two workloads claiming the same entrypoint, protocol, hostname and path produce route_collision. This prevents the proxy from accepting both and routing to one without saying which.

Changing a workload’s key is a rename in the declaration but a replacement at runtime. Onebox starts and verifies the new workload, activates the release, and only then drains and removes the old workload. This ordering keeps a route rename from stopping the old endpoint before the new one can serve.

Persistent volumes follow the same identity rule: a renamed workload receives new derived volume names. Onebox does not guess that data should move between them. Move or reattach persistent data explicitly before treating a workload rename as complete.

Generation is only acceptable because the output is inspectable and the exit is a command:

Terminal window
ob preview # print the generated runtime, change nothing
ob eject # write it out and hand it over, permanently

See Eject for the output and what remains on the host.

A container Onebox cannot describe is adopted verbatim:

workloads:
legacy:
role: Daemon
compose: docker-compose.yml#legacy

Refusals apply only where the referenced service contradicts something Onebox owns: extends, a fixed container_name, network_mode, labels in the onebox. or traefik. namespaces. See Adopt an existing Compose file.

The contract generates by default and defers on request.