// healthcheck is a static binary used by Docker HEALTHCHECK CMD in distroless // images (which have no shell, wget, or curl). // // Two modes: // // 1. HTTP mode (default): // /healthcheck // Performs GET ; exits 0 if HTTP 2xx/3xx, 1 otherwise. // Example: /healthcheck http://localhost:8080/health // // 2. File-liveness mode: // /healthcheck file // Reads , parses its content as RFC3339 timestamp, and exits 1 if the // timestamp is older than . Used by the runner service which // writes /tmp/runner.alive on every successful poll. // Example: /healthcheck file /tmp/runner.alive 120 package main import ( "fmt" "net/http" "os" "strconv" "time" ) func main() { if len(os.Args) > 1 && os.Args[1] == "file" { checkFile() return } checkHTTP() } // checkHTTP performs a GET request and exits 0 on success, 1 on failure. func checkHTTP() { url := "http://localhost:8080/health" if len(os.Args) > 1 { url = os.Args[1] } resp, err := http.Get(url) //nolint:gosec,noctx if err != nil { fmt.Fprintf(os.Stderr, "healthcheck: %v\n", err) os.Exit(1) } resp.Body.Close() if resp.StatusCode >= 400 { fmt.Fprintf(os.Stderr, "healthcheck: status %d\n", resp.StatusCode) os.Exit(1) } } // checkFile reads a timestamp from a file and exits 1 if it is older than the // given max age. Usage: /healthcheck file func checkFile() { if len(os.Args) < 4 { fmt.Fprintln(os.Stderr, "healthcheck file: usage: /healthcheck file ") os.Exit(1) } path := os.Args[2] maxAgeSec, err := strconv.ParseInt(os.Args[3], 10, 64) if err != nil { fmt.Fprintf(os.Stderr, "healthcheck file: invalid max_age_seconds %q: %v\n", os.Args[3], err) os.Exit(1) } data, err := os.ReadFile(path) if err != nil { fmt.Fprintf(os.Stderr, "healthcheck file: cannot read %s: %v\n", path, err) os.Exit(1) } ts, err := time.Parse(time.RFC3339, string(data)) if err != nil { // Fallback: use file mtime if content is not a valid timestamp. info, statErr := os.Stat(path) if statErr != nil { fmt.Fprintf(os.Stderr, "healthcheck file: cannot stat %s: %v\n", path, statErr) os.Exit(1) } ts = info.ModTime() } age := time.Since(ts) if age > time.Duration(maxAgeSec)*time.Second { fmt.Fprintf(os.Stderr, "healthcheck file: %s is %.0fs old (max %ds)\n", path, age.Seconds(), maxAgeSec) os.Exit(1) } }