diff --git a/Dockerfile b/Dockerfile index b0b7e9b..8a3fc9b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -139,6 +139,24 @@ RUN { /opt/usr/sbin/unbound-anchor -v -r root.hints -a root.key || true ; } | te #################################################################################################### +# This is a minimal C wrapper for drill to avoid the need for a shell +# and reduce the exit code to 0 or 1. +# Dockerfile reference says that health checks should always return 0 or 1. +# Any other status code is reserved. +# See https://docs.docker.com/reference/dockerfile/#healthcheck +FROM build-base AS drill-hc + +# Set the working directory +WORKDIR /src + +# Copy the source file +COPY drill-hc/main.c . + +# Compile the program statically +RUN gcc -Wall -Wextra -pedantic -std=c2x -static -O3 -o drill-hc main.c + +#################################################################################################### + FROM scratch AS final COPY --from=build-base /lib/ld-musl*.so.1 /lib/ @@ -152,6 +170,8 @@ COPY --from=unbound /opt/usr/sbin/ /usr/sbin/ COPY --from=ldns /opt/usr/bin/ /usr/bin/ +COPY --from=drill-hc /src/drill-hc /usr/bin/drill-hc + COPY --chown=unbound:unbound rootfs_overlay/etc/unbound/ /etc/unbound/ COPY --from=root-key --chown=unbound:unbound /var/unbound/root.hints /var/unbound/root.hints diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 722178d..a7d4f08 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,7 +1,4 @@ -version: "2" - services: - server: image: localhost:5000/sut build: @@ -48,9 +45,9 @@ services: sleep 5 - docker exec $${server_id} drill -p 5353 dnssec.works @127.0.0.1 | tee /dev/stderr | grep NOERROR - ! docker exec $${server_id} drill -p 5353 foo.local @127.0.0.1 | tee /dev/stderr | grep NOERROR - ! docker exec $${server_id} drill -p 5353 bar.local @127.0.0.1 | tee /dev/stderr | grep NOERROR + docker exec $${server_id} drill-hc -p 5353 dnssec.works @127.0.0.1 | tee /dev/stderr | grep NOERROR + ! docker exec $${server_id} drill-hc -p 5353 foo.local @127.0.0.1 | tee /dev/stderr | grep NOERROR + ! docker exec $${server_id} drill-hc -p 5353 bar.local @127.0.0.1 | tee /dev/stderr | grep NOERROR dig @server -p 5353 dnssec.works +dnssec +multi | tee /dev/stderr | grep NOERROR ! dig @server -p 5353 fail01.dnssec.works +dnssec +multi | tee /dev/stderr | grep NOERROR diff --git a/drill-hc/main.c b/drill-hc/main.c new file mode 100644 index 0000000..b6f1e40 --- /dev/null +++ b/drill-hc/main.c @@ -0,0 +1,51 @@ +// This is a minimal C wrapper for drill to avoid the need for a shell +// and reduce the exit code to 0 or 1. +// Dockerfile reference says that health checks should always return 0 or 1. +// Any other status code is reserved. +// See https://docs.docker.com/reference/dockerfile/#healthcheck + +#include +#include +#include + +int main(int argc, char **argv) +{ + char* DRILL_ARGS[] = {"/usr/bin/drill", NULL}; + if (argc == 0) { + argv = DRILL_ARGS; + } + else { + argv[0] = DRILL_ARGS[0]; + } + + switch (fork()) + { + case -1: + perror("Error calling fork()"); + return 1; + + case 0: + execv(argv[0], argv); + perror("Error calling execv() with drill"); + return 1; + + default: + int status; + if (wait(&status) == -1) { + perror("Error calling wait()"); + return 1; + } + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) == 0) { + return 0; + } + else { + return 1; + } + + } else { + fprintf(stderr, "drill process was terminated for unknown reason\n"); + return 1; + } + } +} diff --git a/examples/pi-hole/docker-compose.yml b/examples/pi-hole/docker-compose.yml index 1109de6..c797ae7 100644 --- a/examples/pi-hole/docker-compose.yml +++ b/examples/pi-hole/docker-compose.yml @@ -7,18 +7,18 @@ services: container_name: pihole image: pihole/pihole:latest ports: - - "53:53/tcp" - - "53:53/udp" - - "67:67/udp" - - "80:80/tcp" + - '53:53/tcp' + - '53:53/udp' + - '67:67/udp' + - '80:80/tcp' networks: default: ipv4_address: 172.28.0.3 environment: - PIHOLE_DNS_: "172.28.0.2;172.28.0.2" + PIHOLE_DNS_: '172.28.0.2;172.28.0.2' volumes: - - "pihole:/etc/pihole" - - "dnsmasq:/etc/dnsmasq.d" + - 'pihole:/etc/pihole' + - 'dnsmasq:/etc/dnsmasq.d' cap_add: - NET_ADMIN restart: unless-stopped @@ -29,7 +29,8 @@ services: default: ipv4_address: 172.28.0.2 healthcheck: - test: ["CMD", "drill", "@127.0.0.1", "dnssec.works"] + # Use the drill wrapper binary to reduce the exit codes to 0 or 1 for healthchecks + test: ['CMD', 'drill-hc', '@127.0.0.1', 'dnssec.works'] interval: 30s timeout: 30s retries: 3 diff --git a/examples/redis/docker-compose.yml b/examples/redis/docker-compose.yml index fdaf3ec..4195d45 100644 --- a/examples/redis/docker-compose.yml +++ b/examples/redis/docker-compose.yml @@ -19,7 +19,8 @@ services: unbound: image: klutchell/unbound healthcheck: - test: ["CMD", "drill", "@127.0.0.1", "dnssec.works"] + # Use the drill wrapper binary to reduce the exit codes to 0 or 1 for healthchecks + test: ['CMD', 'drill-hc', '@127.0.0.1', 'dnssec.works'] interval: 30s timeout: 30s retries: 3