Getting Started with Probes in Kubernetes

Kubernetes offers three types of probes that you can configure on a container to improve application reliability and traffic management:
Liveness Probe: The liveness probe checks whether a container is running properly. If it fails, Kubernetes assumes the container is stuck or broken and will automatically restart it. This helps applications recover from unrecoverable failures without human intervention.
Readiness Probe: The readiness probe determines whether a container is ready to handle incoming requests. If the probe fails, Kubernetes will temporarily remove the container from the service's endpoints, effectively pausing traffic to it, but without stopping or restarting the container itself.
Startup Probe: For applications that need extra time to initialize, the startup probe offers a better alternative to the liveness probe during startup. It allows Kubernetes to give the container sufficient time to become ready, avoiding premature restarts and unnecessary failures during the boot process.
Usage by example
Golang Health App
Let's now look at an example of how you can configure HTTP health endpoints in a Golang application and how we can specify probes on a Kubernetes pod container.
./main.go
package main
import (
"fmt"
"log"
"net/http"
"sync/atomic"
"time"
)
var (
hasStarted atomic.Bool
isReady atomic.Bool
)
func startApp() {
log.Println("Initializing application")
// simulate initialization delay
time.Sleep(time.Second * 10)
hasStarted.Store(true)
isReady.Store(true)
log.Println("Successfully initialized application, " +
"ready to receive traffic")
}
func main() {
// start main application
go startApp()
// setup liveness HTTP endpoint
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
if hasStarted.Load() {
w.WriteHeader(http.StatusOK)
w.Write([]byte("STATUS OK"))
} else {
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte("APPLICATION NOT STARTED"))
}
})
// setup readiness HTTP endpoint
http.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
if isReady.Load() {
w.WriteHeader(http.StatusOK)
w.Write([]byte("STATUS OK"))
} else {
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte("APPLICATION NOT READY"))
}
})
listenPort := 8080
log.Printf("Starting HTTP server on port: %d\n", listenPort)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", listenPort), nil))
}
Docker image
Let’s use a simple Dockerfile to run our Go application in Kubernetes. (This is not recommended in production.)
./dockerfile
FROM golang:1.24
COPY main.go main.go
CMD ["go", "run", "main.go"]
To build Docker image run,
$ docker build -t docker.io/health_check_app:latest -f dockerfile .
Deploying in Kubernetes
./kubernetes.yaml
apiVersion: v1
kind: Pod
metadata:
name: health-app
labels:
app: health-app
spec:
containers:
- name: main
image: docker.io/health_check_app:latest
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
Here,
initialDelaySeconds
is delay before the probe starts running.periodSeconds
is how often to perform the probe.timeoutSeconds
is how long to wait for a response.failureThreshold
is how many times to fail before marking the container as unhealthy/unready.
Bonus
The publishNotReadyAddresses
field in a Kubernetes Service allows the service to include the IPs of Pods that are not yet marked as Ready, which is especially useful in StatefulSet peer discovery scenarios. In distributed systems like Cassandra or custom peer-to-peer apps, a Pod often needs to discover and connect to other peers before it can be considered Ready. By enabling this field on a headless service (clusterIP: None
), all Pods—including those still starting up—are included in DNS resolution, allowing early peer communication and successful bootstrapping before the readiness condition is met.
Subscribe to my newsletter
Read articles from Rupinder Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
