diff --git a/api/types/swarm/task.go b/api/types/swarm/task.go index 591e07ba4134b..bb28eec253f1f 100644 --- a/api/types/swarm/task.go +++ b/api/types/swarm/task.go @@ -61,6 +61,10 @@ type TaskSpec struct { // spec. If not present, the one on cluster default on swarm.Spec will be // used, finally falling back to the engine default if not specified. LogDriver *Driver `json:",omitempty"` + + // ForceUpdate is a counter that triggers an update even if no relevant + // parameters have been changed. + ForceUpdate uint64 } // Resources represents resources (CPU/Memory). diff --git a/cli/command/service/update.go b/cli/command/service/update.go index 797c989271a5c..6034979a666e6 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -37,6 +37,7 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command { flags.String("image", "", "Service image tag") flags.String("args", "", "Service command args") flags.Bool("rollback", false, "Rollback to previous specification") + flags.Bool("force", false, "Force update even if no changes require it") addServiceFlags(cmd, opts) flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable") @@ -257,6 +258,15 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error { return err } + force, err := flags.GetBool("force") + if err != nil { + return err + } + + if force { + spec.TaskTemplate.ForceUpdate++ + } + return nil } diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index 746207e02e7b3..6131ff5267a72 100644 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -2473,6 +2473,7 @@ _docker_service_update() { --constraint --endpoint-mode --env -e + --force --group-add --label -l --limit-cpu diff --git a/contrib/completion/zsh/_docker b/contrib/completion/zsh/_docker index e06082721fc18..415e731f3be16 100644 --- a/contrib/completion/zsh/_docker +++ b/contrib/completion/zsh/_docker @@ -1185,6 +1185,7 @@ __docker_service_subcommand() { "($help)--arg=[Service command args]:arguments: _normal" \ "($help)*--container-label-add=[Add or update container labels]:label: " \ "($help)*--container-label-rm=[Remove a container label by its key]:label: " \ + "($help)--force[Force update]" \ "($help)*--group-rm=[Remove previously added user groups from the container]:group:_groups" \ "($help)--image=[Service image tag]:image:__docker_repositories" \ "($help)--rollback[Rollback to previous specification]" \ diff --git a/daemon/cluster/convert/service.go b/daemon/cluster/convert/service.go index 311fe22333116..35718ee58339f 100644 --- a/daemon/cluster/convert/service.go +++ b/daemon/cluster/convert/service.go @@ -74,6 +74,7 @@ func serviceSpecFromGRPC(spec *swarmapi.ServiceSpec) *types.ServiceSpec { Placement: placementFromGRPC(spec.Task.Placement), LogDriver: driverFromGRPC(spec.Task.LogDriver), Networks: taskNetworks, + ForceUpdate: spec.Task.ForceUpdate, }, Networks: serviceNetworks, @@ -136,9 +137,10 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) { Labels: s.Labels, }, Task: swarmapi.TaskSpec{ - Resources: resourcesToGRPC(s.TaskTemplate.Resources), - LogDriver: driverToGRPC(s.TaskTemplate.LogDriver), - Networks: taskNetworks, + Resources: resourcesToGRPC(s.TaskTemplate.Resources), + LogDriver: driverToGRPC(s.TaskTemplate.LogDriver), + Networks: taskNetworks, + ForceUpdate: s.TaskTemplate.ForceUpdate, }, Networks: serviceNetworks, } diff --git a/docs/reference/api/docker_remote_api.md b/docs/reference/api/docker_remote_api.md index 7de05896692b9..6dd001090a327 100644 --- a/docs/reference/api/docker_remote_api.md +++ b/docs/reference/api/docker_remote_api.md @@ -139,6 +139,7 @@ This section lists each version from latest to oldest. Each listing includes a containers that are tasks (part of a service in swarm mode). * `POST /containers/create` now takes `StopTimeout` field. * `POST /services/create` and `POST /services/(id or name)/update` now accept `Monitor` and `MaxFailureRatio` parameters, which control the response to failures during service updates. +* `POST /services/(id or name)/update` now accepts a `ForceUpdate` parameter inside the `TaskTemplate`, which causes the service to be updated even if there are no changes which would ordinarily trigger an update. * `GET /networks/(name)` now returns field `Created` in response to show network created time. * `POST /containers/(id or name)/exec` now accepts an `Env` field, which holds a list of environment variables to be set in the context of the command execution. * `GET /volumes`, `GET /volumes/(name)`, and `POST /volumes/create` now return the `Options` field which holds the driver specific options to use for when creating the volume. diff --git a/docs/reference/api/docker_remote_api_v1.25.md b/docs/reference/api/docker_remote_api_v1.25.md index 2bde899196afd..47bc7efe486d1 100644 --- a/docs/reference/api/docker_remote_api_v1.25.md +++ b/docs/reference/api/docker_remote_api_v1.25.md @@ -4915,7 +4915,8 @@ List services "Condition": "any", "MaxAttempts": 0 }, - "Placement": {} + "Placement": {}, + "ForceUpdate": 0 }, "Mode": { "Replicated": { @@ -5038,7 +5039,8 @@ image](#create-an-image) section for more details. "Condition": "on-failure", "Delay": 10000000000.0, "MaxAttempts": 10 - } + }, + "ForceUpdate": 0 }, "Mode": { "Replicated": { @@ -5132,6 +5134,7 @@ image](#create-an-image) section for more details. - **Window** – Windows is the time window used to evaluate the restart policy (default value is 0, which is unbounded). - **Placement** – An array of constraints. + - **ForceUpdate**: A counter that triggers an update even if no relevant parameters have been changed. - **Mode** – Scheduling mode for the service (`replicated` or `global`, defaults to `replicated`). - **UpdateConfig** – Specification for the update strategy of the service. - **Parallelism** – Maximum number of tasks to be updated in one iteration (0 means unlimited @@ -5303,7 +5306,8 @@ image](#create-an-image) section for more details. "Condition": "any", "MaxAttempts": 0 }, - "Placement": {} + "Placement": {}, + "ForceUpdate": 0 }, "Mode": { "Replicated": { @@ -5374,6 +5378,7 @@ image](#create-an-image) section for more details. - **Window** – Windows is the time window used to evaluate the restart policy (default value is 0, which is unbounded). - **Placement** – An array of constraints. + - **ForceUpdate**: A counter that triggers an update even if no relevant parameters have been changed. - **Mode** – Scheduling mode for the service (`replicated` or `global`, defaults to `replicated`). - **UpdateConfig** – Specification for the update strategy of the service. - **Parallelism** – Maximum number of tasks to be updated in one iteration (0 means unlimited diff --git a/docs/reference/commandline/service_update.md b/docs/reference/commandline/service_update.md index abbd14a5ac888..90b78a45417ce 100644 --- a/docs/reference/commandline/service_update.md +++ b/docs/reference/commandline/service_update.md @@ -29,6 +29,7 @@ Options: --endpoint-mode string Endpoint mode (vip or dnsrr) --env-add value Add or update environment variables (default []) --env-rm value Remove an environment variable (default []) + --force Force update even if no changes require it --group-add value Add additional user groups to the container (default []) --group-rm value Remove previously added user groups from the container (default []) --help Print usage @@ -67,6 +68,12 @@ Updates a service as described by the specified parameters. This command has to The parameters are the same as [`docker service create`](service_create.md). Please look at the description there for further information. +Normally, updating a service will only cause the service's tasks to be replaced with new ones if a change to the +service requires recreating the tasks for it to take effect. For example, only changing the +`--update-parallelism` setting will not recreate the tasks, because the individual tasks are not affected by this +setting. However, the `--force` flag will cause the tasks to be recreated anyway. This can be used to perform a +rolling restart without any changes to the service parameters. + ## Examples ### Update a service @@ -75,6 +82,19 @@ for further information. $ docker service update --limit-cpu 2 redis ``` +### Perform a rolling restart with no parameter changes + +```bash +$ docker service update --force --update-parallelism 1 --update-delay 30s redis +``` + +In this example, the `--force` flag causes the service's tasks to be shut down +and replaced with new ones even though none of the other parameters would +normally cause that to happen. The `--update-parallelism 1` setting ensures +that only one task is replaced at a time (this is the default behavior). The +`--update-delay 30s` setting introduces a 30 second delay between tasks, so +that the rolling restart happens gradually. + ### Adding and removing mounts Use the `--mount-add` or `--mount-rm` options add or remove a service's bind-mounts