From 472c0063e7c0c2f9303419aaefe5dad972188d2d Mon Sep 17 00:00:00 2001 From: Adarsh Prashar Date: Sun, 31 May 2026 03:26:06 +0530 Subject: [PATCH] feat: add a Docker HEALTHCHECK for the daemon The distroless image has no shell or curl, so add a `riskkernel healthcheck` subcommand that GETs /healthz and exits non-zero when unhealthy, and wire it into the Dockerfile HEALTHCHECK. Lets orchestrators see container health. Fixes #14 --- Dockerfile | 4 ++++ cmd/riskkernel/healthcheck.go | 30 ++++++++++++++++++++++++++++++ cmd/riskkernel/main.go | 3 +++ 3 files changed, 37 insertions(+) create mode 100644 cmd/riskkernel/healthcheck.go diff --git a/Dockerfile b/Dockerfile index 4201e78..9ac51e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,5 +39,9 @@ EXPOSE 7070 VOLUME ["/data"] USER 65532:65532 +# distroless has no shell/curl, so the binary probes itself (GET /healthz). +HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \ + CMD ["/usr/local/bin/riskkernel", "healthcheck"] + ENTRYPOINT ["/usr/local/bin/riskkernel"] CMD ["serve"] diff --git a/cmd/riskkernel/healthcheck.go b/cmd/riskkernel/healthcheck.go new file mode 100644 index 0000000..a386cdb --- /dev/null +++ b/cmd/riskkernel/healthcheck.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + "net/http" + "time" + + "github.com/prashar32/riskkernel/internal/config" +) + +// runHealthcheck probes the daemon's /healthz endpoint and exits non-zero if it +// is not OK. It backs the Docker HEALTHCHECK — the distroless image has no shell +// or curl, so the binary checks itself. +func runHealthcheck(_ []string) error { + cfg, err := config.Load() + if err != nil { + return err + } + url := fmt.Sprintf("http://127.0.0.1:%d/healthz", cfg.Port) + client := &http.Client{Timeout: 4 * time.Second} + resp, err := client.Get(url) + if err != nil { + return fmt.Errorf("healthcheck: %w", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("healthcheck: unhealthy (status %d)", resp.StatusCode) + } + return nil +} diff --git a/cmd/riskkernel/main.go b/cmd/riskkernel/main.go index cf359ac..bf71d73 100644 --- a/cmd/riskkernel/main.go +++ b/cmd/riskkernel/main.go @@ -48,6 +48,8 @@ func main() { err = runApprovals(args) case "memory": err = runMemory(args) + case "healthcheck": + err = runHealthcheck(args) case "version", "--version", "-v": fmt.Println("riskkernel", version.String()) case "help", "--help", "-h": @@ -78,6 +80,7 @@ Usage: riskkernel approvals deny [--reason ...] Deny a pending request riskkernel memory list [namespace] List git-native memory entries riskkernel memory show [namespace] Print a memory file + riskkernel healthcheck Probe /healthz (used by the Docker HEALTHCHECK) riskkernel version Print build identity riskkernel help Show this help