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.

Concretely, that costs three things:

Two descriptions that can disagree. The Compose file would say one thing, the Onebox annotations another, and nothing would arbitrate.

No derivation. 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.

No honest defaults. strategy: rolling needs a health check to gate it. When the health check lives in a file Onebox merely reads, “is this rollout gated?” becomes a question rather than a fact.

  • Derived, stable names. Application containers use the uniform <app>-<component>-<replica> grammar, such as shop-web-1; persistent and provider resources include ob_shop_postgres_data, ob_shop, and ob-ingress. Once a volume exists its name cannot change without moving data, and a foreign resource already holding a derived name is refused rather than 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, domain and path is route_collision, rather than a proxy that accepts both and routes to one with nothing saying which.

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

ob eject strips the overlay, so what lands in your repository is ordinary Compose — not Compose carrying Onebox labels you would then have to unpick — and your workloads are repointed at it with your comments intact.

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 ob. or traefik. namespaces. See Adopt an existing Compose file.

The result is a contract that generates by default and defers on request, rather than one that can only do one of the two.