Compose Overrides Generation
Relevant source files
The following files were used as context for generating this wiki page:
The Compose Overrides Generation system is a core component of Docktree designed to enable parallel execution of Docker Compose stacks across multiple git worktrees. It works by programmatically generating YAML overlay files that modify a project's original docker-compose.yml to prevent resource collisions.
The system ensures that each worktree instance has unique container names, isolated networks, and reassigned host ports. By generating these overrides dynamically, Docktree allows developers to run the same stack multiple times on a single host without manual configuration changes.
Sources: internal/compose/override.go:13-17, internal/cli/up.go:211-235
Override Types and Structure
Docktree utilizes two primary types of override files to manage the state of a worktree project: the Clear Override and the Main Override.
Clear Override
Because Docker Compose merges port arrays rather than replacing them, a specific "clear" override is required. This override uses the !reset sequence (represented by the ResetSequence type) to strip all existing port mappings from services before new, unique ports are assigned.
Sources: internal/compose/compose.go:76-84, internal/compose/override.go:94-106
Main Override
The main override contains the transformed service definitions, networks, and volume configurations tailored for a specific worktree instance.
| Field | Description |
|---|---|
Services | A map of service overrides including renamed containers, rewritten images, and new port assignments. |
Networks | Definitions for isolated bridge networks and namespaced custom networks. |
Volumes | Overrides to isolate external or named internal volumes to the specific worktree. |
Sources: internal/compose/compose.go:4-9, internal/compose/override.go:21-30
Generation Logic and Workflow
The generation process follows a structured pipeline where the original project model is parsed and then transformed based on the worktree's identity and allocated resources.
The flow shows how Docktree transforms a standard project into a namespaced worktree instance.
Sources: internal/cli/up.go:175-235, internal/compose/override.go:13-71
Service Transformation
For every service in the project, the generator applies the following logic:
- Container Naming: If a
container_nameis present, it is prefixed with theinstanceName(e.g.,myrepo-branch-web). - Image Rewriting: If a service has a
buildblock, the image name is rewritten to a Docktree-specific tag (e.g.,docktree/instance/service:tag) to avoid overwriting images from other worktrees. - Port Mapping: Host ports are replaced with those allocated by the port registry.
- Labels: Every service is tagged with metadata labels:
docktree.managed,docktree.instance, anddocktree.repo.
Sources: internal/compose/override.go:44-65, internal/compose/override_test.go:17-45
Network and Volume Isolation
To prevent cross-worktree communication and data corruption, the system enforces isolation at the network and volume levels.
- Isolated Bridge: A per-worktree network (e.g.,
<instance>-isolated) is created. All services (unless usingnetwork_mode) are attached to this network to scope Docker's internal DNS to the worktree. - Network Namespacing: Custom internal networks are renamed by appending the instance name. External networks and platform-specific networks are generally preserved.
- Volume Namespacing: External volumes and named internal volumes (unless explicitly shared) are renamed to be unique to the worktree (e.g.,
<instance>-<volName>).
Sources: internal/compose/override.go:30-43, internal/compose/override.go:72-83, internal/compose/platform.go:133-140
Implementation Details
Key Functions
| Function | File | Purpose |
|---|---|---|
GenerateOverride | override.go | Orchestrates the creation of the Override struct from a project and port assignments. |
GeneratePortClear | override.go | Creates an override to reset port sequences for services with published ports. |
rewritePorts | override.go | Matches original port mappings to new registry assignments based on container port and host IP. |
rewriteImage | override.go | Formats the image name for built services using the docktree/ prefix. |
Sources: internal/compose/override.go:13, internal/compose/override.go:94, internal/compose/override.go:119, internal/compose/override.go:153
Port Matching Logic
The rewritePorts function ensures that when a service has multiple ports, the correct host port is assigned to the matching container port.
func rewritePorts(original []PortMapping, assignments []ports.Assignment) []PortMapping {
// ...
for _, port := range original {
for i, assignment := range remaining {
if assignment.ContainerPort == port.Target && sameHostIP(assignment.HostIP, port.HostIP) {
// Apply assigned HostPort to the mapping
}
}
}
}
Sources: internal/compose/override.go:119-151
Conclusion
Compose Overrides Generation is the mechanism that abstracts the complexities of multi-tenant Docker environments from the user. By programmatically manipulating container metadata, networking, and port bindings, it allows Docktree to treat standard Docker Compose files as templates for isolated, parallel development environments.
Sources: internal/compose/override.go:1-165, internal/cli/up.go:200-250