Skip to content

Commit

Permalink
Implement Health checks (#178)
Browse files Browse the repository at this point in the history
* add healthchecks to moonraker, klipper and ustreamer images
  • Loading branch information
mkuf committed Nov 12, 2024
1 parent f3ba780 commit 9ef0e9d
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Added
* klipper & moonraker: generate version file during build to correctly display versions
* klipper, moonraker & ustreamer: add healthchecks to container images
### Fixed
### Changed
### Removed
Expand Down
3 changes: 3 additions & 0 deletions docker/klipper/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ RUN groupadd klipper --gid 1000 \
RUN mkdir -p printer_data/run printer_data/gcodes printer_data/logs printer_data/config \
&& chown -R klipper:klipper /opt/*

COPY --chown=klipper:klipper health.py ./
HEALTHCHECK --interval=5s CMD ["python3", "/opt/health.py"]

COPY --chown=klipper:klipper --from=build /opt/klipper ./klipper
COPY --chown=klipper:klipper --from=build /opt/venv ./venv

Expand Down
9 changes: 8 additions & 1 deletion docker/klipper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,11 @@ none
|`build-hostmcu`|Based on `mcu`: Build the klipper_mcu binary|No|
|`run`|Default runtime Image for klippy|Yes|
|`tools`|Build Tools for MCU code compilation|Yes|
|`hostmcu`|Runtime Image for the klipper_mcu binary|Yes|
|`hostmcu`|Runtime Image for the klipper_mcu binary|Yes|

## Healthcheck
`/opt/health.py` gets executed every 5s inside the container.
The script does the following:
* queries klippers `info` endpoint via its unix socket
* Checks if state is `ready`
* If one of the above requirements is not `ready`, the script exits with a failure state to indicate the container is unhealthy
22 changes: 22 additions & 0 deletions docker/klipper/health.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python3
import socket, json, sys

socket_address="/opt/printer_data/run/klipper.sock"
message={"id": 666, "method": "info"}

# Set up socket connection
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(socket_address)

# Send message and receive response
sock.sendall(json.dumps(message).encode() + b"\x03")
response = sock.recv(4096).decode('utf-8').strip('\x03')
sock.close()

# Check the result
if json.loads(response)["result"]["state"] == "ready":
# State is ready - healthy
sys.exit(0)
else:
# State is not ready - unhealthy
sys.exit(1)
4 changes: 4 additions & 0 deletions docker/moonraker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ RUN apt update \
systemd \
sudo \
git \
jq \
&& apt clean

WORKDIR /opt
Expand All @@ -48,6 +49,9 @@ RUN groupadd moonraker --gid 1000 \
RUN mkdir -p printer_data/run printer_data/gcodes printer_data/logs printer_data/database printer_data/config \
&& chown -R moonraker:moonraker /opt/*

COPY --chown=moonraker:moonraker health.sh ./
HEALTHCHECK --interval=5s CMD ["bash", "/opt/health.sh"]

COPY --chown=moonraker:moonraker --from=build /opt/moonraker ./moonraker
COPY --chown=moonraker:moonraker --from=build /opt/venv ./venv

Expand Down
12 changes: 11 additions & 1 deletion docker/moonraker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,14 @@ services:
|Target|Description|Pushed|
|---|---|---|
|`build`|Pull Upstream Codebase and build python venv|No|
|`run`|Default runtime Image|Yes|
|`run`|Default runtime Image|Yes|

## Healthcheck
`/opt/health.sh` gets executed every 5s inside the container.
The script does the following:
* queries the `/server/info` endpoint of moonraker
* Performs the following checks
* Number of failed moonraker_components = 0
* klippy_connected is `true`
* klippy_state is `ready`
* If one of the above requirements is not met, the script exits with a failure state to indicate the container is unhealthy
17 changes: 17 additions & 0 deletions docker/moonraker/health.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

serverinfo=$(curl -s localhost:7125/server/info)

klippy_connected=$(echo -n ${serverinfo} | jq -r .result.klippy_connected)
klippy_state=$(echo -n ${serverinfo} | jq -r .result.klippy_state)
failed_components=$(echo -n ${serverinfo} | jq -r .result.failed_components[] | wc -l)

if [ "$klippy_connected" == "true" ] \
&& [ "$klippy_state" == "ready" ] \
&& [ $failed_components -eq 0 ]; then
## moonraker is up and connected to klippy
exit 0
else
## moonraker started w/ failed components and/or is not connected to klippy
exit 1
fi
7 changes: 6 additions & 1 deletion docker/ustreamer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,23 @@ RUN apt update \
libbsd0 \
libgpiod2 \
v4l-utils \
curl \
jq \
&& apt clean

WORKDIR /opt
RUN groupadd ustreamer --gid 1000 \
&& useradd ustreamer --uid 1000 --gid ustreamer \
&& usermod ustreamer --append --groups video

COPY --chown=ustreamer:ustreamer health.sh ./
HEALTHCHECK --interval=5s CMD ["bash", "/opt/health.sh"]

COPY --chown=ustreamer:ustreamer --from=build /opt/ustreamer/src/ustreamer.bin ./ustreamer

## Start ustreamer
USER ustreamer
EXPOSE 8080
ENTRYPOINT [ "/opt/ustreamer"]
ENTRYPOINT ["/opt/ustreamer"]
CMD ["--host=0.0.0.0", "--port=8080"]

11 changes: 10 additions & 1 deletion docker/ustreamer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,13 @@ none
|Target|Description|Pushed|
|---|---|---|
|`build`|Pull Upstream Codebase and build application|No|
|`run`|Default runtime Image|Yes|
|`run`|Default runtime Image|Yes|

## Healthcheck
`/opt/health.sh` gets executed every 5s inside the container.
The script does the following:
* gets the JSON structure with the state of the server
* Checks the following values
* `.ok` is set to `true`, which indicates ustreamer is working
* `.result.source.online` is set to `true`, which indicates the source (webcam) is returning an image rather than `NO SIGNAL`
* If one of the above requirements is not met, the script exits with a failure state to indicate the container is unhealthy
13 changes: 13 additions & 0 deletions docker/ustreamer/health.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

state=$(curl -s localhost:8080/state)
ok=$(echo $state | jq -r .ok)
online=$(echo $state | jq -r .result.source.online)

if [ "$ok" == "true" ] && [ "$online" == "true" ]; then
## ustreamer is ok and source is online
exit 0
else
## ustreamer is not ok or source is not online
exit 1
fi

0 comments on commit 9ef0e9d

Please sign in to comment.