Docker swarm service for automatically updating your services whenever their image is refreshed
Shepherd
A Docker swarm service for automatically updating your services whenever their base image is refreshed.
Usage
-script
docker service create --name shepherd \
--constraint "node.role==manager" \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock,ro \
containrrr/shepherd
Or with Docker Compose
version: "3"
services:
...
shepherd:
build: .
image: containrrr/shepherd
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
placement:
constraints:
- node.role == manager
See the example docker-compose.yml and some more compose configs in the examples folder.
Configuration
Shepherd will try to update your services every 5 minutes by default. You can adjust this value using the SLEEP_TIME variable.
You can prevent services from being updated by appending them to the IGNORELIST_SERVICES variable. This should be a space-separated list of service names.
Alternatively you can specify a filter for the services you want updated using the FILTER_SERVICES variable. This can be anything accepted by the filtering flag in docker service ls.
You can set Shepherd to roll back a service to the previous version if the update fails by setting the ROLLBACKONFAILURE variable.
You can control additional parameters for the docker service update and docker service update --rollback calls using the variables UPDATEOPTIONS and ROLLBACKOPTIONS.
If the docker service update takes too long then it will be killed after 5 minutes by default. You can adjust this value using the TIMEOUT variable.
You can enable private registry authentication by setting the WITHREGISTRYAUTH variable.
If you need to authenticate to a registry (for example in order to get around the Docker Hub rate limits), you can set the variable REGISTRYUSER and store the password either in a docker secret named shepherdregistrypassword or in the environment variable REGISTRYPASSWORD. If you are not using Docker Hub but a private registry, set REGISTRY_HOST to the hostname of your registry.
It is also possible to put all authentication information in a secret file. This approach is required if you need to authenticate with multiple accounts to the same registry (eg authenticate to the Gitlab registry for images from different projects). The content of the file is <TAB> separated and has 4 columns:
- id: an identifier for the account. This should be an acceptable Docker config name.
- registry: the registry to authenticate against, eg
registry.gitlab.com - login: the user to authenticate as
- password: the password to authenticate with
# are comments, and are ignored, as are invalid lines. Make sure this file ends with a new line. Otherwise your last line in the file will be ignored (here is why). Here is an example: blog registry.gitlab.com gitlab+deploy-token-5123674 ssw2Nrd2 Create and edit that file locally, eg at the location private/shepherd-registries-auth, and create the docker secret with docker secret create shepherd-registries-auth private/shepherd-registries-auth You need to make the secret available to shepherd with the secrets key, and pass the secret file to the REGISTRIES_FILE variable: services: app: image: containrrr/shepherd environment: REGISTRIES_FILE: /var/run/secrets/shepherd-registries-auth secrets: - shepherd-registries-auth secrets: shepherd-registries-auth: external: true You also need to add a label shepherd.auth.config to the container to be updated specifying which line of the secret file should be used. The value of that label should be the id in the secret file:
deploy:
labels:
- shepherd.enable=true
- shepherd.auth.config=blog
You can enable connection to insecure private registry by setting the WITHINSECUREREGISTRY variable to true.
You can prevent pulling images from the registry by setting the WITHNORESOLVE_IMAGE variable to true.
You can enable notifications on service update with apprise, using the apprise microservice and the APPRISESIDECARURL variable. See the file docker-compose.apprise.yml for an example.
You can enable old image autocleaning on service update by setting the IMAGEAUTOCLEANLIMIT variable.
You can enable one shot running with RUNONCEAND_EXIT variable.
If you care about log entries having the right timezone, you can set the TZ variable to the correct value (make sure to not include quotation marks in the variable value).
Example:
-script
docker service create --name shepherd \
--constraint "node.role==manager" \
--env SLEEP_TIME="5m" \
--env IGNORELIST_SERVICES="shepherd my-other-service" \
--env WITHREGISTRYAUTH="true" \
--env WITHINSECUREREGISTRY="true" \
--env WITHNORESOLVE_IMAGE="true" \
--env FILTER_SERVICES="label=com.mydomain.autodeploy" \
--env APPRISESIDECARURL="apprise-microservice:5000" \
--env IMAGEAUTOCLEANLIMIT="5" \
--env RUN_ \
--env ROLLBACK_ \
--env UPDATE_OPTI \
--env TZ=Europe/Berlin \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock,ro \
--mount type=bind,source=/root/.docker/config.json,target=/root/.docker/config.json,ro \
containrrr/shepherd
Note that the quotes in the command above are evaluated by your shell and are not part of the environment variable value! - See also the note in docker-compose.yml!
Running on a cron schedule
When running shepherd as described with a SLEEPTIME, the de facto running times will drift the longer the container is running. If you want to run shepherd on a fixed schedule instead, it is recommended to pair it with swarm-cronjob:
- Create a swarm-cronjob service as described in its documentation.
- Set
RUNONCEANDEXITtotrue,replicasto0andrestartpolicytocondition: none. Add docker labels for the schedule.
How does it work?
Shepherd just triggers updates by updating the image specification for each service, removing the current digest.
Most of the work is thankfully done by Docker which resolves the image tag, checks the registry for a newer version and updates running container tasks as needed.
Also, Docker handles all the work of applying rolling updates. So at least with replicated services, there should be no noticeable downtime.