瀏覽代碼

Add force option to service update

Currently, there's no way to restart the tasks of a service without
making an actual change to the service. This leads to us giving awkward
workarounds as in
https://github.com/docker/docker.github.io/pull/178/files, where we tell
people to scale a service up and down to restore balance, or make
unnecessary changes to trigger a restart.

This change adds a --force option to "docker service update", which
forces the service to be updated even if no changes require that.

Since rolling update parameters are respected, the user can use
"docker service --force" to do a rolling restart. For example, the
following is supported:

   docker service update --force --update-parallelism 2 \
   --update-delay 5s myservice

Since the default value of --update-parallelism is 1, the default
behavior is to restart the service one task at a time.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
Aaron Lehmann 8 年之前
父節點
當前提交
c9fdf9abf8

+ 4 - 0
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
 	// 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.
 	// used, finally falling back to the engine default if not specified.
 	LogDriver *Driver `json:",omitempty"`
 	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).
 // Resources represents resources (CPU/Memory).

+ 10 - 0
cli/command/service/update.go

@@ -37,6 +37,7 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
 	flags.String("image", "", "Service image tag")
 	flags.String("image", "", "Service image tag")
 	flags.String("args", "", "Service command args")
 	flags.String("args", "", "Service command args")
 	flags.Bool("rollback", false, "Rollback to previous specification")
 	flags.Bool("rollback", false, "Rollback to previous specification")
+	flags.Bool("force", false, "Force update even if no changes require it")
 	addServiceFlags(cmd, opts)
 	addServiceFlags(cmd, opts)
 
 
 	flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable")
 	flags.Var(newListOptsVar(), flagEnvRemove, "Remove an environment variable")
@@ -257,6 +258,15 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error {
 		return err
 		return err
 	}
 	}
 
 
+	force, err := flags.GetBool("force")
+	if err != nil {
+		return err
+	}
+
+	if force {
+		spec.TaskTemplate.ForceUpdate++
+	}
+
 	return nil
 	return nil
 }
 }
 
 

+ 1 - 0
contrib/completion/bash/docker

@@ -2473,6 +2473,7 @@ _docker_service_update() {
 		--constraint
 		--constraint
 		--endpoint-mode
 		--endpoint-mode
 		--env -e
 		--env -e
+		--force
 		--group-add
 		--group-add
 		--label -l
 		--label -l
 		--limit-cpu
 		--limit-cpu

+ 1 - 0
contrib/completion/zsh/_docker

@@ -1185,6 +1185,7 @@ __docker_service_subcommand() {
                 "($help)--arg=[Service command args]:arguments: _normal" \
                 "($help)--arg=[Service command args]:arguments: _normal" \
                 "($help)*--container-label-add=[Add or update container labels]:label: " \
                 "($help)*--container-label-add=[Add or update container labels]:label: " \
                 "($help)*--container-label-rm=[Remove a container label by its key]: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)*--group-rm=[Remove previously added user groups from the container]:group:_groups" \
                 "($help)--image=[Service image tag]:image:__docker_repositories" \
                 "($help)--image=[Service image tag]:image:__docker_repositories" \
                 "($help)--rollback[Rollback to previous specification]" \
                 "($help)--rollback[Rollback to previous specification]" \

+ 5 - 3
daemon/cluster/convert/service.go

@@ -74,6 +74,7 @@ func serviceSpecFromGRPC(spec *swarmapi.ServiceSpec) *types.ServiceSpec {
 			Placement:     placementFromGRPC(spec.Task.Placement),
 			Placement:     placementFromGRPC(spec.Task.Placement),
 			LogDriver:     driverFromGRPC(spec.Task.LogDriver),
 			LogDriver:     driverFromGRPC(spec.Task.LogDriver),
 			Networks:      taskNetworks,
 			Networks:      taskNetworks,
+			ForceUpdate:   spec.Task.ForceUpdate,
 		},
 		},
 
 
 		Networks:     serviceNetworks,
 		Networks:     serviceNetworks,
@@ -136,9 +137,10 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
 			Labels: s.Labels,
 			Labels: s.Labels,
 		},
 		},
 		Task: swarmapi.TaskSpec{
 		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,
 		Networks: serviceNetworks,
 	}
 	}

