Repository: containrrr/watchtower (go)

Issue:
--notification-email-delay is ignored
<!--
  Before submitting your issue, please make sure you're using the containrrr/watchtower:latest image.
  If not, switch to this image prior to posting your report. Other forks, or the old `v2tec` image are **not** supported.
-->

**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
It seems, that the variable `--notification-email-delay` (or the environment variable `WATCHTOWER_NOTIFICATION_EMAIL_DELAY`) is ignored and the email is send immediately after finishing the update process of all containers.
This is a problem, when the mail service itself is a docker service and updated by watchtower and not yet ready to receive the email from watchtower.
**To Reproduce**
<!--

Steps to reproduce the behaviour:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
1. Create a docker-compose file like:
```
version: "3"
services:
  watchtower:
    container_name: watchtower
    restart: unless-stopped
    image: containrrr/watchtower
    network_mode: bridge
    environment:
      - WATCHTOWER_MONITOR_ONLY=false
      - WATCHTOWER_SCHEDULE=@midnight
      - WATCHTOWER_NOTIFICATIONS=email
      - WATCHTOWER_NOTIFICATION_EMAIL_FROM=${WATCHTOWER_NOTIFICATION_EMAIL_FROM}
      - WATCHTOWER_NOTIFICATION_EMAIL_TO=${WATCHTOWER_NOTIFICATION_EMAIL_TO}
      - WATCHTOWER_NOTIFICATION_EMAIL_SERVER=${WATCHTOWER_NOTIFICATION_EMAIL_SERVER}
      - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=${WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT}
      - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=${WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER}
      - WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=${WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD}
      - WATCHTOWER_NOTIFICATION_EMAIL_SUBJECTTAG=${WATCHTOWER_NOTIFICATION_EMAIL_SUBJECTTAG}
      - WATCHTOWER_NOTIFICATION_EMAIL_DELAY=300
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
```
and fill the variables with correct data
2. Wait until watchtower starts at midnight and new container are available for updates
3. Email will be send immediately

**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
After updating the container(s) the email notification should not be sent before 00:05 a.m. (300s = 5 minutes)

