Skip to content

tarampampam/microcheck

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

34 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Lightweight health check utilities for Docker containers

Minimal, statically linked tools designed for container health checks. Built with musl for minimal size and zero dependencies.

A common use case is to include these tools in HEALTHCHECK instructions in Dockerfiles, allowing Docker to monitor the health of applications running inside containers. Typically, you don't need them in Kubernetes (because Kubernetes has its own health check mechanisms, where the kubelet periodically checks the container's status), but in vanilla Docker or other container runtimes without built-in health checks, these tools can be very useful.

You might say, "But why? There are already tools like curl or wget!". That's true, but those tools are often quite large because they include many features and dependencies. Using them only for health checks can unnecessarily increase the size of your Docker images. These tools are designed to be as small as possible while still providing the required functionality, especially for scratch or distroless images (curl and wget won't work there at all, since they rely on shared libraries). In addition, their exit codes are designed to match Docker's expectations for health checks (0 = healthy, 1 = unhealthy), whereas curl and wget do not follow this convention.

Just to illustrate the size difference, here is a comparison of adding httpcheck versus curl or wget:

COPY --from=... /bin/httpcheck  [β–Œ--------------------------------------] 75Kb
apk add wget                    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ--------------------] 3.3Mb // 44Γ— larger
apt install wget                [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ------------------] 4Mb   // 53Γ— larger
apk add curl                    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ-------------] 5.2Mb // 69Γ— larger
apt install curl                [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 9.3Mb // 124Γ— larger

So, think of this as an alternative to:

-# install curl for health checks (+~10MB)
-RUN apt update && apt install -y curl && rm -r /var/lib/apt/lists/*
-
-HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost:8080/ || exit 1
+# add httpcheck binary (+~75KB)
+COPY --from=ghcr.io/tarampampam/microcheck:1 /bin/httpcheck /bin/httpcheck
+
+HEALTHCHECK --interval=5m --timeout=3s CMD ["httpcheck", "http://localhost:8080/"]

Note

By the way - the first approach also creates a shell process (adding unnecessary overhead) and depends on the shell being present in the container, which may not be the case in minimal images.

πŸ”₯ Features

  • Statically linked: Works in minimal containers (e.g., scratch, distroless)
  • Pretty fast: Written in pure C, compiled with musl
  • Multi-arch and cross-compiled (x86_64, ARM, etc.), even for macOS you may find precompiled binaries in the releases
  • Distributed as single binaries (see the releases page) and Docker image
  • Minimal size: Optimized for small Docker images
  • TLS support: Uses mbedTLS for HTTPS (accepts self-signed certificates and does NOT verify SSL/TLS certificates)
  • Protocol auto-detection (httpscheck only): Automatically tries HTTPS first, falls back to HTTP on TLS errors
  • Flexible configuration: Command-line flags and environment variables
  • Docker-friendly: Handles signals (SIGTERM, SIGINT) gracefully

🧩 Tools

Tool Size Use case
httpcheck ~75KB Check HTTP (only) endpoints
httpscheck ~500KB Check HTTP and HTTPS endpoints
portcheck ~70KB Check TCP/UDP ports
parallel ~50KB Run multiple commands in parallel
pidcheck ~40KB Check if process from PID file is running

httpcheck & httpscheck

Those tools perform HTTP health checks. httpscheck includes TLS support, while httpcheck does not to reduce the binary file size. Both tools share the same command-line interface, and even compile from the same source code (but with different build flags).

Note

httpscheck supports protocol auto-detection: when no protocol (http:// or https://) is specified in the URL, it will first attempt an HTTPS connection. If the HTTPS connection fails (TLS handshake error), it will automatically fall back to HTTP. This is useful for applications that may have TLS enabled or disabled based on configuration.

Options:
  -h, --help           Show this help message
  -m, --method         HTTP method to use (default: "GET") [$CHECK_METHOD]
      --method-env     Change env variable name for --method
  -u, --user-agent     User-Agent header value (default: "healthcheck/0.0.0 (httpscheck)") [$CHECK_USER_AGENT]
      --user-agent-env Change env variable name for --user-agent
  -t, --timeout        Request timeout in seconds (default: "5") [$CHECK_TIMEOUT]
      --timeout-env    Change env variable name for --timeout
  -H, --header         Add custom HTTP header (can be used multiple times)
      --basic-auth     Basic auth credentials (username:password) [$CHECK_BASIC_AUTH]
      --basic-auth-env Change env variable name for --basic-auth
      --host           Override hostname from URL [$CHECK_HOST]
      --host-env       Change env variable name for --host
  -p, --port           Override port from URL [$CHECK_PORT]
      --port-env       Change env variable name for --port

URL Format Examples:

# Explicit HTTP
httpcheck http://localhost:8080/health

# Explicit HTTPS
httpscheck https://localhost:8080/health

# Auto-detect (httpscheck only): tries HTTPS first, falls back to HTTP on TLS error
httpscheck localhost:8080/health

portcheck

This tool checks if a TCP or UDP port is open on a given host (usually 127.0.0.1). For TCP, it attempts to establish a connection, while for UDP... Since UDP is connectionless - very frequently it may not be possible to determine if the port is open or closed.

Important

Most UDP servers respond only to valid protocol requests. This tool sends nearly empty UDP datagram, which may not receive a response from many services. Use UDP checks only when you are certain the target will respond appropriately.

Note

You need to specify the target host and port explicitly via flags or environment variables. Don't try to pass them as positional arguments like portcheck --port 80 example.com, as this tool does not accept them that way. Use --host and --port options instead - portcheck --port 80 --host example.com.

Options:
  -h, --help        Show this help message
      --tcp         Use TCP protocol (default)
      --udp         Use UDP protocol
      --host        Target hostname or IPv4 address (default: "127.0.0.1") [$CHECK_HOST]
      --host-env    Change env variable name for --host
  -p, --port        Target port number (required) [$CHECK_PORT]
      --port-env    Change env variable name for --port
  -t, --timeout     Check timeout in seconds (default: "5") [$CHECK_TIMEOUT]
      --timeout-env Change env variable name for --timeout

Examples:

# Check TCP port 80 on localhost
portcheck --port 80

# Check UDP port 53 on example.com
portcheck --udp --port 53 --host example.com

parallel

This tool executes multiple commands in parallel and is designed specifically for Docker health checks where you need to verify multiple conditions simultaneously. It returns exit code 0 only if all commands succeed, or the exit code of the first failed command otherwise.

The main use case is combining multiple health checks (HTTP endpoints, TCP ports, etc.) into a single HEALTHCHECK instruction. When any command fails, parallel immediately terminates all other running commands and returns the failure code, ensuring fast failure detection.

Options:
  -h, --help  Show this help message
  -j, --jobs  Limit number of parallel jobs (has no effect, kept for backward compatibility

Examples:

# Check both HTTP endpoint AND port using parallel
parallel "httpcheck http://127.0.0.1:8080" "portcheck --port 8080"

# Check multiple HTTP endpoints
parallel "httpcheck http://127.0.0.1:8080/health" "httpcheck http://127.0.0.1:8080/status"

Argument Parsing

Commands can be specified as:

  • Unquoted words for simple commands: parallel whoami id
  • Quoted strings for commands with arguments: parallel "echo hello" "echo world"
  • Mixed quoted/unquoted parts that concatenate: parallel cmd'arg1 arg2'"arg3" (produces a single argument: cmdarg1 arg2arg3)

Inside quoted strings:

  • Single quotes preserve everything literally (no escaping)
  • Double quotes allow backslash escaping
  • Spaces and tabs separate arguments
  • Adjacent quoted/unquoted parts concatenate into single argument

pidcheck

This tool checks whether a process specified in a PID file or directly by PID is currently running. It reads the PID from a file or a command line argument and verifies that the process exists using the kill(pid, 0) system call.

Note

The zero signal (kill(pid, 0)) does not actually send a signal but performs error checking to determine whether the process exists and whether the current user has permission to send signals to it.

It may be useful for monitoring daemon processes inside containers that do not open any kind of network ports, but write their PID to a file.

Options:
  -h, --help     Show this help message
  -f, --file     Path to PID file [$CHECK_PIDFILE]
      --file-env Change env variable name for --file
  -p, --pid      Process ID to check [$CHECK_PID]
      --pid-env  Change env variable name for --pid

Note

The --file and --pid options are mutually exclusive and cannot be used together.

Here is an example of how to create and write a PID file in your Go app:

package main

import (
	"fmt"
	"os"
	"strconv"
)

func main() {
	pidFile := "/var/run/myapp.pid"

	// write the PID to the specified file
	if err := os.WriteFile(pidFile, []byte(strconv.Itoa(os.Getpid())), 0o644); err != nil {
		panic(fmt.Errorf("failed to write PID file: %w", err))
	}

	defer func() { _ = os.Remove(pidFile) }() // remove PID file on exit

	// ... the rest of your app
}

And then use pidcheck in your Dockerfile:

HEALTHCHECK --interval=5s CMD ["pidcheck", "--file", "/var/run/myapp.pid"]

PID File Format

The PID file should contain a single process ID number. Leading and trailing whitespace is automatically stripped. Any non-numeric content will result in an error.

Environment Variable Overrides

Most options can be overridden via environment variables. This is useful in Docker containers, where you may want to configure health checks without modifying the command line. For example:

# Use a custom method via environment variable
CHECK_METHOD=HEAD httpcheck http://127.0.0.1

# If the application already uses the APP_PORT variable, you can map it to override the port used by httpcheck
APP_PORT=8080 httpcheck --port-env=APP_PORT http://127.0.0.1

πŸ‹ Docker image

Registry Image
GitHub Container Registry ghcr.io/tarampampam/microcheck
Red Hat Container Registry quay.io/tarampampam/microcheck
Docker Hub tarampampam/microcheck

Important

Using the latest tag for the Docker image is highly discouraged due to potential backward-incompatible changes during major upgrades. Please use tags in the X.Y.Z, X.Y, or at least X format.

The following platforms for this image are available:

$ docker run --rm mplatform/mquery ghcr.io/tarampampam/microcheck:1
Image: ghcr.io/tarampampam/microcheck:1
 * Manifest List: Yes (Image type: application/vnd.oci.image.index.v1+json)
 * Supported platforms:
   - linux/386
   - linux/amd64
   - linux/arm/v6
   - linux/arm/v7
   - linux/arm64
   - linux/ppc64le
   - linux/s390x

βš™ Pre-compiled binaries

Pre-compiled static binaries are available on the releases page. Download the appropriate binary for your architecture and operating system.

πŸ”Œ Usage examples

πŸš€ Healthcheck for HTTP server
# use empty filesystem
FROM scratch

# import some executable application
COPY --from=docker.io/containous/whoami:v1.5.0 /whoami /whoami

# import httpcheck from current repository image (exactly 'httpcheck' due
# to we don't need TLS here)
COPY --from=ghcr.io/tarampampam/microcheck:1 /bin/httpcheck /bin/httpcheck

# docs: <https://docs.docker.com/reference/dockerfile#healthcheck>
HEALTHCHECK --interval=5s --retries=2 CMD ["httpcheck", "http://127.0.0.1:8080/health"]

ENTRYPOINT ["/whoami", "-port", "8080"]

Let's build it and run:

$ docker build -t http-check:local - < ./examples/http-check.Dockerfile
$ docker run --rm -d --name http-check http-check:local
$ docker ps --filter 'name=http-check' --format '{{.Status}}'
Up 6 seconds (healthy)
$ docker kill http-check
πŸš€ Multiple health checks with parallel

This example shows how to use parallel to check multiple conditions simultaneously. The container is considered healthy only if all checks pass:

FROM scratch

# import some executable application
COPY --from=docker.io/containous/whoami:v1.5.0 /whoami /whoami

# import httpcheck, portcheck and parallel from microcheck image
COPY --from=ghcr.io/tarampampam/microcheck:1 /bin/httpcheck /bin/portcheck /bin/parallel /bin/

# check both HTTP endpoint AND port using parallel (the port usually will differ from the HTTP port)
HEALTHCHECK --interval=5s --retries=2 CMD ["parallel", \
    "httpcheck http://127.0.0.1:8080", \
    "portcheck --port 8080" \
]

ENTRYPOINT ["/whoami", "-port", "8080"]

Let's build it and run:

$ docker build -t parallel:local - < ./examples/parallel.Dockerfile
$ docker run --rm -d --name parallel parallel:local
$ docker ps --filter 'name=parallel' --format '{{.Status}}'
Up 6 seconds (healthy)
$ docker kill parallel
πŸš€ Healthcheck with protocol auto-detection

This example demonstrates the protocol auto-detection feature of httpscheck, which is useful when your application may have TLS enabled or disabled based on configuration:

# use empty filesystem
FROM scratch

# import your application (example assumes it can run with or without TLS)
COPY --from=your-app:latest /app /app

# import httpscheck to enable auto-detection
COPY --from=ghcr.io/tarampampam/microcheck:1 /bin/httpscheck /bin/httpscheck

# healthcheck will try HTTPS first, fall back to HTTP if TLS is not available
# note: no http:// or https:// prefix in the URL
HEALTHCHECK --interval=5s --retries=2 CMD ["httpscheck", "127.0.0.1:8080/health"]

ENTRYPOINT ["/app"]

How it works:

  1. When no protocol is specified (127.0.0.1:8080/health instead of https://...), httpscheck first attempts an HTTPS connection
  2. If the HTTPS handshake fails (TLS error), it automatically falls back to HTTP
  3. This happens silently without any output, making it transparent for health checks
  4. The fallback only occurs on connection/TLS errors, not on HTTP status codes (4xx, 5xx)

This is particularly useful for:

  • Applications with optional TLS configuration
  • Development vs production environments
  • Gradual TLS rollouts
πŸš€ Healthcheck for TCP server

The same as previous, but using portcheck:

# use empty filesystem
FROM scratch

# import some executable application
COPY --from=docker.io/containous/whoami:v1.5.0 /whoami /whoami

# import portcheck because we need only TCP port check here
COPY --from=ghcr.io/tarampampam/microcheck:1 /bin/portcheck /bin/portcheck

# docs: <https://docs.docker.com/reference/dockerfile#healthcheck>
HEALTHCHECK --interval=5s --retries=2 CMD ["portcheck", "--port", "8080"]

ENTRYPOINT ["/whoami", "-port", "8080"]

Let's build it and run:

$ docker build -t tcp-check:local - < ./examples/tcp-check.Dockerfile
$ docker run --rm -d --name tcp-check tcp-check:local
$ docker ps --filter 'name=tcp-check' --format '{{.Status}}'
Up 7 seconds (healthy)
$ docker kill tcp-check
πŸš€ Healthcheck for daemon process using pidcheck

This example demonstrates how to use pidcheck to monitor a daemon process inside a Docker container.

[!NOTE] Since nginx exposes TCP port and even HTTP endpoint, we use here pidcheck just for demonstration purposes (better to use portcheck or httpcheck in real-world scenarios).

FROM docker.io/library/nginx:1.25-alpine

# import pidcheck from microcheck image
COPY --from=ghcr.io/tarampampam/microcheck:1 /bin/pidcheck /bin/pidcheck

# nginx writes its PID to /var/run/nginx.pid by default
HEALTHCHECK --interval=5s --retries=2 CMD ["pidcheck", "--file", "/var/run/nginx.pid"]

Let's build it and run:

$ docker build -t pidcheck:local - < ./examples/pidcheck.Dockerfile
$ docker run --rm -d --name pidcheck pidcheck:local
$ docker ps --filter 'name=pidcheck' --format '{{.Status}}'
Up 8 seconds (healthy)
$ docker kill pidcheck

🎁 Bonus level - adding healthcheck to popular images

Since you're here, you might find it useful to know how to healthcheck some popular Docker images (you don't need tools from this repository for that, but it might be interesting anyway):

πŸ§ͺ PostgreSQL

PostgreSQL, often simply "Postgres", is an object-relational database management system (ORDBMS) with an emphasis on extensibility and standards-compliance.

# compose.yml

services:
  postgresql:
    image: docker.io/library/postgres:18-alpine
    environment:
      POSTGRES_DB: some_dbname # POSTGRES_DATABASE in older versions
      POSTGRES_USER: some_user
      POSTGRES_PASSWORD: some_password
    ports: ['5432/tcp']
    healthcheck:
      test: ['CMD', 'pg_isready', '-U', 'some_user', '-d', 'some_dbname']
      interval: 10s
πŸ§ͺ Temporal

Temporal is a scalable and reliable runtime for durable function executions.

# compose.yml

services:
  temporal:
    image: docker.io/temporalio/auto-setup:1.28.1
    environment:
      BIND_ON_IP: 0.0.0.0
    ports: ['7233/tcp']
    healthcheck:
      test: ['CMD', 'tctl', '--address', '127.0.0.1:7233', 'workflow', 'list']
      interval: 10s
πŸ§ͺ Jaeger

Jaeger is an open-source, distributed tracing platform used to monitor and troubleshoot complex microservices architectures.

# compose.yml

services:
  jaeger:
    image: docker.io/jaegertracing/all-in-one:1.60
    ports: ['6831/udp', '16686/tcp', '4318/tcp']
    healthcheck:
      test: ['CMD', 'wget', '--spider', '-q', 'http://127.0.0.1:14269/healthz']
      interval: 10s
πŸ§ͺ Minio

MinIO is a high-performance, Kubernetes-native object storage system that is compatible with the Amazon S3 API.

# compose.yml

services:
  minio:
    image: quay.io/minio/minio:RELEASE.2025-09-07T16-13-09Z
    command: server /data --json --console-address ':9090'
    ports: ['9000/tcp', '9090/tcp']
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://127.0.0.1:9000/minio/health/live']
      interval: 10s
πŸ§ͺ MySQL

MySQL is an open-source relational database management system (RDBMS).

# compose.yml

services:
  mysql:
    image: docker.io/library/mysql:9
    environment:
      MYSQL_RANDOM_ROOT_PASSWORD: 'true'
      MYSQL_DATABASE: some_dbname
      MYSQL_USER: some_user
      MYSQL_PASSWORD: some_password
    ports: ['3306/tcp', '3306/tcp'] # use port 32601 for local development
    healthcheck:
      test: ['CMD', 'mysql', '-h', '127.0.0.1', '--user=some_user', '--password=some_password', '--execute', 'SELECT 1']
      interval: 10s
πŸ§ͺ Redis

Redis is an open-source, in-memory data structure store used as a database, cache, and message broker.

# compose.yml

services:
  redis:
    image: docker.io/library/redis:8-alpine
    ports: ['6379/tcp']
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 10s
πŸ§ͺ Adminer (phpMinAdmin)

Adminer (formerly phpMinAdmin) is a full-featured database management tool written in PHP.

# compose.yml

services:
  adminer:
    image: docker.io/library/adminer:5
    ports: ['8080/tcp']
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/"]
      interval: 10s
πŸ§ͺ Caddy

Caddy 2 is a powerful, enterprise-ready, open source web server with automatic HTTPS written in Go.

# compose.yml

services:
  caddy:
    image: docker.io/library/caddy:2-alpine
    ports: ['80/tcp', '443/tcp']
    healthcheck:
      test: ['CMD', 'wget', '--spider', '-q', 'http://127.0.0.1:80/']
      interval: 10s
πŸ§ͺ Cassandra

Apache Cassandra is an open source distributed database management system designed to handle large amounts of data across many commodity servers, providing high availability with no single point of failure.

# compose.yml

services:
  cassandra:
    image: docker.io/library/cassandra:5
    ports: ['9042/tcp']
    healthcheck:
      test: ['CMD', 'cqlsh', '-e', 'DESCRIBE KEYSPACES', '127.0.0.1', '9042']
      interval: 10s
      start_period: 60s # <-- important

Tip

Feel free to contribute more examples via pull requests!

πŸ— Building from sources

To build the tools from sources, ensure you have the following dependencies installed:

  • musl-gcc
  • cmake
  • wget
  • patch
  • Standard build tools (make, tar)
  • Optionally - clang-format

After cloning the repository, build the tools using the Makefile - execute make.

For testing, you need python3 and openssl installed. Run tests with make test.

πŸ‘Ύ Support

Issues Issues

If you encounter any bugs in the project, please create an issue in this repository.

πŸ“– License

This is open-sourced software licensed under the MIT License.

About

πŸ§ͺ Lightweight health check utilities for Docker containers

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors 3

  •  
  •  
  •  

Languages