+ 1 - 0
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).
   containers that are tasks (part of a service in swarm mode).
 * `POST /containers/create` now takes `StopTimeout` field.
 * `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/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.
 * `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.
 * `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.
 * `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.

+ 8 - 3
docs/reference/api/docker_remote_api_v1.25.md

@@ -4915,7 +4915,8 @@ List services
               "Condition": "any",
               "Condition": "any",
               "MaxAttempts": 0
               "MaxAttempts": 0
             },
             },
-            "Placement": {}
+            "Placement": {},
+            "ForceUpdate": 0
           },
           },
           "Mode": {
           "Mode": {
             "Replicated": {
             "Replicated": {
@@ -5038,7 +5039,8 @@ image](#create-an-image) section for more details.
           "Condition": "on-failure",
           "Condition": "on-failure",
           "Delay": 10000000000.0,
           "Delay": 10000000000.0,
           "MaxAttempts": 10
           "MaxAttempts": 10
-        }
+        },
+        "ForceUpdate": 0
       },
       },
       "Mode": {
       "Mode": {
         "Replicated": {
         "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
         - **Window** – Windows is the time window used to evaluate the restart policy (default value is
           0, which is unbounded).
           0, which is unbounded).
     - **Placement** – An array of constraints.
     - **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`).
 - **Mode** – Scheduling mode for the service (`replicated` or `global`, defaults to `replicated`).
 - **UpdateConfig** – Specification for the update strategy of the service.
 - **UpdateConfig** – Specification for the update strategy of the service.
     - **Parallelism** – Maximum number of tasks to be updated in one iteration (0 means unlimited
     - **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",
           "Condition": "any",
           "MaxAttempts": 0
           "MaxAttempts": 0
         },
         },
-        "Placement": {}
+        "Placement": {},
+        "ForceUpdate": 0
       },
       },
       "Mode": {
       "Mode": {
         "Replicated": {
         "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
         - **Window** – Windows is the time window used to evaluate the restart policy (default value is
           0, which is unbounded).
           0, which is unbounded).
     - **Placement** – An array of constraints.
     - **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`).
 - **Mode** – Scheduling mode for the service (`replicated` or `global`, defaults to `replicated`).
 - **UpdateConfig** – Specification for the update strategy of the service.
 - **UpdateConfig** – Specification for the update strategy of the service.
     - **Parallelism** – Maximum number of tasks to be updated in one iteration (0 means unlimited
     - **Parallelism** – Maximum number of tasks to be updated in one iteration (0 means unlimited

+ 20 - 0
docs/reference/commandline/service_update.md

@@ -29,6 +29,7 @@ Options:
       --endpoint-mode string             Endpoint mode (vip or dnsrr)
       --endpoint-mode string             Endpoint mode (vip or dnsrr)
       --env-add value                    Add or update environment variables (default [])
       --env-add value                    Add or update environment variables (default [])
       --env-rm value                     Remove an environment variable (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-add value                  Add additional user groups to the container (default [])
       --group-rm value                   Remove previously added user groups from the container (default [])
       --group-rm value                   Remove previously added user groups from the container (default [])
       --help                             Print usage
       --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
 The parameters are the same as [`docker service create`](service_create.md). Please look at the description there
 for further information.
 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
 ## Examples
 
 
 ### Update a service
 ### Update a service
@@ -75,6 +82,19 @@ for further information.
 $ docker service update --limit-cpu 2 redis
 $ 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
 ### Adding and removing mounts
 
 
 Use the `--mount-add` or `--mount-rm` options add or remove a service's bind-mounts
 Use the `--mount-add` or `--mount-rm` options add or remove a service's bind-mounts