**Screenshots**
![image](https://user-images.githubusercontent.com/86572636/141684909-a7406349-2005-4ea7-889d-85472de954d3.png)

<!--
If applicable, add screenshots to help explain your problem.
-->
**Environment**
<!-- 
We want to know:
 - Platform
 - Architecture
 - Docker version
-->
 - Platform: `Debian Bullseye (Linux 5.10.17-v8+)`
 - Architecture: `aarch64 (Raspberry Pi)`
 - Docker version: `Docker version 20.10.9, build c2ea9bc` 
<details>
 <summary><b> Logs from running watchtower with the <code>--debug</code> option </b></summary>

```
time="2021-07-09T00:02:34+02:00" level=info msg="Stopping /transmission (46be36e8777b) with SIGTERM",
time="2021-07-09T00:02:40+02:00" level=debug msg="Removing container 46be36e8777b",
time="2021-07-09T00:02:40+02:00" level=info msg="Stopping /mailu_front (58e4eba0d0d0) with SIGTERM",
time="2021-07-09T00:02:41+02:00" level=debug msg="Removing container 58e4eba0d0d0",
time="2021-07-09T00:02:41+02:00" level=info msg="Stopping /mailu_antispam (b3c140ff1c32) with SIGTERM",
time="2021-07-09T00:02:43+02:00" level=debug msg="Removing container b3c140ff1c32",
time="2021-07-09T00:02:43+02:00" level=info msg="Stopping /mailu_imap (0f51d8382e21) with SIGTERM",
time="2021-07-09T00:02:45+02:00" level=debug msg="Removing container 0f51d8382e21",
time="2021-07-09T00:02:45+02:00" level=info msg="Stopping /mailu_certdump (a10c7d16f5ee) with SIGTERM",
time="2021-07-09T00:02:55+02:00" level=debug msg="Removing container a10c7d16f5ee",
time="2021-07-09T00:02:55+02:00" level=info msg="Stopping /mailu_admin (26f10f8be6b9) with SIGTERM",
time="2021-07-09T00:03:05+02:00" level=debug msg="Removing container 26f10f8be6b9",
time="2021-07-09T00:03:06+02:00" level=info msg="Stopping /mailu_smtp (c81b2aef50dc) with SIGTERM",
time="2021-07-09T00:03:16+02:00" level=debug msg="Removing container c81b2aef50dc",
time="2021-07-09T00:03:17+02:00" level=info msg="Stopping /mailu_webmail (f8fa8547a5cb) with SIGTERM",
time="2021-07-09T00:03:27+02:00" level=debug msg="Removing container f8fa8547a5cb",
time="2021-07-09T00:03:27+02:00" level=debug msg="This is the watchtower container /watchtower",
time="2021-07-09T00:03:27+02:00" level=info msg="Creating /mailu_webmail",
time="2021-07-09T00:03:27+02:00" level=debug msg="Starting container /mailu_webmail (e5eb7b049e89)",
time="2021-07-09T00:03:29+02:00" level=info msg="Creating /mailu_smtp",
time="2021-07-09T00:03:29+02:00" level=debug msg="Starting container /mailu_smtp (a5648d79fdd1)",
time="2021-07-09T00:03:31+02:00" level=info msg="Creating /mailu_admin",
time="2021-07-09T00:03:31+02:00" level=debug msg="Starting container /mailu_admin (38dba7459fa3)",
time="2021-07-09T00:03:32+02:00" level=info msg="Creating /mailu_certdump",
time="2021-07-09T00:03:33+02:00" level=debug msg="Starting container /mailu_certdump (1f4f5879181f)",
time="2021-07-09T00:03:34+02:00" level=info msg="Creating /mailu_imap",
time="2021-07-09T00:03:35+02:00" level=debug msg="Starting container /mailu_imap (ce089a49b1a3)",
time="2021-07-09T00:03:37+02:00" level=info msg="Creating /mailu_antispam",
time="2021-07-09T00:03:37+02:00" level=debug msg="Starting container /mailu_antispam (17e890c90a3d)",
time="2021-07-09T00:03:39+02:00" level=info msg="Creating /mailu_front",
time="2021-07-09T00:03:39+02:00" level=debug msg="Starting container /mailu_front (fee1acb8f96b)",
time="2021-07-09T00:03:41+02:00" level=info msg="Creating /transmission",
time="2021-07-09T00:03:42+02:00" level=debug msg="Starting container /transmission (5bdca098870e)",
time="2021-07-09T00:03:45+02:00" level=debug msg="Session done: 44 scanned, 8 updated, 0 failed",
time="2021-07-09T00:03:45+02:00" level=debug msg="Scheduled next run: 2021-07-10 00:00:00 +0200 CEST",
Failed to send notification via shoutrrr (url=smtp://<smtp-server>:465/?auth=Plain&fromaddress=<fromaddress>&fromname=Watchtower&subject=%5BWatchtower%5D+Watchtower+updates+on+6a3a2a6b90e9&toaddresses=<toaddresses>):  failed to send using smtp: timed out,
Failed to send notification via shoutrrr (url=smtp://<smtp-server>:465/?auth=Plain&fromaddress=<fromaddress>&fromname=Watchtower&subject=%5BWatchtower%5D+Watchtower+updates+on+6a3a2a6b90e9&toaddresses=<toaddresses>):  failed to send using smtp: timed out,
Failed to send notification via shoutrrr (url=smtp://<smtp-server>:465/?auth=Plain&fromaddress=<fromaddress>&fromname=Watchtower&subject=%5BWatchtower%5D+Watchtower+updates+on+6a3a2a6b90e9&toaddresses=<toaddresses>):  failed to send using smtp: timed out
```

</details>

**Additional context**
<!--
  Add any other context about the problem here.
-->
The logs are a little bit old, but the bug exists from beginning and i logged the debug output in July.
Container beginning with "mailu" are updated and mailu is the mail service that should receive the message from watchtower.
After finishing watchtower tries to send the mail (i removed the real address from the log), but since the containers are not ready yet the notification is failing.

Pull request description:
feat(notifications): support delayed sending
Fixes #1135 

<!--

Thank you for contributing to the watchtower project! 🙏

We truly appreciate all the contributions we get from the community.

To make your PR experience as smooth as possible, make sure that you
include the following in your PR:

- What your PR contributes
- Which issues it solves (preferrably using auto closing instructions like "closes #123".
- Tests that verify the code your contributing
- Updates to the documentation

Thank you again! ✨

-->


Patch:
diff --git a/cmd/root.go b/cmd/root.go
index ff1cac3..1be52a8 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -191,6 +191,11 @@ func Run(c *cobra.Command, names []string) {
 	if enableUpdateAPI {
 		updateHandler := update.New(func() { runUpdatesWithNotifications(filter) }, updateLock)
 		httpAPI.RegisterFunc(updateHandler.Path, updateHandler.Handle)
+		// If polling isn't enabled the scheduler is never started and
+		// we need to trigger the startup messages manually.
+		if !unblockHTTPAPI {
+			writeStartupMessage(c, time.Time{}, filterDesc)
+		}
 	}
 
 	if enableMetricsAPI {
@@ -261,6 +266,7 @@ func formatDuration(d time.Duration) string {
 
 func writeStartupMessage(c *cobra.Command, sched time.Time, filtering string) {
 	noStartupMessage, _ := c.PersistentFlags().GetBool("no-startup-message")
+	enableUpdateAPI, _ := c.PersistentFlags().GetBool("http-api-update")
 
 	var startupLog *log.Entry
 	if noStartupMessage {
@@ -286,8 +292,15 @@ func writeStartupMessage(c *cobra.Command, sched time.Time, filtering string) {
 		until := formatDuration(time.Until(sched))
 		startupLog.Info("Scheduling first run: " + sched.Format("2006-01-02 15:04:05 -0700 MST"))
 		startupLog.Info("Note that the first check will be performed in " + until)
+	} else if runOnce, _ := c.PersistentFlags().GetBool("run-once"); runOnce {
+			startupLog.Info("Running a one time update.")
 	} else {
-		startupLog.Info("Running a one time update.")
+		startupLog.Info("Periodic runs are not enabled.")
+	}
+
+	if enableUpdateAPI {
+		// TODO: make listen port configurable
+		startupLog.Info("The HTTP API is enabled at :8080.")
 	}
 
 	if !noStartupMessage {
diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile
index 345f5c2..c3ed14b 100644
--- a/dockerfiles/Dockerfile
+++ b/dockerfiles/Dockerfile
@@ -1,4 +1,4 @@
-FROM --platform=$BUILDPLATFORM alpine:3.11 as alpine
+FROM --platform=$BUILDPLATFORM alpine:3.15 as alpine
 
 RUN apk add --no-cache \
     ca-certificates \
diff --git a/docs/arguments.md b/docs/arguments.md
index f08be7a..c2d4521 100644
--- a/docs/arguments.md
+++ b/docs/arguments.md
@@ -237,7 +237,7 @@ Environment Variable: WATCHTOWER_RUN_ONCE
 
 ## HTTP API Mode
 Runs Watchtower in HTTP API mode, only allowing image updates to be triggered by an HTTP request. 
-For details see [HTTP API](https://containrrr.github.io/watchtower/http-api-mode).
+For details see [HTTP API](https://containrrr.dev/watchtower/http-api-mode).
 
 ```text
             Argument: --http-api-update
@@ -268,7 +268,7 @@ Environment Variable: WATCHTOWER_HTTP_API_PERIODIC_POLLS
 
 ## Filter by scope
 Update containers that have a `com.centurylinklabs.watchtower.scope` label set with the same value as the given argument. 
-This enables [running multiple instances](https://containrrr.github.io/watchtower/running-multiple-instances).
+This enables [running multiple instances](https://containrrr.dev/watchtower/running-multiple-instances).
 
 ```text
             Argument: --scope
diff --git a/docs/index.md b/docs/index.md
index ef234ec..1d0b2cc 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -45,13 +45,16 @@ and restart it with the same options that were used when it was deployed initial
 the following command:
 
 === "docker run"
+
     ```bash
     $ docker run -d \
     --name watchtower \
     -v /var/run/docker.sock:/var/run/docker.sock \
     containrrr/watchtower
     ```
+
 === "docker-compose.yml"
+
     ```yaml
     version: "3"
     services:
diff --git a/docs/private-registries.md b/docs/private-registries.md
index 8b3f28d..94f9a81 100644
--- a/docs/private-registries.md
+++ b/docs/private-registries.md
@@ -25,6 +25,18 @@ password `auth` string:
 `<REGISTRY_NAME>` needs to be replaced by the name of your private registry
 (e.g., `my-private-registry.example.org`)
 
+!!! important "Using private images on docker hub"
+    When using private images on docker hub, the containers beeing watched needs to use the full image name, including the repository prefix `index.docker.io`.
+    So instead of
+    ```
+    docker run -d myuser/myimage
+    ```
+    you would run it as
+    ```
+    docker run -d index.docker.io/myuser/myimage
+    ```
+
+
 The required `auth` string can be generated as follows:
 
 ```bash
diff --git a/go.mod b/go.mod
index 00c0f8d..809a225 100644
--- a/go.mod
+++ b/go.mod
@@ -2,8 +2,11 @@ module github.com/containrrr/watchtower
 
 go 1.12
 
+// Use non-vulnerable runc (until github.com/containerd/containerd v1.6.0 is stable)
+replace github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.3
+
 require (
-	github.com/containerd/containerd v1.5.7 // indirect
+	github.com/containerd/containerd v1.5.8 // indirect
 	github.com/containrrr/shoutrrr v0.5.2
 	github.com/docker/cli v20.10.8+incompatible
 	github.com/docker/distribution v2.7.1+incompatible
diff --git a/go.sum b/go.sum
index 33e6c19..202603e 100644
--- a/go.sum
+++ b/go.sum
@@ -54,8 +54,7 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
 github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
 github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
 github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
-github.com/Microsoft/hcsshim v0.8.21 h1:btRfUDThBE5IKcvI8O8jOiIkujUsAMBSRsYDYmEi6oM=
-github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
+github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
 github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
 github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@@ -79,7 +78,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
-github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
 github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
 github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
@@ -89,12 +87,12 @@ github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7
 github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
 github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
 github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
+github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
 github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
 github.com/chromedp/cdproto v0.0.0-20190614062957-d6d2f92b486d/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw=
 github.com/chromedp/cdproto v0.0.0-20190621002710-8cbd498dd7a0/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw=
@@ -126,7 +124,6 @@ github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1
 github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
 github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
 github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
-github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ=
 github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
 github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
 github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
@@ -141,27 +138,25 @@ github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX
 github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
 github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
 github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
 github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
 github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
 github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
 github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
-github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
-github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM=
-github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
+github.com/containerd/containerd v1.5.8 h1:NmkCC1/QxyZFBny8JogwLpOy2f+VEbO/f6bV2Mqtwuw=
+github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
 github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
 github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
 github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
 github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo=
 github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
 github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
-github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8=
 github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
 github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
 github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
 github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
 github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
 github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
-github.com/containerd/fifo v1.0.0 h1:6PirWBr9/L7GDamKr+XM0IeUFXu5mf3M/BPpH9gaLBU=
 github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
 github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU=
 github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk=
@@ -181,12 +176,11 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG
 github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
 github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
 github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
-github.com/containerd/ttrpc v1.0.2 h1:2/O3oTZN36q2xRolk0a2WWGgh7/Vf/liElg5hFYLX9U=
 github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
 github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
 github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
 github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
-github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY=
 github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
 github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
 github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
@@ -250,7 +244,6 @@ github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avu
 github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
 github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
 github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
 github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
 github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
@@ -318,7 +311,6 @@ github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6
 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
-github.com/gogo/googleapis v1.4.0 h1:zgVt4UpGxcqVOw97aRGxT4svlcmdK35fynLNctY32zI=
 github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@@ -332,7 +324,6 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -381,7 +372,6 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
 github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@@ -444,7 +434,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
 github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4=
 github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -491,10 +480,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
 github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
 github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
-github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
 github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
 github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
-github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM=
 github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
 github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
 github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
@@ -544,24 +531,16 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I
 github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
 github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
-github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg=
-github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
+github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
 github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
 github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
 github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
 github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
-github.com/opencontainers/selinux v1.8.2 h1:c4ca10UMgRcvZ6h0K4HtS15UaVSBEaE+iln2LVpAuGc=
 github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
@@ -713,7 +692,6 @@ go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvS
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -813,7 +791,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1010,8 +987,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/mkdocs.yml b/mkdocs.yml
index 46a941c..57b2f7b 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -23,7 +23,8 @@ markdown_extensions:
         user: containrrr
         repo: watchtower
     - pymdownx.saneheaders
-    - pymdownx.tabbed
+    - pymdownx.tabbed:
+        alternate_style: true 
 nav:
    - 'Home': 'index.md'
    - 'Introduction': 'introduction.md'
diff --git a/pkg/api/api.go b/pkg/api/api.go
index 756db90..d0c4a95 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -62,7 +62,6 @@ func (api *API) Start(block bool) error {
 		log.Fatal(tokenMissingMsg)
 	}
 
-	log.Info("Watchtower HTTP API started.")
 	if block {
 		runHTTPServer()
 	} else {
@@ -74,6 +73,5 @@ func (api *API) Start(block bool) error {
 }
 
 func runHTTPServer() {
-	log.Info("Serving HTTP")
 	log.Fatal(http.ListenAndServe(":8080", nil))
 }
diff --git a/pkg/notifications/email.go b/pkg/notifications/email.go
index 6a61dd1..2b1b85a 100644
--- a/pkg/notifications/email.go
+++ b/pkg/notifications/email.go
@@ -82,6 +82,10 @@ func (e *emailTypeNotifier) GetURL(c *cobra.Command) (string, error) {
 	return conf.GetURL().String(), nil
 }
 
+func (e *emailTypeNotifier) GetDelay() time.Duration {
+	return e.delay
+}
+
 func (e *emailTypeNotifier) getSubject(c *cobra.Command) string {
 	subject := GetTitle(c)
 
diff --git a/pkg/notifications/notifier.go b/pkg/notifications/notifier.go
index 7c999d0..5bfa08c 100644
--- a/pkg/notifications/notifier.go
+++ b/pkg/notifications/notifier.go
@@ -1,11 +1,13 @@
 package notifications
 
 import (
+	"os"
+	"time"
+
 	ty "github.com/containrrr/watchtower/pkg/types"
 	"github.com/johntdyer/slackrus"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
-	"os"
 )
 
 // NewNotifier creates and returns a new Notifier, using global configuration.
@@ -28,14 +30,14 @@ func NewNotifier(c *cobra.Command) ty.Notifier {
 	tplString, _ := f.GetString("notification-template")
 	urls, _ := f.GetStringArray("notification-url")
 
-	urls = AppendLegacyUrls(urls, c)
+	urls, delay := AppendLegacyUrls(urls, c)
 
 	title := GetTitle(c)
-	return newShoutrrrNotifier(tplString, acceptedLogLevels, !reportTemplate, title, urls...)
+	return newShoutrrrNotifier(tplString, acceptedLogLevels, !reportTemplate, title, delay, urls...)
 }
 
 // AppendLegacyUrls creates shoutrrr equivalent URLs from legacy notification flags
-func AppendLegacyUrls(urls []string, cmd *cobra.Command) []string {
+func AppendLegacyUrls(urls []string, cmd *cobra.Command) ([]string, time.Duration) {
 
 	// Parse types and create notifiers.
 	types, err := cmd.Flags().GetStringSlice("notifications")
@@ -43,6 +45,8 @@ func AppendLegacyUrls(urls []string, cmd *cobra.Command) []string {
 		log.WithError(err).Fatal("could not read notifications argument")
 	}
 
+	delay := time.Duration(0)
+
 	for _, t := range types {
 
 		var legacyNotifier ty.ConvertibleNotifier
@@ -71,9 +75,13 @@ func AppendLegacyUrls(urls []string, cmd *cobra.Command) []string {
 		}
 		urls = append(urls, shoutrrrURL)
 
+		if delayNotifier, ok := legacyNotifier.(ty.DelayNotifier); ok {
+			delay = delayNotifier.GetDelay()
+		}
+
 		log.WithField("URL", shoutrrrURL).Trace("created Shoutrrr URL from legacy notifier")
 	}
-	return urls
+	return urls, delay
 }
 
 // GetTitle returns a common notification title with hostname appended
diff --git a/pkg/notifications/shoutrrr.go b/pkg/notifications/shoutrrr.go
index 1611a04..e41ed92 100644
--- a/pkg/notifications/shoutrrr.go
+++ b/pkg/notifications/shoutrrr.go
@@ -5,6 +5,7 @@ import (
 	stdlog "log"
 	"strings"
 	"text/template"
+	"time"
 
 	"github.com/containrrr/shoutrrr"
 	"github.com/containrrr/shoutrrr/pkg/types"
@@ -77,14 +78,14 @@ func (n *shoutrrrTypeNotifier) GetNames() []string {
 	return names
 }
 
-func newShoutrrrNotifier(tplString string, acceptedLogLevels []log.Level, legacy bool, title string, urls ...string) t.Notifier {
+func newShoutrrrNotifier(tplString string, acceptedLogLevels []log.Level, legacy bool, title string, delay time.Duration, urls ...string) t.Notifier {
 
 	notifier := createNotifier(urls, acceptedLogLevels, tplString, legacy)
 	notifier.params = &types.Params{"title": title}
 	log.AddHook(notifier)
 
 	// Do the sending in a separate goroutine so we don't block the main process.
-	go sendNotifications(notifier)
+	go sendNotifications(notifier, delay)
 
 	return notifier
 }
@@ -112,8 +113,9 @@ func createNotifier(urls []string, levels []log.Level, tplString string, legacy
 	}
 }
 
-func sendNotifications(n *shoutrrrTypeNotifier) {
+func sendNotifications(n *shoutrrrTypeNotifier, delay time.Duration) {
 	for msg := range n.messages {
+		time.Sleep(delay)
 		errs := n.Router.Send(msg, n.params)
 
 		for i, err := range errs {
diff --git a/pkg/types/convertible_notifier.go b/pkg/types/convertible_notifier.go
index 87f8659..90f0078 100644
--- a/pkg/types/convertible_notifier.go
+++ b/pkg/types/convertible_notifier.go
@@ -1,8 +1,16 @@
 package types
 
-import "github.com/spf13/cobra"
+import (
+	"github.com/spf13/cobra"
+	"time"
+)
 
 // ConvertibleNotifier is a notifier capable of creating a shoutrrr URL
 type ConvertibleNotifier interface {
 	GetURL(c *cobra.Command) (string, error)
 }
+
+// DelayNotifier is a notifier that might need to be delayed before sending notifications
+type DelayNotifier interface {
+	GetDelay() time.Duration
+}
\ No newline at end of file


Test patch:
diff --git a/pkg/notifications/notifier_test.go b/pkg/notifications/notifier_test.go
index 71bfea3..05d6d56 100644
--- a/pkg/notifications/notifier_test.go
+++ b/pkg/notifications/notifier_test.go
@@ -241,7 +241,7 @@ func testURL(args []string, expectedURL string) {
 	err := command.ParseFlags(args)
 	Expect(err).NotTo(HaveOccurred())
 
-	urls := notifications.AppendLegacyUrls([]string{}, command)
+	urls, _ := notifications.AppendLegacyUrls([]string{}, command)
 
 	Expect(err).NotTo(HaveOccurred())
 
diff --git a/pkg/notifications/shoutrrr_test.go b/pkg/notifications/shoutrrr_test.go
index 1b4ebab..6e67b6f 100644
--- a/pkg/notifications/shoutrrr_test.go
+++ b/pkg/notifications/shoutrrr_test.go
@@ -1,6 +1,8 @@
 package notifications
 
 import (
+	"time"
+
 	"github.com/containrrr/shoutrrr/pkg/types"
 	"github.com/containrrr/watchtower/internal/actions/mocks"
 	"github.com/containrrr/watchtower/internal/flags"
@@ -212,7 +214,7 @@ Turns out everything is on fire
 	When("batching notifications", func() {
 		When("no messages are queued", func() {
 			It("should not send any notification", func() {
-				shoutrrr := newShoutrrrNotifier("", allButTrace, true, "", "logger://")
+				shoutrrr := newShoutrrrNotifier("", allButTrace, true, "", time.Duration(0), "logger://")
 				shoutrrr.StartNotification()
 				shoutrrr.SendNotification(nil)
 				Consistently(logBuffer).ShouldNot(gbytes.Say(`Shoutrrr:`))
@@ -220,7 +222,7 @@ Turns out everything is on fire
 		})
 		When("at least one message is queued", func() {
 			It("should send a notification", func() {
-				shoutrrr := newShoutrrrNotifier("", allButTrace, true, "", "logger://")
+				shoutrrr := newShoutrrrNotifier("", allButTrace, true, "", time.Duration(0), "logger://")
 				shoutrrr.StartNotification()
 				logrus.Info("This log message is sponsored by ContainrrrVPN")
 				shoutrrr.SendNotification(nil)
@@ -282,7 +284,7 @@ func sendNotificationsWithBlockingRouter(legacy bool) (*shoutrrrTypeNotifier, *b
 		Message: "foo bar",
 	}
 
-	go sendNotifications(shoutrrr)
+	go sendNotifications(shoutrrr, time.Duration(0))
 
 	shoutrrr.StartNotification()
 	_ = shoutrrr.Fire(entry)