Operational guidance

Container Execution

How container mode and Dockerfiles fit together in ota.

referenceautomation buildersintermediatestable2026-05-30

When to use this page

Use this page when a repo already has a Dockerfile and you need to decide how ota fits around it.

Choose this when you want the image build and the readiness contract to stay in separate layers so each one stays honest.

  • Dockerfile builds the image
  • ota.yaml declares what the repo needs
  • ota run and ota up execute against the declared environment
  • when legacy execution.preferred: container is set, or when a selected execution context uses backend: container, ota runs inside that image instead of on the host
  • if the image comes from a Dockerfile, the Dockerfile is what made the container runnable
  • the contract still matters even when the image already exists

Boundary note

  • Docker is optional, not a universal prerequisite for ota
  • use container mode when the repo or org already allows it
  • host bootstrap for Docker is a separate concern and should not be assumed by default
  • container mode primarily governs workload execution; topology-aware service reachability now comes from execution contexts plus services.endpoints and services.readiness, not from assuming host and container see the same service surface.
  • use tasks.<name>.runtime.listeners when the app itself should stay in the container but still publish a deterministic host URL for browsers, curl, or local tooling

How they differ

  • Dockerfile handles OS packages, runtimes, and reproducible image setup
  • ota handles tasks, checks, safe AI-agent guidance, provisioning policy, and execution mode
  • container mode gives ota a repeatable runtime boundary for run and up
  • workload listeners let ota report the resolved published URL for long-running app tasks instead of making users guess the host port
  • doctor still explains whether the repo is ready inside that boundary
  • ota doctor --mode container and ota up --mode container target the container image directly
  • explicit container mode stops before any host provisioning fallback when the image cannot satisfy declared pins or no supported container engine is available
  • if the selected image cannot be pulled or started, ota doctor --container reports that image acquisition blocker before reporting runtime or tool probes inside the image
  • use both when the repo already ships a Dockerfile and still needs explicit readiness rules

Simple model

Flowtext
Dockerfile  -> builds the imageota.yaml    -> declares what the repo needsota run/up  -> executes against the declared environment

Example

Dockerfiledockerfile
FROM eclipse-temurin:21-jdkWORKDIR /workspaceCOPY . .RUN ./mvnw -q dependency:go-offline
ota.yamlyaml
version: 1project:  name: sample-java-servicetoolchains:  java:    version: "21"tools:  maven: "*"tasks:  setup:    internal: true    prepare:      kind: dependency_hydration      medium: package_dependencies      source:        kind: maven        cwd: .        mode: go_offline    requirements:      toolchains:        - java      tools:        maven: "*"    effects:      writes:        - .m2      network: true      network_kind: dependency_hydration  test:    run: mvn testexecution:  preferred: container  lifecycle: persistent  backends:    container:      image: eclipse-temurin:21-jdk

Rule of thumb

  • use the Dockerfile to make the image runnable
  • use the ota contract to make the repo explainable, diagnosable, and safe
  • use container mode when you want ota to run against the image instead of the host
  • use ota up --dry-run --mode container when you want the exact container preparation plan before ota mutates anything
  • use ota up --mode container when you want ota to prepare the repo inside that image before running tasks
  • do not replace the contract with the Dockerfile, because the Dockerfile does not tell ota what is safe to run or what should be provisioned
  • do not make Docker the default adoption requirement unless the repo or org already uses it

Preview example

The preview should read like a real operator plan, not a second generic explanation layer.

Container previewtext
๐Ÿฆฆ UP PREVIEW ./ota.yamlย โžค NOT READYย โ– Mode: dry-run (no write)ย Executionโ†’ Backend: containerโ†’ Lifecycle: persistentโ†’ Image: `eclipse-temurin:21-jdk`โ†’ Task: `setup`ย Contractโ†’ Project: java-serviceโ†’ Version: 1โ†’ Execution: preferred=container, lifecycle=persistent, image=eclipse-temurin:21-jdkโ†’ Counts: runtimes=1, tools=1, env=0, services=0, checks=0, tasks=2ย Planโ†’ provision `java` `21` via `sdkman`โ†’ run task `setup`โ†’ re-check repo readinessย โžค Primary BlockerMissing runtime: javaWhy: java is declared in the contract but is not available inside the configured ยป  Image: `eclipse-temurin:21-jdk`Next: update `execution.backends.container.image` so `java` is available, then rerun `ota up --dry-run --mode container`