diff --git a/v3.1.0/404.html b/v3.1.0/404.html new file mode 100644 index 0000000..4205446 --- /dev/null +++ b/v3.1.0/404.html @@ -0,0 +1,650 @@ + + + +
+ + + + + + + + + + + + + + +As with every other aspect, Dolce comes with great default templates that are tailored specifically for each notifier. +If you however want to customize the look or contents of the default, Dolce provides you with an easy way to override +the templates that are used to generate the notifications.
+When rendering a message, Dolce first checks if the template file exists inside DOLCE_CUSTOM_TEMPLATE_PATH
. Only if
+this lookup fails the default template gets used, so to override the template for one or more notifier, create the
+following file:
./templates/<notifier>/<eventtype>.eta
+
where
+<notifier>
is one of the built-in notifiers (smtp
| discord
| telegram
| apprise
) and<eventtype>
is either event
| reboot
depending on which notification you want to customise. The mount this folder to where DOLCE_CUSTOM_TEMPLATE_PATH
+points (by default this will be /var/dolce-custom-templates/
):
services:
+ dolce:
+ image: dangrie158/dolce:v3.1.0
+ restart: unless-stopped
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ - ./templates:/var/dolce-custom-templates # (1)!
+ environment:
+ ...
+
DOLCE_CUSTOM_TEMPLATE_PATH
to any other value.As you can probably guess from the file extension, Dolce uses Eta as a templating engine to render +the notification bodies so you can leverage the full power of JavaScript to generate the massge of you so choose.
+Additionally some notifiers use the templates frontmatter in JSON format to +specify additional attributes (e.g. EMail subject for SMTP notifier).
+It is probably a good idea to to look at the +default templates to get a starting point and work from +there.
+Each template has access to a context object it
that is populated with information that can be used inside the
+template.
Every template context contains the following global properties:
+Name | +Type | +Description | +
---|---|---|
hostname |
+string |
+Hostname of the machine running Dolce | +
newest_first |
+(DockerContainerEvent, DockerContainerEvent): number |
+See newest_first |
+
get_event_class |
+(DockerContainerEvent): string |
+See get_event_class | +
get_event_symbol |
+(DockerContainerEvent): string |
+See get_event_symbol | +
For event
templates the context additionally contains the following properties:
Name | +Type | +Description | +
---|---|---|
events |
+DockerContainerEvent[] 1 |
+Events since the last notification | +
earliest_next_update |
+Date |
+Timestamp of the earliest next notification | +
For restart
templates the context additionally contains the following properties:
Name | +Type | +Description | +
---|---|---|
events_since_shutdown |
+DockerContainerEvent[] 1 |
+Events that happened while Dolce was not running | +
downtime_start |
+Date |
+Latest known timestamp where Dolce was still running | +
downtime_end |
+Date |
+Timestamp at which Dolce started again | +
newest_first
This function takes two event arguments and returns the chronological order of the events so that newer events will be
+sorted first. This function is compatible with JavaScripts Array.sort
and Array.toSorted
which makes it perfect to
+iterate over a sorted array of events like this:
<% it.events.toSorted(it.newest_first).forEach(event => { %>
+ <%= new Date(event.time * 1000).toLocaleString() %>: <%= event.Action %> <%= event.actor_name %>
+<% }); %>
+
get_event_class
This function takes an event and returns one of success
| warning
| error
depending on the event action. This is
+used to color the events in the default templates and can thus be used is custom templates to keep the same
+categorization that is used in the default templates:
event.Action |
+Class | +
---|---|
start |
+success |
+
die |
+error |
+
kill |
+error |
+
oom |
+error |
+
stop |
+warning |
+
pause |
+warning |
+
unpause |
+success |
+
health_status |
+warning |
+
Example usage:
+<span class="<%= it.get_event_class(event) %>"><%= event.Action %></span>
+
get_event_symbol
This function takes an event an returns a single UTF-8 glyph that can be used to represent the event based on the event +action:
+event.Action |
+Symbol | +
---|---|
start |
+✅ | +
die |
+❌ | +
kill |
+❌ | +
oom |
+❌ | +
stop |
+⏹️ | +
pause |
+⏸️ | +
unpause |
+⏯️ | +
health_status |
+❓ | +
Example usage:
+<%= event.actor_name %>: <%= it.get_event_symbol(event) %><%= event.Action %>
+
Name | +Type | +Default | +Description | +
---|---|---|---|
DOLCE_MIN_TIMEOUT |
+number |
+10 |
+Minimum number of seconds between notifications | +
DOLCE_MAX_TIMEOUT |
+number |
+60*60*24 (1 day) |
+Maximum number of seconds between notifications | +
DOLCE_MULTIPLIER |
+number |
+10 |
+Multiplier to increase the timeout with each message | +
The delay between notifications is calculated as $delay(n) = min(m * f ^ n, M)$ where $n$ is the current iteration of +the backoff algorithm.
+If you assume you have a container that has a problem and repeatetly restarts every second starting $t=0$, you will +receive the following notifications with the default settings
+$n$ | +$delay$ | ++ | $t$ | +$t_n = t_(n-1) + delay$ | +
---|---|---|---|---|
1 | +$10 * 10 ^ 0$ | +10 | +$0 + delay$ | +10 | +
2 | +$10 * 10 ^ 1$ | +100 | +$10 + delay$ | +110 | +
3 | +$10 * 10 ^ 2$ | +1_000 | +$110 + delay$ | +1110 | +
4 | +$10 * 10 ^ 3$ | +10_000 | +$1110 + delay$ | +11110 | +
5 | +$60 * 60 * 24$ | +86_400 | +$11110 + delay$ | +97510 | +
6 | +$60 * 60 * 24$ | +86_400 | +$97510 + delay$ | +97510 | +
From this moment nothing changes anymore and you will receive a new message every 24h. $n$ wil be reset if the delay for
+the next notification passes and no events happen that would require a new notification. This means: if you fix the
+problem and everything is quiet for the next 24 hours and breaks again after that time, you will be notified within
+DOLCE_MIN_TIMEOUT
seconds again.
By default you need to mount the docker socket with read and write permissions. Any container with this level of +access effecively has root-priviledges on the host.
+Sadly you can't simply mount the docker socket read-only. Although dolce never changes anything that would require write +access to the docker API (e.g. creating mounts), it needs write access to send HTTP requests to the it.
+If you don't trust the prebuild images and want to err on the safe side, you can reduce the attack area by using +docker-socket-proxy and connect dolce to this proxy via TCP. This +means you only need to trust the
+++official Alpine-based HAProxy image with a small configuration file
+
which you can also use to hook up other services. Here is a sample configuration file to get you started:
+services:
+ dolce:
+ image: dangrie158/dolce:v3.1.0
+ restart: unless-stopped
+ environment:
+ DOCKER_HOST: docker-proxy:2375 # (1)!
+ DOCKER_TRANSPORT: tcp
+
+ docker-proxy:
+ image: tecnativa/docker-socket-proxy
+ environment:
+ INFO: 1 # (2)!
+ ports:
+ - 127.0.0.1:2375:2375
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+
docker-socket-proxy
container belowNotice how you don't need to mount the docker socket in the dolce
container, but only in the docker-proxy
which
+allows dolce
read-only access to a small part of the API by default.