Skip to content

Instantly share code, notes, and snippets.

@venkata-qa
Last active April 10, 2025 07:32
Show Gist options
  • Save venkata-qa/ab349b562f5ef399c18ae31cf957044f to your computer and use it in GitHub Desktop.
Save venkata-qa/ab349b562f5ef399c18ae31cf957044f to your computer and use it in GitHub Desktop.
#!/bin/bash
NAMESPACE=$1
if [[ -z "$NAMESPACE" ]]; then
echo "❌ Usage: $0 <namespace>"
exit 1
fi
DATE=$(date "+%Y-%m-%d %H:%M:%S")
REPORT="k8s_health_report_${NAMESPACE}_$(date +%Y%m%d).md"
add_heading() {
echo -e "\n## $1\n" >> "$REPORT"
}
add_subheading() {
echo -e "\n### $1\n" >> "$REPORT"
}
# Header
cat <<EOF > "$REPORT"
# πŸš€ Kubernetes Cluster Health Report
- **Namespace**: \`$NAMESPACE\`
- **Cluster**: \`$(kubectl config current-context)\`
- **Generated On**: \`$DATE\`
---
EOF
# Pre-fetch values
CRASHING=$(kubectl get pods -n "$NAMESPACE" -o json | jq '[.items[] | select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff")] | length')
POD_TOTAL=$(kubectl get pods -n "$NAMESPACE" --no-headers | wc -l)
POD_RUNNING=$(kubectl get pods -n "$NAMESPACE" --field-selector=status.phase=Running --no-headers | wc -l)
REPLICA_ISSUES=$(kubectl get deployments -n "$NAMESPACE" -o json | jq '[.items[] | select((.spec.replicas // 0) != (.status.readyReplicas // 0))] | length')
# 1. Cluster Readiness Summary
add_heading "1. 🚦 Cluster Readiness Summary"
if [[ "$CRASHING" -eq 0 && "$REPLICA_ISSUES" -eq 0 ]]; then
echo "**βœ… Cluster is healthy and ready for release. All deployments are stable.**" >> "$REPORT"
else
echo "**⚠️ Issues detected:**" >> "$REPORT"
echo "- CrashLoopBackOff Pods: **$CRASHING**" >> "$REPORT"
echo "- Deployment Replica Mismatches: **$REPLICA_ISSUES**" >> "$REPORT"
fi
# 2. Namespace Metadata
add_heading "2. 🏷️ Namespace Overview"
kubectl describe namespace "$NAMESPACE" | grep -E 'Name:|Labels:|Status:' >> "$REPORT"
# 3. Deployment Status
add_heading "3. πŸ“¦ Deployment Status"
echo '| Name | Ready | Up-to-date | Available |' >> "$REPORT"
echo '|------|-------|-------------|-----------|' >> "$REPORT"
kubectl get deployments -n "$NAMESPACE" --no-headers | awk '{printf "| %s | %s | %s | %s |\n", $1, $2, $3, $4}' >> "$REPORT"
# 4. Deployment Replica Mismatches
add_heading "4. 🧐 Deployment Replica Mismatches"
MISMATCHES=$(kubectl get deployments -n "$NAMESPACE" -o json | jq -r '
.items[] |
{
name: .metadata.name,
expected: (.spec.replicas // 0),
ready: (.status.readyReplicas // 0)
} |
select(.expected != .ready) |
[.name, .expected, .ready] | @tsv')
if [[ -z "$MISMATCHES" ]]; then
echo "_βœ… All deployments have expected number of ready replicas._" >> "$REPORT"
else
echo '| Deployment | Expected | Ready |' >> "$REPORT"
echo '|------------|----------|-------|' >> "$REPORT"
echo "$MISMATCHES" | while IFS=$'\t' read -r name expected ready; do
echo "| $name | $expected | $ready |"
done >> "$REPORT"
fi
# 5. Expected vs Running Pods
add_heading "5. πŸ”„ Expected vs Running Pods"
DEPLOY=$(kubectl get deployments -n "$NAMESPACE" -o json | jq '[.items[].spec.replicas // 0] | add')
STS=$(kubectl get statefulsets -n "$NAMESPACE" -o json | jq '[.items[].spec.replicas // 0] | add')
DS=$(kubectl get daemonsets -n "$NAMESPACE" -o json | jq '[.items[].status.desiredNumberScheduled // 0] | add')
EXPECTED=$((DEPLOY + STS + DS))
echo '| Source | Expected |' >> "$REPORT"
echo '|---------------|----------|' >> "$REPORT"
echo "| Deployments | $DEPLOY |" >> "$REPORT"
echo "| StatefulSets | $STS |" >> "$REPORT"
echo "| DaemonSets | $DS |" >> "$REPORT"
echo "| **Total** | **$EXPECTED** |" >> "$REPORT"
echo "| **Running** | **$POD_RUNNING** / $POD_TOTAL |" >> "$REPORT"
# 6. Pod Health Summary
add_heading "6. βœ… Pod Health Summary"
echo "- Total Pods: **$POD_TOTAL**" >> "$REPORT"
echo "- Running Pods: **$POD_RUNNING**" >> "$REPORT"
echo "- CrashLoopBackOff Pods: **$CRASHING**" >> "$REPORT"
# 7. CrashLoopBackOff Pods
if [[ "$CRASHING" -gt 0 ]]; then
add_heading "7. 🚫 CrashLoopBackOff Pods"
echo '| Pod Name | Node | Restarts |' >> "$REPORT"
echo '|----------|------|----------|' >> "$REPORT"
kubectl get pods -n "$NAMESPACE" -o json | jq -r '
.items[] |
select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff") |
[.metadata.name, .spec.nodeName, (.status.containerStatuses[0].restartCount // 0)] | @tsv' |
while IFS=$'\t' read -r pod node restarts; do
printf "| %s | %s | %s |\n" "$pod" "$node" "$restarts"
done >> "$REPORT"
fi
# 8. Top Resource Usage
add_heading "8. πŸ“Š Top Resource Usage (CPU)"
echo '| Pod | CPU (m) | Memory (Mi) |' >> "$REPORT"
echo '|-----|---------|--------------|' >> "$REPORT"
kubectl top pods -n "$NAMESPACE" --no-headers 2>/dev/null | sort -k2 -rh | head -n 5 | awk '{printf "| %s | %s | %s |\n", $1, $2, $3}' >> "$REPORT" || echo '| Metrics unavailable | - | - |' >> "$REPORT"
# 9. Image Versions
add_heading "10. πŸ§ͺ Deployed Image Versions"
echo '| Image | Version |' >> "$REPORT"
echo '|--------|---------|' >> "$REPORT"
kubectl get pods -n "$NAMESPACE" -o json | jq -r '
[.items[].spec.containers[].image] | unique | .[]' | sort |
while read -r image; do
base=$(echo "$image" | cut -d":" -f1)
tag=$(echo "$image" | cut -d":" -f2)
echo "| $base | ${tag:-latest} |"
done >> "$REPORT"
# 10. Recent Warning Events
add_heading "9. πŸ”₯ Recent Warning Events"
echo '| Type | Reason | Message | Time |' >> "$REPORT"
echo '|------|--------|---------|------|' >> "$REPORT"
kubectl get events -n "$NAMESPACE" --sort-by=.lastTimestamp -o json | jq -r '
.items[]
| select(.type == "Warning")
| [
.type,
.reason,
(.message // "N/A" | tostring | gsub("[\n\r\t]+"; " ") | sub("^(.{0,60}).*"; "\\1...")),
(.lastTimestamp // "N/A")
]
| @tsv' | tail -n 10 |
while IFS=$'\t' read -r type reason msg time; do
printf "| %s | %s | %s | %s |\n" "$type" "$reason" "$msg" "$time"
done >> "$REPORT"
echo ""
echo "βœ… Report generated: $REPORT"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment