Skip to content

Commit dbb6217

Browse files
committed
Adds health-check functionality to local image
Adds health-check script to template. Alters Dockerfile to import health-check script and adds `HEALTHCHECK` directive. Updates container documentation to explain behaviour of, and configuration options for, the health-check agent.
1 parent 131f02e commit dbb6217

File tree

3 files changed

+192
-0
lines changed

3 files changed

+192
-0
lines changed

.templates/mosquitto/Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ ENV IOTSTACK_DEFAULTS_DIR="iotstack_defaults"
1313
# copy template files to image
1414
COPY --chown=mosquitto:mosquitto ${IOTSTACK_DEFAULTS_DIR} /${IOTSTACK_DEFAULTS_DIR}
1515

16+
# copy the health-check script into place
17+
ENV HEALTHCHECK_SCRIPT "iotstack_healthcheck.sh"
18+
COPY ${HEALTHCHECK_SCRIPT} /usr/local/bin/${HEALTHCHECK_SCRIPT}
19+
20+
# define the health check
21+
HEALTHCHECK \
22+
--start-period=30s \
23+
--interval=30s \
24+
--timeout=10s \
25+
--retries=3 \
26+
CMD ${HEALTHCHECK_SCRIPT} || exit 1
27+
1628
# replace the docker entry-point script
1729
ENV IOTSTACK_ENTRY_POINT="docker-entrypoint.sh"
1830
COPY ${IOTSTACK_ENTRY_POINT} /${IOTSTACK_ENTRY_POINT}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env sh
2+
3+
# assume the following environment variables, all of which may be null
4+
# HEALTHCHECK_PORT
5+
# HEALTHCHECK_USER
6+
# HEALTHCHECK_PASSWORD
7+
# HEALTHCHECK_TOPIC
8+
9+
# set a default for the port
10+
HEALTHCHECK_PORT="${HEALTHCHECK_PORT:-1883}"
11+
12+
# strip any quotes from username and password
13+
HEALTHCHECK_USER="$(eval echo $HEALTHCHECK_USER)"
14+
HEALTHCHECK_PASSWORD="$(eval echo $HEALTHCHECK_PASSWORD)"
15+
16+
# set a default for the topic
17+
HEALTHCHECK_TOPIC="${HEALTHCHECK_TOPIC:-iotstack/mosquitto/healthcheck}"
18+
HEALTHCHECK_TOPIC="$(eval echo $HEALTHCHECK_TOPIC)"
19+
20+
# record the current date and time for the test payload
21+
PUBLISH=$(date)
22+
23+
# publish a retained message containing the timestamp
24+
mosquitto_pub \
25+
-h localhost \
26+
-p "$HEALTHCHECK_PORT" \
27+
-t "$HEALTHCHECK_TOPIC" \
28+
-m "$PUBLISH" \
29+
-u "$HEALTHCHECK_USER" \
30+
-P "$HEALTHCHECK_PASSWORD" \
31+
-r
32+
33+
# did that succeed?
34+
if [ $? -eq 0 ] ; then
35+
36+
# yes! now, subscribe to that same topic with a 2-second timeout
37+
# plus returning on the first message
38+
SUBSCRIBE=$(mosquitto_sub \
39+
-h localhost \
40+
-p "$HEALTHCHECK_PORT" \
41+
-t "$HEALTHCHECK_TOPIC" \
42+
-u "$HEALTHCHECK_USER" \
43+
-P "$HEALTHCHECK_PASSWORD" \
44+
-W 2 \
45+
-C 1 \
46+
)
47+
48+
# did the subscribe succeed?
49+
if [ $? -eq 0 ] ; then
50+
51+
# yes! do the publish and subscribe payloads compare equal?
52+
if [ "$PUBLISH" = "$SUBSCRIBE" ] ; then
53+
54+
# yes! return success
55+
exit 0
56+
57+
fi
58+
59+
fi
60+
61+
fi
62+
63+
# otherwise, return failure
64+
exit 1

