Kubernetes Probes — Complete Implementation Guide
In this tutorial, you will learn about Kubernetes Probes. We cover key concepts, practical examples, and best practices to help you master this topic.
Kubernetes probes are configured in the pod spec to control how kubelet checks container health, with three probe types (liveness, readiness, startup) and three handler types (HTTP, TCP, gRPC).
What You'll Learn
By the end of this tutorial, you will know how to configure all three Kubernetes probe types, choose the right handler, set timing parameters, and avoid common probe configuration mistakes.
Why It Matters
Kubernetes probes are the primary mechanism for automated health management. Misconfigured probes cause unnecessary restarts, traffic loss, and deployment failures.
Real-World Use
DodaTech's standard Kubernetes deployment includes all three probes: startup (30 attempts, 1 second each), readiness (5 second interval, 3 failures), liveness (15 second interval, 3 failures).
Kubernetes Probes Learning Path
flowchart LR
A[Spring Boot Health Check] --> B[Kubernetes Probes]
B --> C[HTTP Probes]
B --> D[gRPC Probes]
B --> E[Timing Config]
B --> F{You Are Here}
style F fill:#f90,color:#fff
Probe Types and Their Purposes
Each probe type serves a distinct purpose in the container lifecycle.
class KubernetesProbeExplainer {
static describe(type) {
const probes = {
liveness: {
purpose: "Know when to restart a container",
action: "Restart the container",
endpoint: "/healthz",
commonConfig: "Every 15s, timeout 5s, failureThreshold 3"
},
readiness: {
purpose: "Know when a container is ready to serve traffic",
action: "Remove from Service endpoints",
endpoint: "/readyz",
commonConfig: "Every 10s, timeout 3s, failureThreshold 3"
},
startup: {
purpose: "Know when a container has started",
action: "Delay liveness/readiness checks",
endpoint: "/startupz",
commonConfig: "Every 5s, timeout 5s, failureThreshold 30"
}
};
const p = probes[type];
console.log(`${type} probe: ${p.purpose}`);
console.log(` Action: ${p.action}`);
console.log(` Common endpoint: ${p.endpoint}`);
console.log(` Config: ${p.commonConfig}`);
}
}
KubernetesProbeExplainer.describe("readiness");
KubernetesProbeExplainer.describe("liveness");
KubernetesProbeExplainer.describe("startup");
// readiness probe: Know when a container is ready to serve traffic
// Action: Remove from Service endpoints
// Common endpoint: /readyz
// Config: Every 10s, timeout 3s, failureThreshold 3
HTTP Probe Configuration
HTTP probes are the most common and check HTTP response status codes.
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:1.0.0
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /startupz
port: 8080
initialDelaySeconds: 0
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
gRPC Probe Configuration
Kubernetes 1.24+ supports native gRPC probes.
# deployment.yaml with gRPC probe
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: grpc-service
image: grpc-service:1.0.0
ports:
- containerPort: 50051
readinessProbe:
grpc:
port: 50051
service: "my.Service"
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
grpc:
port: 50051
service: "my.Service"
initialDelaySeconds: 15
periodSeconds: 15
// gRPC health server implementation (Node.js example)
const grpc = require("@grpc/grpc-js");
const health = require("@grpc/grpc-js/build/src/health");
function createHealthServer() {
const healthImpl = new health.HealthImplementation({
"my.Service": health.ServingStatus.SERVING
});
const server = new grpc.Server();
healthImpl.addToServer(server);
return server;
}
const server = createHealthServer();
server.bindAsync("0.0.0.0:50051", grpc.ServerCredentials.createInsecure(), () => {
server.start();
console.log("gRPC health server on :50051");
});
TCP Probe Configuration
TCP probes check if a port is accepting connections. Use for non-HTTP services.
# TCP probe example
readinessProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
class TCPProbeDemo {
static reasonsForTCP() {
return [
"Non-HTTP services (databases, message queues)",
"Services where a connection means healthy",
"When HTTP health endpoint is not implemented",
"Simple readiness checks during migration"
];
}
static limitations() {
return [
"Cannot verify application logic (only TCP port)",
"Cannot check response content",
"Higher false-positive rate than HTTP probes"
];
}
}
console.log("Use TCP probes for:");
TCPProbeDemo.reasonsForTCP().forEach(r => console.log(" -", r));
Probe Timing Parameter Guide
Each timing parameter has specific effects on probe behavior.
class ProbeTimingGuide {
static explain() {
return {
initialDelaySeconds: {
purpose: "Wait before first probe",
recommendation: "5 for readiness, 15 for liveness, 0 for startup",
risk: "Too low: probe fails before service is ready. Too high: delayed detection."
},
periodSeconds: {
purpose: "How often to run the probe",
recommendation: "10 for readiness, 15 for liveness, 5 for startup",
risk: "Too low: unnecessary load. Too high: slow detection of failures."
},
timeoutSeconds: {
purpose: "Max time for probe to complete",
recommendation: "3-5 seconds",
risk: "Too low: false failures during latency spikes. Too high: probe backlog."
},
failureThreshold: {
purpose: "Consecutive failures before action",
recommendation: "3 for readiness/liveness, 30 for startup",
risk: "Too low: flapping. Too high: slow response to failures."
},
successThreshold: {
purpose: "Successes needed to recover",
recommendation: "1 (default)",
risk: "Higher values prevent flapping but delay recovery."
}
};
}
static calculateDetectionTime(periodSeconds, failureThreshold) {
return periodSeconds * failureThreshold;
}
}
const guide = ProbeTimingGuide.explain();
Object.entries(guide).forEach(([name, info]) => {
console.log(`${name}: ${info.recommendation}`);
});
// initialDelaySeconds: 5 for readiness, 15 for liveness, 0 for startup
// periodSeconds: 10 for readiness, 15 for liveness, 5 for startup
// timeoutSeconds: 3-5 seconds
// failureThreshold: 3 for readiness/liveness, 30 for startup
// successThreshold: 1 (default)
Common Mistakes
Using the same probe for liveness and readiness -- Liveness restarts the container, readiness removes from service. Differentiate them for proper behavior.
Setting initialDelaySeconds too low -- If the service takes 10 seconds to start but initialDelaySeconds is 2, probes fail and the container restarts repeatedly.
Forgetting startup probes for slow-starting services -- Without a startup probe, liveness checks start immediately and restart the container during initialization.
Setting timeoutSeconds higher than periodSeconds -- If timeout is 10s and period is 5s, probes overlap and create a backlog of concurrent checks.
Not considering probe impact on performance -- A probe that makes expensive database queries every 5 seconds across 10 replicas creates 120 queries per minute. Keep probes lightweight.
Practice Questions
What is the purpose of the startup probe? To delay liveness and readiness checks until the container has finished initializing. This prevents premature restarts.
What happens when a readiness probe fails? The pod is removed from all Service endpoints. No traffic is routed to it, but it's not restarted.
What is the formula for worst-case detection time for a liveness probe? initialDelaySeconds + (periodSeconds * failureThreshold). Example: 15 + (15 * 3) = 60 seconds worst case.
Challenge: Write a probe configuration validator that checks for common misconfigurations.
class ProbeConfigValidator {
static validate(probe, name) {
const issues = [];
if (probe.timeoutSeconds >= probe.periodSeconds) {
issues.push(`${name}: timeout (${probe.timeoutSeconds}s) >= period (${probe.periodSeconds}s)`);
}
if (probe.failureThreshold < 2) {
issues.push(`${name}: failureThreshold too low (${probe.failureThreshold})`);
}
if (probe.initialDelaySeconds < 0) {
issues.push(`${name}: initialDelaySeconds cannot be negative`);
}
return { name, valid: issues.length === 0, issues };
}
}
const config = {
initialDelaySeconds: 5,
periodSeconds: 10,
timeoutSeconds: 15,
failureThreshold: 1
};
console.log(ProbeConfigValidator.validate(config, "readiness"));
// { name: 'readiness', valid: false, issues: [ 'readiness: timeout (15s) >= period (10s)', 'readiness: failureThreshold too low (1)' ] }
FAQ
Mini Project
Generate a complete Kubernetes deployment YAML with properly configured liveness, readiness, and startup probes for a Node.js application, including a probe validation step.
function generateProbeYaml(appName, port, options = {}) {
const probes = {
startup: {
httpGet: { path: "/startupz", port },
initialDelaySeconds: 0,
periodSeconds: 5,
timeoutSeconds: 3,
failureThreshold: 30
},
readiness: {
httpGet: { path: "/readyz", port },
initialDelaySeconds: 5,
periodSeconds: 10,
timeoutSeconds: 3,
failureThreshold: 3
},
liveness: {
httpGet: { path: "/healthz", port },
initialDelaySeconds: 15,
periodSeconds: 15,
timeoutSeconds: 5,
failureThreshold: 3
},
...options
};
return {
apiVersion: "apps/v1",
kind: "Deployment",
metadata: { name: appName },
spec: {
replicas: 3,
selector: { matchLabels: { app: appName } },
template: {
metadata: { labels: { app: appName } },
spec: {
containers: [{
name: appName,
image: `${appName}:latest`,
ports: [{ containerPort: port }],
...probes
}]
}
}
}
};
}
const yaml = generateProbeYaml("my-app", 8080);
console.log("Probe config generated for:", yaml.metadata.name);
What's Next
Now that you understand Kubernetes probes, learn how to create custom health indicators. Then explore health check aggregation for Microservices.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro