Skip to content

Instantly share code, notes, and snippets.

@venkata-qa
Last active April 9, 2025 17:29
Show Gist options
  • Save venkata-qa/ac45986cceb15268a1053ec1ecad3dd5 to your computer and use it in GitHub Desktop.
Save venkata-qa/ac45986cceb15268a1053ec1ecad3dd5 to your computer and use it in GitHub Desktop.
#!/bin/bash
NAMESPACE=$1
if [[ -z "$NAMESPACE" ]]; then
echo "❌ Usage: $0 <namespace>"
exit 1
fi
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
REPORT_FILE="k8s_release_report_${NAMESPACE}_$(date +%Y%m%d).md"
add_heading() {
echo -e "\n## $1\n" >> "$REPORT_FILE"
}
add_subheading() {
echo -e "\n### $1\n" >> "$REPORT_FILE"
}
# Report header
cat <<EOF > "$REPORT_FILE"
# 🚀 Kubernetes Release Report
- **Namespace**: \`$NAMESPACE\`
- **Generated**: \`$TIMESTAMP\`
- **Cluster Context**: \`$(kubectl config current-context 2>/dev/null)\`
---
EOF
# 1. Namespace Overview
add_heading "1. Namespace Overview"
kubectl describe namespace "$NAMESPACE" --request-timeout=30s 2>/dev/null | grep -E 'Name:|Labels:|Status:' >> "$REPORT_FILE"
# 2. Deployment Summary
add_heading "2. Deployment Summary"
echo '| Deployment | Ready Replicas | Up-to-date | Available |' >> "$REPORT_FILE"
echo '|------------|----------------|------------|-----------|' >> "$REPORT_FILE"
kubectl get deployments -n "$NAMESPACE" --no-headers | awk '{printf "| %s | %s | %s | %s |\n", $1, $2, $3, $4}' >> "$REPORT_FILE"
# 3. Pod Summary
add_heading "3. Pod Summary"
echo '| Status | Count |' >> "$REPORT_FILE"
echo '|--------|-------|' >> "$REPORT_FILE"
kubectl get pods -n "$NAMESPACE" --no-headers -o custom-columns=STATUS:.status.phase | sort | uniq -c | awk '{printf "| %s | %s |\n", $2, $1}' >> "$REPORT_FILE"
# 3.0 Expected vs Running Pods
add_subheading "3.0 Expected vs Running Pods"
DEPLOY_REPLICAS=$(kubectl get deployments -n "$NAMESPACE" -o json | jq '[.items[].spec.replicas // 0] | add')
STS_REPLICAS=$(kubectl get statefulsets -n "$NAMESPACE" -o json | jq '[.items[].spec.replicas // 0] | add')
DS_REPLICAS=$(kubectl get daemonsets -n "$NAMESPACE" -o json | jq '[.items[].status.desiredNumberScheduled // 0] | add')
EXPECTED=$((DEPLOY_REPLICAS + STS_REPLICAS + DS_REPLICAS))
RUNNING=$(kubectl get pods -n "$NAMESPACE" --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l)
echo '| Source | Expected Pods |' >> "$REPORT_FILE"
echo '|---------------|----------------|' >> "$REPORT_FILE"
echo "| Deployments | $DEPLOY_REPLICAS |" >> "$REPORT_FILE"
echo "| StatefulSets | $STS_REPLICAS |" >> "$REPORT_FILE"
echo "| DaemonSets | $DS_REPLICAS |" >> "$REPORT_FILE"
echo "| **Total Expected** | **$EXPECTED** |" >> "$REPORT_FILE"
echo "| **Running Pods** | **$RUNNING** |" >> "$REPORT_FILE"
# 3.1 Pod Health Summary (to file)
add_subheading "3.1 Pod Health Summary"
POD_TOTAL=$(kubectl get pods -n "$NAMESPACE" --no-headers 2>/dev/null | wc -l)
POD_RUNNING=$(kubectl get pods -n "$NAMESPACE" --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l)
CRASHING_PODS=$(kubectl get pods -n "$NAMESPACE" -o json 2>/dev/null | jq '[.items[] | select(.status.containerStatuses[]?.state.waiting.reason == "CrashLoopBackOff")] | length')
echo "- **Total Pods**: $POD_TOTAL" >> "$REPORT_FILE"
echo "- **Running Pods**: $POD_RUNNING" >> "$REPORT_FILE"
echo "- **CrashLoopBackOff Pods**: $CRASHING_PODS" >> "$REPORT_FILE"
# 3.2 CrashLoopBackOff Pods
add_subheading "3.2 CrashLoopBackOff Pods"
echo '| Pod Name | Node | Restarts |' >> "$REPORT_FILE"
echo '|----------|------|----------|' >> "$REPORT_FILE"
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_FILE"
# 4. Deployed Images
add_heading "4. Deployed Images"
# 4.1 App images
add_subheading "4.1 Application Images"
echo '| Image | Version |' >> "$REPORT_FILE"
echo '|--------|---------|' >> "$REPORT_FILE"
kubectl get pods -n "$NAMESPACE" -o json | jq -r '
[.items[].spec.containers[].image] | unique | .[] | select(test("istio|proxy|envoy|sidecar") | not)' | sort |
while read -r image; do
base=$(echo "$image" | cut -d":" -f1)
tag=$(echo "$image" | cut -d":" -f2)
echo "| $base | ${tag:-latest} |"
done >> "$REPORT_FILE"
# 4.2 Sidecar images
add_subheading "4.2 Sidecar Images"
echo '| Image | Version |' >> "$REPORT_FILE"
echo '|--------|---------|' >> "$REPORT_FILE"
kubectl get pods -n "$NAMESPACE" -o json | jq -r '
[.items[].spec.containers[].image] | unique | .[] | select(test("istio|proxy|envoy|sidecar"))' | sort |
while read -r image; do
base=$(echo "$image" | cut -d":" -f1)
tag=$(echo "$image" | cut -d":" -f2)
echo "| $base | ${tag:-latest} |"
done >> "$REPORT_FILE"
# 5. Top Resource Usage Pods
add_heading "5. Top Resource Usage Pods"
echo '| Pod Name | CPU (m) | Memory (Mi) |' >> "$REPORT_FILE"
echo '|----------|---------|-------------|' >> "$REPORT_FILE"
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_FILE" || echo '| Metrics unavailable | - | - |' >> "$REPORT_FILE"
# 6. Recent Warnings
add_heading "6. Recent Warning Events"
echo '| Type | Reason | Message | Time |' >> "$REPORT_FILE"
echo '|------|--------|---------|------|' >> "$REPORT_FILE"
kubectl get events -n "$NAMESPACE" --sort-by=.lastTimestamp -o json 2>/dev/null | jq -r '
.items[]
| select(.type == "Warning")
| {
type: .type,
reason: .reason,
message: (.message // "N/A") | tostring | gsub("[\n\r\t]+"; " ") | sub("^(.{0,60}).*"; "\1..."),
time: (.lastTimestamp // "N/A")
}
| [.type, .reason, .message, .time]
| @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_FILE"
echo -e "\n✅ Minimal release report generated: $REPORT_FILE"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment