environment
Is there a way to force a rolling update to a docker swarm service already running if the service update is not changing any parameters but the docker hub image has been updated?
Example: I deployed service:
docker service create --replicas 1 --name servicename --publish 80:80 username/imagename:latest
My build process has updated the latest image on docker hub now I want to pull the latest again.
I have tried running:
docker service update --image username/imagename:latest servicename
When I follow this process, docker does not pull the latest, I guess it assumes that since I wanted latest and docker already pulled an image:latest then there is nothing to do.
The only work around I have is to remove the service servicename and redeploy.
To update to a newer image, you first need to pull the new version. Run the docker pull command followed by a colon and the name and the tag of the newer image: the name and tag that you took note of previously.
Use the --network-add or --network-rm flags to add or remove a network for a service. You can use the short or long syntax discussed in the docker service create reference.
By default, when an update to an individual task returns a state of RUNNING , the scheduler schedules another task to update until all tasks are updated. If, at any time during an update a task returns FAILED , the scheduler pauses the update.
Just for future reference:
Docker 1.13 added a --force
flag to service update
:
--force
: Force update even if no changes require it
Use it as in:
docker service update --force service_name
Docker won't automatically perform a pull from DockerHub (or private registry) for an image:tag you already have locally.
If you performed a manual pull before the docker service update
, or deleted the image locally, it would.
You could also chain the command:
docker pull image:tag && docker service update --image username/imagename:latest servicename
You can avoid this scenario by tagging your images numerically and using an updated tag. username/imagename:1.1.0
You could use image ID instead of username/imagename:latest
like this:
docker service update --image \
$(docker inspect --type image --format '{{.Id}}' username/imagename:latest) \
servicename
But in this case all your nodes must pull this image before service update. Otherwise, containers will be updated only on those nodes where image with such ID exists. Fortunately, nodes which do not have this image will stop their containers, so there is nothing bad if some nodes will fail to pull new version of image.
UPDATE: or you could use image digest as follow:
docker service update --image \
$(docker inspect --type image --format '{{index .RepoDigests 0}}' username/imagename:latest) \
servicename
docker inspect --type image --format '{{index .RepoDigests 0}}' IMAGE
returns image digest which includes unique hash of image generated by registry v2. Thus, image must be pulled from registry, otherwise digest will not be available.
Using digest allow you do not pull images on all of your nodes (images with specified digest will automatically be pulled from registry on necessary nodes). But you have to pull fresh version of image once on a manager node before service update.
BTW, last way will be default since Docker 1.13
If you want to update docker service image, you can simply do docker service update --image myimage:tag servicename
. e.g. docker service update --image traefik:1.7.5 traefik_proxy
Also by not using myimage:latest
tag, it makes sure you will not unintentionally update to latest updated major/minor release instead of patch release.
Ref: https://github.com/moby/moby/issues/30951#issuecomment-279479589
What I do is
docker service update --container-label-add last_deployed=$(date -u +%Y-%m-%dT%H:%M:%S) service_name_or_id
I'm writing this in 2020, I hope this script will help those who wants a clean way to pull and restart a container on a stack without publishing each times a new image on a new tag !
#!/bin/bash -e
if [ $# -lt 1 ]
then
echo "this command needs the name of the container and the branch you want to use"
echo "Syntax: ./update.sh <microservice> <version>"
echo "Syntax: ./update.sh mymicroservice develop"
exit 1
fi
declare -r STACK_NAME="mystack" # this should be generated or asked to user
declare -r REPO="192.168.1.100" # this should be generated or asked to user
echo "Pull the image ${REPO}/${1}:${2}"
# Pull latest image on the swarm master
docker pull ${REPO}/${1}:${2}
# Get the ID of that image
declare -r imageSha256=`docker image inspect --format '{{ .Id }}' ${REPO}/${1}:${2}`
declare -r image="${REPO}/${1}@${imageSha256}"
# Update the server and the image used
docker service update --image ${image} ${STACK_NAME}_${1}
echo "Update succeeded !"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With