Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cmd/compose/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ func runCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backen
flags.BoolVar(&buildOpts.quiet, "quiet-build", false, "Suppress progress output from the build process")
flags.BoolVar(&options.quietPull, "quiet-pull", false, "Pull without printing progress information")
flags.BoolVar(&createOpts.Build, "build", false, "Build image before starting container")
flags.BoolVar(&createOpts.noRecreate, "no-recreate", false, "If dependent containers already exist, don't recreate them, even if their configuration diverged")
flags.BoolVar(&options.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file")

cmd.Flags().BoolVarP(&options.interactive, "interactive", "i", true, "Keep STDIN open even if not attached")
Expand Down Expand Up @@ -329,6 +330,11 @@ func runRun(ctx context.Context, backend api.Compose, project *types.Project, op
RemoveOrphans: options.removeOrphans,
IgnoreOrphans: options.ignoreOrphans,
QuietPull: options.quietPull,
// Only the dependencies run starts are subject to a recreate
// policy (the one-off itself is always a fresh container), but
// their create sees them as targeted services — set both.
Recreate: createOpts.recreateStrategy(),
RecreateDependencies: createOpts.dependenciesRecreateStrategy(),
},
Name: options.name,
Service: options.Service,
Expand Down
55 changes: 28 additions & 27 deletions docs/reference/compose_run.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,33 +57,34 @@ specified in the service configuration.

### Options

| Name | Type | Default | Description |
|:------------------------|:--------------|:---------|:---------------------------------------------------------------------------------|
| `--build` | `bool` | | Build image before starting container |
| `--cap-add` | `list` | | Add Linux capabilities |
| `--cap-drop` | `list` | | Drop Linux capabilities |
| `-d`, `--detach` | `bool` | | Run container in background and print container ID |
| `--dry-run` | `bool` | | Execute command in dry run mode |
| `--entrypoint` | `string` | | Override the entrypoint of the image |
| `-e`, `--env` | `stringArray` | | Set environment variables |
| `--env-from-file` | `stringArray` | | Set environment variables from file |
| `-i`, `--interactive` | `bool` | `true` | Keep STDIN open even if not attached |
| `-l`, `--label` | `stringArray` | | Add or override a label |
| `--name` | `string` | | Assign a name to the container |
| `--no-deps` | `bool` | | Don't start linked services |
| `-T`, `--no-tty` | `bool` | `true` | Disable pseudo-TTY allocation (default: auto-detected) |
| `-p`, `--publish` | `stringArray` | | Publish a container's port(s) to the host |
| `--pull` | `string` | `policy` | Pull image before running ("always"\|"missing"\|"never") |
| `-q`, `--quiet` | `bool` | | Don't print anything to STDOUT |
| `--quiet-build` | `bool` | | Suppress progress output from the build process |
| `--quiet-pull` | `bool` | | Pull without printing progress information |
| `--remove-orphans` | `bool` | | Remove containers for services not defined in the Compose file |
| `--rm` | `bool` | | Automatically remove the container when it exits |
| `-P`, `--service-ports` | `bool` | | Run command with all service's ports enabled and mapped to the host |
| `--use-aliases` | `bool` | | Use the service's network useAliases in the network(s) the container connects to |
| `-u`, `--user` | `string` | | Run as specified username or uid |
| `-v`, `--volume` | `stringArray` | | Bind mount a volume |
| `-w`, `--workdir` | `string` | | Working directory inside the container |
| Name | Type | Default | Description |
|:------------------------|:--------------|:---------|:-------------------------------------------------------------------------------------------------|
| `--build` | `bool` | | Build image before starting container |
| `--cap-add` | `list` | | Add Linux capabilities |
| `--cap-drop` | `list` | | Drop Linux capabilities |
| `-d`, `--detach` | `bool` | | Run container in background and print container ID |
| `--dry-run` | `bool` | | Execute command in dry run mode |
| `--entrypoint` | `string` | | Override the entrypoint of the image |
| `-e`, `--env` | `stringArray` | | Set environment variables |
| `--env-from-file` | `stringArray` | | Set environment variables from file |
| `-i`, `--interactive` | `bool` | `true` | Keep STDIN open even if not attached |
| `-l`, `--label` | `stringArray` | | Add or override a label |
| `--name` | `string` | | Assign a name to the container |
| `--no-deps` | `bool` | | Don't start linked services |
| `--no-recreate` | `bool` | | If dependent containers already exist, don't recreate them, even if their configuration diverged |
| `-T`, `--no-tty` | `bool` | `true` | Disable pseudo-TTY allocation (default: auto-detected) |
| `-p`, `--publish` | `stringArray` | | Publish a container's port(s) to the host |
| `--pull` | `string` | `policy` | Pull image before running ("always"\|"missing"\|"never") |
| `-q`, `--quiet` | `bool` | | Don't print anything to STDOUT |
| `--quiet-build` | `bool` | | Suppress progress output from the build process |
| `--quiet-pull` | `bool` | | Pull without printing progress information |
| `--remove-orphans` | `bool` | | Remove containers for services not defined in the Compose file |
| `--rm` | `bool` | | Automatically remove the container when it exits |
| `-P`, `--service-ports` | `bool` | | Run command with all service's ports enabled and mapped to the host |
| `--use-aliases` | `bool` | | Use the service's network useAliases in the network(s) the container connects to |
| `-u`, `--user` | `string` | | Run as specified username or uid |
| `-v`, `--volume` | `stringArray` | | Bind mount a volume |
| `-w`, `--workdir` | `string` | | Working directory inside the container |


<!---MARKER_GEN_END-->
Expand Down
11 changes: 11 additions & 0 deletions docs/reference/docker_compose_run.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,17 @@ options:
experimentalcli: false
kubernetes: false
swarm: false
- option: no-recreate
value_type: bool
default_value: "false"
description: |
If dependent containers already exist, don't recreate them, even if their configuration diverged
deprecated: false
hidden: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
- option: no-tty
shorthand: T
value_type: bool
Expand Down
4 changes: 4 additions & 0 deletions pkg/compose/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ func (s *composeService) startDependencies(ctx context.Context, project *types.P
IgnoreOrphans: options.IgnoreOrphans,
RemoveOrphans: options.RemoveOrphans,
QuietPull: options.QuietPull,
// empty means the default "diverged" policy; `run --no-recreate`
// passes "never" so an existing dependency is reused as-is
Recreate: options.Recreate,
RecreateDependencies: options.RecreateDependencies,
})
if err != nil {
return err
Expand Down
20 changes: 20 additions & 0 deletions pkg/e2e/compose_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,26 @@ func TestComposeRunDeps(t *testing.T) {
ServiceNotCreated("service_b"))
}

