[Solved] Force-update a service with the REST-API does not work as expected

Hi docker-swarm-community,

using the API I want to force-update a service in my swarm. That means I just want a service create with the name test-hello-world and image hello-world:latest update to the latest version (btw hello-world is in my own registry). But I’m currently struggling with this simple task. The working cli command for a service is:

docker service update test-hello-world --force

The command works, the service is updated to the latest image, envs and ports are still mapped.

In my swarm I need to automatically do that for many services with a more or less complex script. While I could use node.js to execute the command on the command line it seems to be more natural to use the REST-API. So I’ve tried the API and it does not work out the way I thought it would be.

Using the docs at h ttps://docs.docker.com/engine/api/v1.37/#operation/ServiceUpdate and curl I assembled this request:

Request

curl -X POST -H "Content-Type: application/json" -d '{ "TaskTemplate": { "ForceUpdate": 1 } }' --unix-socket /var/run/docker.sock http:/v1.37/services/fy7fp5tb8e8s6uq53mu2ckpe5/update?version=1479

Response

{"message":"mismatched Runtime and *Spec fields"}

Strange error, a quick search lead me to the comment in the source code // If the ContainerSpec is nil, we can't set the task runtime. (https://github.com/docker/docker-ce/blob/master/components/engine/daemon/cluster/convert/service.go#L182)

So I tried different things out:


Request

curl -X POST -H "Content-Type: application/json" -d '{ "TaskTemplate": { "ForceUpdate": 1, "ContainerSpec": {} } }' --unix-socket /var/run/docker.sock http:/v1.37/services/o2gwea12kjom/update?version=1519

Response
{"message":"rpc error: code = InvalidArgument desc = ContainerSpec: image reference must be provided"}

Ok, adding the ContainerSpec with the image (even if it should not change…).


Request

curl -X POST -H "Content-Type: application/json" -d '{ "TaskTemplate": { "ForceUpdate": 1, "ContainerSpec": { "Image": "docker.mydomain.com/hello-world" } } }' --unix-socket /var/run/docker.sock http:/v1.37/services/o2gwea12kjom/update?version=1519

Response

{"message":"rpc error: code = Unimplemented desc = renaming services is not supported"}


Request

curl -X POST -H "Content-Type: application/json" -d '{ "Name": "test-hello-world", "TaskTemplate": { "ForceUpdate": 1, "ContainerSpec": { "Image": "docker.triggerco.de/hello-world" } } }' --unix-socket /var/run/docker.sock http:/v1.37/services/o2gwea12kjom/update?version=1538

Response

{"Warnings":null}

Seems to work. But ”noooooo”. The service lost all EndpointSpecs, Ports, Labels, everything, I’ve double checked that the version was correct. So that can’t be the issue.

My questions:

  1. Am I doing something wrong?
  2. Or is this a bug?
  3. The docs at https://docs.docker.com/engine/api/v1.37/#operation/ServiceUpdate seem to be incomplete, at least the API needs some parameters that are not flagged as required. Neither simple nor complex scenarios are described. Is this the best the docs has to offer? I found some basic examples here, but they are thought for usage without the swarm.

Any help is appreciated. Thanks!

BR, Tobias

To answer my own questions

Am I doing something wrong?

Yes, on the contrary to the cli the API was designed that the complete state needs to be passed. See Docker service update via API removes the configuration of ommited keys · Issue #1394 · moby/swarmkit · GitHub.

Or is this a bug?

Works as designed.

The docs at h ttps://docs.docker.com/engine/api/v1.37/#operation/ServiceUpdate seem to be incomplete, at least the API needs some parameters that are not flagged as required. Neither simple nor complex scenarios are described. Is this the best the docs has to offer? I found some basic examples here, but they are thought for usage without the swarm.

I could not find a better documentation.


My solution

I fetch the service spec via Docker Engine API v1.39 Reference and pass the complete Spec into the ServiceUpdate endpoint with ForceUpdate set to 1 and the version set as query param.