diff --git a/cli/command/container/create.go b/cli/command/container/create.go index a055121b27..69ebd8ce29 100644 --- a/cli/command/container/create.go +++ b/cli/command/container/create.go @@ -66,6 +66,10 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *createOptions, reportError(dockerCli.Err(), "create", err.Error(), true) return cli.StatusError{StatusCode: 125} } + if err = validateAPIVersion(containerConfig, dockerCli.Client().ClientVersion()); err != nil { + reportError(dockerCli.Err(), "create", err.Error(), true) + return cli.StatusError{StatusCode: 125} + } response, err := createContainer(context.Background(), dockerCli, containerConfig, opts) if err != nil { return err diff --git a/cli/command/container/opts.go b/cli/command/container/opts.go index 7cd9ce998c..bce5c231e0 100644 --- a/cli/command/container/opts.go +++ b/cli/command/container/opts.go @@ -16,6 +16,7 @@ import ( "github.com/docker/docker/api/types/container" networktypes "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/strslice" + "github.com/docker/docker/api/types/versions" "github.com/docker/docker/pkg/signal" "github.com/docker/go-connections/nat" "github.com/pkg/errors" @@ -869,3 +870,12 @@ func validateAttach(val string) (string, error) { } return val, errors.Errorf("valid streams are STDIN, STDOUT and STDERR") } + +func validateAPIVersion(c *containerConfig, serverAPIVersion string) error { + for _, m := range c.HostConfig.Mounts { + if m.BindOptions != nil && m.BindOptions.NonRecursive && versions.LessThan(serverAPIVersion, "1.40") { + return errors.Errorf("bind-nonrecursive requires API v1.40 or later") + } + } + return nil +} diff --git a/cli/command/container/run.go b/cli/command/container/run.go index 7013a7167e..e3f36e0af7 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -84,6 +84,10 @@ func runRun(dockerCli command.Cli, flags *pflag.FlagSet, ropts *runOptions, copt reportError(dockerCli.Err(), "run", err.Error(), true) return cli.StatusError{StatusCode: 125} } + if err = validateAPIVersion(containerConfig, dockerCli.Client().ClientVersion()); err != nil { + reportError(dockerCli.Err(), "run", err.Error(), true) + return cli.StatusError{StatusCode: 125} + } return runContainer(dockerCli, ropts, copts, containerConfig) } diff --git a/cli/command/service/create.go b/cli/command/service/create.go index ec74eb43c3..c045682e03 100644 --- a/cli/command/service/create.go +++ b/cli/command/service/create.go @@ -79,6 +79,10 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *serviceOptions return err } + if err = validateAPIVersion(service, dockerCli.Client().ClientVersion()); err != nil { + return err + } + specifiedSecrets := opts.secrets.Value() if len(specifiedSecrets) > 0 { // parse and validate secrets diff --git a/cli/command/service/opts.go b/cli/command/service/opts.go index 834b537048..2478ca8e89 100644 --- a/cli/command/service/opts.go +++ b/cli/command/service/opts.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/api/types/versions" "github.com/docker/docker/client" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/api/defaults" @@ -909,3 +910,12 @@ const ( flagConfigRemove = "config-rm" flagIsolation = "isolation" ) + +func validateAPIVersion(c swarm.ServiceSpec, serverAPIVersion string) error { + for _, m := range c.TaskTemplate.ContainerSpec.Mounts { + if m.BindOptions != nil && m.BindOptions.NonRecursive && versions.LessThan(serverAPIVersion, "1.40") { + return errors.Errorf("bind-nonrecursive requires API v1.40 or later") + } + } + return nil +} diff --git a/docs/reference/commandline/service_create.md b/docs/reference/commandline/service_create.md index 0f80384018..1840b767da 100644 --- a/docs/reference/commandline/service_create.md +++ b/docs/reference/commandline/service_create.md @@ -363,16 +363,34 @@ volumes in a service:
The Engine mounts binds and volumes read-write unless readonly option - is given when mounting the bind or volume. + is given when mounting the bind or volume. Note that setting readonly for a + bind-mount does not make its submounts readonly on the current Linux implementation. See also bind-nonrecursive.
Option | +Description | +|
---|---|---|
bind-propagation | +
+ See the bind propagation section. + |
+ |
consistency | -
The consistency requirements for the mount; one of
|
|
bind-nonrecursive | +
+ By default, submounts are recursively bind-mounted as well. However, this behavior can be confusing when a
+ bind mount is configured with readonly option, because submounts are not mounted as read-only.
+ Set bind-nonrecursive to disable recursive bind-mount. + + A value is optional: + +
|
+