func TestComposeRunNoRecreate(t *testing.T) {
// Regression test for https://github.com/docker/compose/issues/13769
// A dependency whose config-hash diverged is recreated by the default
// "diverged" policy — correct, but state-destroying for a database
// warmed up by a previous run. --no-recreate opts out and reuses the
// existing container as-is.
NewScenario(t, "run --no-recreate must reuse an existing dependency even when its configuration diverged").
Step("run creates and starts the dependency",
ComposeCmd("run", "task").WithEnv("TAG=one"),
StdoutContains("task done"),
ServiceState("dep", "running")).
Step("by default a diverged dependency is recreated",
ComposeCmd("run", "task").WithEnv("TAG=two", "COMPOSE_IGNORE_ORPHANS=True"),
Recreated("dep")).
Step("run --no-recreate reuses the diverged dependency as-is",
ComposeCmd("run", "--no-recreate", "task").WithEnv("TAG=three", "COMPOSE_IGNORE_ORPHANS=True"),
NotRecreated("dep"),
ServiceState("dep", "running"))
}

func TestComposeRunNotRequiredDeps(t *testing.T) {
NewScenario(t, "run must skip a dependency marked required: false when its profile is inactive").
Step("run executes the service without materializing the optional dependency",
Expand Down
14 changes: 14 additions & 0 deletions pkg/e2e/testdata/TestComposeRunNoRecreate/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
task:
image: alpine
command: echo "task done"
depends_on:
- dep
dep:
image: alpine
init: true
command: sleep infinity
environment:
# divergence vector: changing TAG between invocations changes the
# config-hash of dep, which the default policy answers by recreating
TAG: ${TAG:-initial}
Loading