Skip to content
/ somnus Public

A NodeJs based docker image to keep services in a Docker stack always up-to-date to their latest images.

License

Notifications You must be signed in to change notification settings

visitsb/somnus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

What is Somnus?

A NodeJs based docker image to keep services in a Docker stack always up-to-date to their latest images.

Why another docker image?

I use Docker stacks in my environment. It was becoming pretty mundane to keep checking for latest images against my services on a periodic basis. The service in my stack also had dependencies within each other, and juggling each time to decide which service comes before which was a pain during the manual update. I usually tore down my stack itself, updated the latest image tags against each service and then relaunched my stack fresh once again. Few services had to be on some specific version of an image, few could always go upto latest, and rest had a need to stick to specific tag prefixes. Not to mention, I also had to prune up any unused containers, dangling images - manually every time I went through this update process.

I came across Watchtower and did find it pretty impressive. However, it is feature-rich and has some advanced features into it that I found a little complicated to research into. Watchtower may've solved what I was after, but I decided to instead write a simple NodeJs script specific to my needs.

Here is how my script - Somnus (In Roman mythology, Somnus ("sleep") is the personification of sleep) works like this.

How does Somnus work?

Somnus uses Dockerode under the covers. Dockerode is an excellent library that simplifies working against the Docker Engine API.

  1. Invoke somnus as a standalone container like this-

    $ docker run \
       -v /var/run/docker.sock:/var/run/docker.sock:ro \
       -v ./logs:/app/logs:rw \
       -v ./somnus.yml:/app/somnus.yml:ro \
       -w /app \
       somnus:latest --config somnus.yml

    somnus.yml contains default settings to use Docker hub as well as socketPath to connect to your running Docker engine can be specified there. Please use the sample somnus.yml available in the project repo.

    Somnus currently supports the below parameters

    Options:
    -v, --version              output the current version
    -c, --config <config.yml>  path to somnus.yml config
    -d, --dry-run              if specified, just do a dry run but do not actually update anything
    -h, --help                 output usage information

    In addition, the logs folder contains the log of the entire operation done by Somnus. Any older log files over 5 days are deleted automatically. Logs within 5 days are zipped to save space. The latest log is always available at logs/somnus.log

  2. All running Docker services are listed. All services across all Docker stacks are listed.

  3. Services are parsed using Docker labels. Usually the defaults are sufficient, but if these are specified on the service as label, then that value will be used instead.

    Most likely, you'll want to use somnus.defaults.enable and somnus.defaults.order labels compared to the rest of them.

    All defaults except enable, order are specified in somnus.yml.

    Label Default Value Description
    somnus.defaults.enable true Set this label on a service to enable or disable this for Somnus to target for autoupdate.
    somnus.defaults.order 0 Determines the order in which services within a Docker stack should be updated. Somnus will update any services with same order in parallel.

    Lower numbered order is updated first then next higher order in sequence. Useful to explicitly control a bunch of related services within a stack to get updated before others in sequence.

    Somnus will wait until the updated service has achieved completed state which means the updated service is fully up and running.

    Note: All Docker Stacks are updated in parallel. order matters only within that stack.
    somnus.defaults.latest.tag latest Specify which tag represents the latest image for the service.

    This value can be partial tag such as alpine, buster used in some popular images, or it could be a few characters such as 5 for example to stick to 5x series of mysql.

    Behind the scenes the tags are matched for similarity using a Levenshtein distance using leven and then the longest match is used to determine the latest image tag to update to.

    Tip: Use --dry-run when running somuns to check if the latest tag is what you expect it to be.
    somnus.defaults.registry hub.docker.com Somnus uses the official Docker Hub for updates by default.
    somnus.defaults.version v2 Used to create the standard Docker Hub url to fetch latest tags for an image
    somnus.defaults.namespace library Default namespace for official Docker images.

    For images that use a custom namespace e.g. containous/whoamithe namespace is automatically adjusted to fetch the correct tags from that custom namespace.
    somnus.defaults.architecture amd64 Used to determine to correct image tag suitable for architecture on which current Docker Engine is running.
    somnus.defaults.os linux Used to determine the suitable OS version for the image tag.
  4. Each service is checked to see if it has a newer image tag available.

  5. If a newer image tag is available then the service is updated to use that tag. Somnus waits until the service reports completed as it's status after updating. Somnus then proceeds to the next service to update based on order.

  6. As a final step, any stopped containers, unused images are removed.

How do I install Somnus?

Once you verify that the above docker run command works for your stack, then declare somnus like any other service in your Docker stack and you're good to go.

Note: You only need to define somnus once in one of your Docker stacks, perhaps a master stack. Somnus will keep updating all services across all stacks currently deployed in your Docker engine.

  # My example service that I want to always keep up-to-date using Somnus
  mongo:
    image: mongo:4.2.1-bionic
    labels:
      # Somnus autoupdate tags.  Latest 'bionic' tags for mongo should be kept up-to-date.
      - "somnus.defaults.latest.tag=bionic"
      - "somnus.defaults.enable=true"
    command: ["mongod", "--config", "/etc/mongod.conf"]    
    ports:
     - ...
    volumes:
       - ...
    environment:
      - ...
  # Declare Somnus like any other service in your stack. Since just one global service is sufficient
  # you can specify the service placement to be `global` and restricted to a `manager` node.
  somnus:
        image: visitsb/somnus:1.0
        volumes:
           - /var/run/docker.sock:/var/run/docker.sock:ro
           - /somnus/somnus.yml:/app/somnus.yml:ro
           - /somnus/logs:/app/logs:rw
        deploy:
          mode: global
          placement:
          constraints:
            - node.role == manager
        ... 

By default, somnus.yml has a schedule to auto update once daily. You can change the schedule using a different schedule.

Restart somnus service to pick up the new schedule and somnus will happily keep all of your services up-to-date.

Any problems?

Please use Github to post your issues, suggestions. PRs are welcome too. Let Somnus save you some quality time in your Docker infrastructure.