opsdocsConsole

Packages / ops-sdk

Healthcheck probe

A dependency free healthcheck binary for container images that have no shell and no curl.

Updated 13 Oct 2026View as Markdown

Feature: probe.

A hardened image (distroless or scratch) has no shell and no curl, so a container healthcheck needs a binary of its own. The healthprobe binary sends one GET to a loopback address and exits by the answer. It uses the standard library only: the feature adds no dependency, and the binary is a few hundred kilobytes.

Build it into the image

dockerfile
FROM rust:1.85 AS build
RUN cargo install ops-sdk --registry ops --features probe --bin healthprobe --root /out
# ... build your service in the same stage ...

FROM gcr.io/distroless/cc-debian12
COPY --from=build /out/bin/healthprobe /usr/local/bin/healthprobe
COPY --from=build /src/target/release/web /usr/local/bin/web
HEALTHCHECK CMD ["/usr/local/bin/healthprobe", "http://127.0.0.1:8080/healthz"]
CMD ["/usr/local/bin/web"]

The image build needs the registry configuration from the install steps to fetch the crate.

Usage

sh
healthprobe <http://host:port/path> [timeout-seconds]
exit codemeaning
0healthy: the answer's status is below 400. A redirect counts as healthy
1unhealthy: a bad status, a refused connection, a timeout or a malformed answer
2called wrongly: no URL, or a timeout that is not a whole number above zero

The default timeout is 4 seconds for connecting, sending and reading together.

It speaks plain HTTP to a loopback address only: no TLS, no redirects, no proxy and no authentication. A healthcheck runs inside the container, so none of those are needed.

From your own code

The same check is a library call:

rust
use std::time::Duration;
use ops_sdk::probe::{DEFAULT_TIMEOUT_SECS, probe};

let status = probe("http://127.0.0.1:8080/healthz", Duration::from_secs(DEFAULT_TIMEOUT_SECS))?;

probe returns the HTTP status, or a sentence saying why there was none.