docs/Containers/Mosquitto.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@ Replace «username» and «password» with appropriate values, then execute the
298298
```
299299
$ docker exec mosquitto mosquitto_passwd -b /mosquitto/pwfile/pwfile hello world
300300
```
301+
302+
Note:
303+
304+
* See also [customising health-check](#healthCheckCustom). If you are creating usernames and passwords, you may also want to create credentials for the health-check agent.
301305

302306
#### <a name="checkPasswordFile"> check password file </a>
303307

@@ -476,6 +480,118 @@ $
476480
[1]+ Terminated mosquitto_sub -v -h 127.0.0.1 -p 1883 -t "/password/test" -F "%I %t %p" -u hello -P world
477481
```
478482

483+
## <a name="healthCheck"> Container health check </a>
484+
485+
### <a name="healthCheckTheory"> theory of operation </a>
486+
487+
A script , or "agent", to assess the health of the Mosquitto container has been added to the *local image* via the *Dockerfile*. In other words, the script is specific to IOTstack.
488+
489+
The agent is invoked 30 seconds after the container starts, and every 30 seconds thereafter. The agent:
490+
491+
* Publishes a retained MQTT message to the broker running in the same container. The message payload is the current date and time, and the default topic string is:
492+
493+
```
494+
iotstack/mosquitto/healthcheck
495+
```
496+
497+
* Subscribes to the same broker for the same topic for a single message event.
498+
* Compares the payload sent with the payload received. If the payloads (ie time-stamps) match, the agent concludes that the Mosquitto broker (the process running inside the same container) is functioning properly for round-trip messaging.
499+
500+
### <a name="healthCheckMonitor"> monitoring health-check </a>
501+
502+
Portainer's *Containers* display contains a *Status* column which shows health-check results for all containers that support the feature.
503+
504+
You can also use the `docker ps` command to monitor health-check results. The following command narrows the focus to mosquitto:
505+
506+
```bash
507+
$ docker ps --format "table {{.Names}}\t{{.Status}}" --filter name=mosquitto
508+
```
509+
510+
Possible reply patterns are:
511+
512+
1. The container is starting and has not yet run the health-check agent:
513+
514+
```
515+
NAMES STATUS
516+
mosquitto Up 3 seconds (health: starting)
517+
```
518+
519+
2. The container has been running for at least 30 seconds and the health-check agent has returned a positive result within the last 30 seconds:
520+
521+
```
522+
NAMES STATUS
523+
mosquitto Up 34 seconds (healthy)
524+
```
525+
526+
3. The container has been running for more than 90 seconds but has failed the last three successive health-check tests:
527+
528+
```
529+
NAMES STATUS
530+
mosquitto Up About a minute (unhealthy)
531+
```
532+
533+
You can also subscribe to the same topic that the health-check agent is using to view the retained messages as they are published:
534+
535+
```bash
536+
$ mosquitto_sub -v -h localhost -p 1883 -t "iotstack/mosquitto/healthcheck" -F "%I %t %p"
537+
```
538+
539+
Notes:
540+
541+
* This assumes you are running the command *outside* container-space on the *same* host as your Mosquitto container. If you run this command from *another* host, replace `localhost` with the IP address or domain name of the host where your Mosquitto container is running.
542+
* The `-p 1883` is the *external* port. You will need to adjust this if you are using a different *external* port for your MQTT service.
543+
* If you enable authentication for your Mosquitto broker, you will need to add `-u «user»` and `-P «password»` parameters to this command.
544+
* You should expect to see a new message appear approximately every 30 seconds. That indicates the health-check agent is functioning normally. Use <kbd>control</kbd>+<kbd>c</kbd> to terminate the command.
545+
546+
### <a name="healthCheckCustom"> customising health-check </a>
547+
548+
You can customise the operation of the health-check agent by editing the `mosquitto` service definition in your *Compose* file:
549+
550+
1. By default, the mosquitto broker listens to **internal** port 1883. If you need change that port, you also need to inform the health-check agent via an environment variable. For example, suppose you changed the **internal** port to 12345:
551+
552+
```yaml
553+
environment:
554+
- HEALTHCHECK_PORT=12345
555+
```
556+
557+
2. If the default topic string used by the health-check agent causes a name-space collision, you can override it. For example, you could use a Universally-Unique Identifier (UUID):
558+
559+
```yaml
560+
environment:
561+
- HEALTHCHECK_TOPIC=4DAA361F-288C-45D5-9540-F1275BDCAF02
562+
```
563+
564+
Note:
565+
566+
* You will also need to use the same topic string in the `mosquitto_sub` command shown at [monitoring health-check](#healthCheckMonitor).
567+
568+
3. If you have enabled authentication for your Mosquitto broker service, you will need to provide appropriate credentials for your health-check agent:
569+
570+
```yaml
571+
environment:
572+
- HEALTHCHECK_USER=healthyUser
573+
- HEALTHCHECK_PASSWORD=healthyUserPassword
574+
```
575+
576+
4. If the health-check agent misbehaves in your environment, or if you simply don't want it to be active, you can disable all health-checking for the container by adding the following lines to its service definition:
577+
578+
```yaml
579+
healthcheck:
580+
disable: true
581+
```
582+
583+
Notes:
584+
585+
* The directives to disable health-checking are independent of the environment variables. If you want to disable health-checking temporarily, there is no need to remove any `HEALTHCHECK_` environment variables that may already be in place.
586+
* Conversely, the mere presence of a `healthcheck:` clause in the `mosquitto` service definition overrides the supplied agent. In other words, the following can't be used to re-enable the supplied agent:
587+
588+
```yaml
589+
healthcheck:
590+
disable: false
591+
```
592+
593+
You must remove the entire `healthcheck:` clause.
594+
479595
## <a name="upgradingMosquitto"> Upgrading Mosquitto </a>
480596

481597
You can update most containers like this:

0 commit comments

Comments
 (0)