Kubernetes DaemonSet scheduling issues represent some of the most challenging troubleshooting scenarios in production environments, where critical system components fail to deploy across cluster nodes as expected. These issues can cascade into broader infrastructure problems, affecting monitoring, logging, storage, and networking capabilities that underpin entire application ecosystems.

Understanding how to systematically diagnose and resolve DaemonSet scheduling problems requires deep knowledge of Kubernetes scheduling mechanics, node conditions, taints and tolerations, and cluster networking. This comprehensive guide explores advanced troubleshooting methodologies based on real-world production scenarios and provides actionable solutions for complex scheduling challenges.

Executive Summary

Kubernetes DaemonSet scheduling failures require systematic troubleshooting approaches that examine node conditions, scheduling constraints, resource availability, and cluster configuration issues. This guide provides comprehensive methodologies for diagnosing complex scheduling problems, implementing automated resolution strategies, and building robust monitoring systems that prevent DaemonSet-related production incidents.

Understanding DaemonSet Scheduling Architecture

DaemonSet Controller Mechanics

DaemonSets operate through sophisticated scheduling logic that must account for numerous factors:

# Comprehensive DaemonSet scheduling analysis configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: daemonset-scheduling-analysis
  namespace: kube-system
data:
  scheduling-factors.yaml: |
    daemonset_scheduling_requirements:
      node_selection:
        - "Node must be in Ready state"
        - "Node must not have SchedulingDisabled condition"
        - "Node taints must be tolerated by DaemonSet"
        - "NodeSelector requirements must be satisfied"

      resource_requirements:
        - "Sufficient CPU resources available"
        - "Sufficient memory resources available"
        - "Required volumes can be mounted"
        - "Host ports are available if specified"

      network_requirements:
        - "CNI plugin operational on node"
        - "Pod CIDR allocation available"
        - "Host networking accessible if required"

      security_constraints:
        - "Pod Security Standards compliance"
        - "Service Account permissions"
        - "SecurityContext requirements met"
        - "Admission controller approvals"

    common_scheduling_failures:
      node_not_ready:
        symptoms:
          - "Pods remain in Pending state"
          - "desiredNumberScheduled < number of nodes"
          - "Node shows NotReady condition"
        causes:
          - "Kubelet not running or unhealthy"
          - "Container runtime issues"
          - "Network connectivity problems"

      taints_not_tolerated:
        symptoms:
          - "Pods not scheduled on specific nodes"
          - "Event shows FailedScheduling due to taints"
          - "desiredNumberScheduled excludes tainted nodes"
        causes:
          - "Node initialization taints not removed"
          - "Cloud provider taints present"
          - "Custom taints blocking scheduling"

      resource_constraints:
        symptoms:
          - "Pods in Pending state with resource warnings"
          - "Events show Insufficient resources"
          - "Node pressure conditions present"
        causes:
          - "CPU or memory limits exceeded"
          - "Disk pressure on nodes"
          - "Pod limit per node reached"

      node_selector_mismatch:
        symptoms:
          - "Pods not scheduled on any nodes"
          - "No events or warnings generated"
          - "DaemonSet shows 0 desired pods"
        causes:
          - "NodeSelector labels not present on nodes"
          - "Label selectors too restrictive"
          - "Node labels changed after DaemonSet creation"

---
# DaemonSet troubleshooting toolkit
apiVersion: v1
kind: ConfigMap
metadata:
  name: daemonset-troubleshooting-tools
  namespace: kube-system
data:
  diagnostic-commands.yaml: |
    basic_checks:
      - name: "Check DaemonSet status"
        command: "kubectl get daemonset -A -o wide"
        description: "Overview of all DaemonSets and their scheduling status"

      - name: "Describe problematic DaemonSet"
        command: "kubectl describe daemonset <daemonset-name> -n <namespace>"
        description: "Detailed information including events and conditions"

      - name: "Check node status"
        command: "kubectl get nodes -o wide"
        description: "Node readiness and basic information"

      - name: "Check node conditions"
        command: "kubectl describe nodes"
        description: "Detailed node conditions and resource usage"

    advanced_diagnostics:
      - name: "Check node taints"
        command: "kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, taints: .spec.taints}'"
        description: "Identify taints that might prevent scheduling"

      - name: "Check DaemonSet tolerations"
        command: "kubectl get daemonset <name> -o json | jq '.spec.template.spec.tolerations'"
        description: "Verify DaemonSet tolerations match node taints"

      - name: "Check node labels"
        command: "kubectl get nodes --show-labels"
        description: "Verify node labels for NodeSelector requirements"

      - name: "Check pod resource requests"
        command: "kubectl get daemonset <name> -o json | jq '.spec.template.spec.containers[].resources'"
        description: "Analyze resource requirements vs node capacity"

    event_analysis:
      - name: "Check recent cluster events"
        command: "kubectl get events --sort-by='.lastTimestamp' -A"
        description: "Recent events that might indicate scheduling issues"

      - name: "Filter DaemonSet-related events"
        command: "kubectl get events --field-selector involvedObject.kind=DaemonSet -A"
        description: "Events specifically related to DaemonSet operations"

      - name: "Check node events"
        command: "kubectl get events --field-selector involvedObject.kind=Node -A"
        description: "Node-related events that might affect scheduling"

    scheduler_diagnostics:
      - name: "Check scheduler logs"
        command: "kubectl logs -n kube-system -l component=kube-scheduler"
        description: "Scheduler decision logs for troubleshooting"

      - name: "Check kubelet logs on problematic nodes"
        command: "journalctl -u kubelet -f"
        description: "Kubelet logs on nodes where pods aren't scheduling"

Advanced Diagnostic Framework

Implement comprehensive diagnostic automation for DaemonSet issues:

#!/bin/bash
# Script: daemonset-diagnostics.sh
# Purpose: Comprehensive DaemonSet scheduling diagnostics

set -euo pipefail

# Configuration
DIAGNOSTIC_LOG="/var/log/daemonset-diagnostics-$(date +%Y%m%d_%H%M%S).log"
DIAGNOSTIC_REPORT="/tmp/daemonset-diagnostic-report-$(date +%Y%m%d_%H%M%S).json"

function log_diagnostic() {
    local level="$1"
    local message="$2"
    local timestamp=$(date -u +"%Y-%m-%d %H:%M:%S UTC")

    echo "[$timestamp] [$level] $message" | tee -a "$DIAGNOSTIC_LOG"
}

function analyze_cluster_state() {
    log_diagnostic "INFO" "Analyzing cluster state for DaemonSet scheduling"

    # Get basic cluster information
    local cluster_info=$(kubectl cluster-info 2>/dev/null | head -5)
    local k8s_version=$(kubectl version -o json 2>/dev/null | jq -r '.serverVersion.gitVersion' || echo "unknown")
    local node_count=$(kubectl get nodes --no-headers | wc -l)

    log_diagnostic "INFO" "Cluster: $k8s_version, Nodes: $node_count"

    # Check overall node health
    local ready_nodes=$(kubectl get nodes -o json | jq '[.items[] | select(.status.conditions[] | select(.type=="Ready" and .status=="True"))] | length')
    local not_ready_nodes=$((node_count - ready_nodes))

    if [[ $not_ready_nodes -gt 0 ]]; then
        log_diagnostic "WARN" "$not_ready_nodes nodes are not ready"
        kubectl get nodes | grep -v " Ready "
    fi

    # Check for node pressure conditions
    local nodes_with_pressure=$(kubectl get nodes -o json | jq -r '.items[] | select(.status.conditions[] | select(.type | test("Pressure$") and .status=="True")) | .metadata.name')

    if [[ -n "$nodes_with_pressure" ]]; then
        log_diagnostic "WARN" "Nodes with pressure conditions detected"
        for node in $nodes_with_pressure; do
            log_diagnostic "WARN" "Node $node has resource pressure"
        done
    fi

    log_diagnostic "INFO" "Cluster state analysis completed"
}

function analyze_daemonset_status() {
    local namespace="${1:-}"
    local daemonset_name="${2:-}"

    log_diagnostic "INFO" "Analyzing DaemonSet status"

    # Get all DaemonSets if not specified
    if [[ -z "$namespace" || -z "$daemonset_name" ]]; then
        log_diagnostic "INFO" "Analyzing all DaemonSets in cluster"

        # Get DaemonSet summary
        kubectl get daemonset -A -o json | jq -r '
          .items[] |
          "\(.metadata.namespace)/\(.metadata.name): \(.status.desiredNumberScheduled)/\(.status.numberReady) ready"
        ' | while read -r ds_info; do
            log_diagnostic "INFO" "DaemonSet status: $ds_info"
        done

        # Find problematic DaemonSets
        local problematic_ds=$(kubectl get daemonset -A -o json | jq -r '
          .items[] |
          select(.status.desiredNumberScheduled != .status.numberReady) |
          "\(.metadata.namespace),\(.metadata.name)"
        ')

        if [[ -n "$problematic_ds" ]]; then
            log_diagnostic "WARN" "Found DaemonSets with scheduling issues"
            echo "$problematic_ds" | while IFS=',' read -r ns name; do
                analyze_specific_daemonset "$ns" "$name"
            done
        fi
    else
        analyze_specific_daemonset "$namespace" "$daemonset_name"
    fi
}

function analyze_specific_daemonset() {
    local namespace="$1"
    local daemonset_name="$2"

    log_diagnostic "INFO" "Analyzing DaemonSet: $namespace/$daemonset_name"

    # Get DaemonSet details
    local ds_json=$(kubectl get daemonset "$daemonset_name" -n "$namespace" -o json)

    local desired=$(echo "$ds_json" | jq -r '.status.desiredNumberScheduled // 0')
    local ready=$(echo "$ds_json" | jq -r '.status.numberReady // 0')
    local available=$(echo "$ds_json" | jq -r '.status.numberAvailable // 0')
    local unavailable=$(echo "$ds_json" | jq -r '.status.numberUnavailable // 0')

    log_diagnostic "INFO" "DaemonSet $namespace/$daemonset_name: $ready/$desired ready, $unavailable unavailable"

    # Check tolerations
    local tolerations=$(echo "$ds_json" | jq -r '.spec.template.spec.tolerations // []')
    log_diagnostic "INFO" "DaemonSet tolerations: $(echo "$tolerations" | jq -c .)"

    # Check node selector
    local node_selector=$(echo "$ds_json" | jq -r '.spec.template.spec.nodeSelector // {}')
    log_diagnostic "INFO" "DaemonSet nodeSelector: $(echo "$node_selector" | jq -c .)"

    # Get DaemonSet events
    local ds_events=$(kubectl get events -n "$namespace" --field-selector involvedObject.name="$daemonset_name" --sort-by=.lastTimestamp 2>/dev/null || echo "")

    if [[ -n "$ds_events" ]]; then
        log_diagnostic "INFO" "Recent events for DaemonSet $namespace/$daemonset_name:"
        echo "$ds_events" | tail -5
    fi

    # Check pod status
    log_diagnostic "INFO" "Analyzing pods for DaemonSet $namespace/$daemonset_name"

    local pods=$(kubectl get pods -n "$namespace" -l "$(kubectl get daemonset "$daemonset_name" -n "$namespace" -o jsonpath='{.spec.selector.matchLabels}' | jq -r 'to_entries | map("\(.key)=\(.value)") | join(",")')" -o json)

    echo "$pods" | jq -r '.items[] | "\(.metadata.name): \(.status.phase) on \(.spec.nodeName // "unscheduled")"' | while read -r pod_info; do
        log_diagnostic "INFO" "Pod status: $pod_info"
    done

    # Identify nodes without pods
    identify_missing_pod_nodes "$namespace" "$daemonset_name" "$ds_json"
}

function identify_missing_pod_nodes() {
    local namespace="$1"
    local daemonset_name="$2"
    local ds_json="$3"

    log_diagnostic "INFO" "Identifying nodes missing DaemonSet pods"

    # Get all nodes
    local all_nodes=$(kubectl get nodes -o json | jq -r '.items[] | .metadata.name')

    # Get nodes with pods
    local nodes_with_pods=$(kubectl get pods -n "$namespace" -l "$(echo "$ds_json" | jq -r '.spec.selector.matchLabels | to_entries | map("\(.key)=\(.value)") | join(",")')" -o json | jq -r '.items[] | select(.spec.nodeName) | .spec.nodeName' | sort -u)

    # Find missing nodes
    local missing_nodes=""
    for node in $all_nodes; do
        if ! echo "$nodes_with_pods" | grep -q "^$node$"; then
            missing_nodes="$missing_nodes $node"
        fi
    done

    if [[ -n "$missing_nodes" ]]; then
        log_diagnostic "WARN" "Nodes without DaemonSet pods: $missing_nodes"

        for node in $missing_nodes; do
            analyze_node_scheduling_constraints "$node" "$ds_json"
        done
    else
        log_diagnostic "INFO" "All eligible nodes have DaemonSet pods"
    fi
}

function analyze_node_scheduling_constraints() {
    local node_name="$1"
    local ds_json="$2"

    log_diagnostic "INFO" "Analyzing scheduling constraints for node: $node_name"

    # Get node information
    local node_json=$(kubectl get node "$node_name" -o json)

    # Check node readiness
    local node_ready=$(echo "$node_json" | jq -r '.status.conditions[] | select(.type=="Ready") | .status')
    if [[ "$node_ready" != "True" ]]; then
        log_diagnostic "ERROR" "Node $node_name is not ready: $node_ready"
        return 1
    fi

    # Check node scheduling
    local unschedulable=$(echo "$node_json" | jq -r '.spec.unschedulable // false')
    if [[ "$unschedulable" == "true" ]]; then
        log_diagnostic "ERROR" "Node $node_name is marked as unschedulable"
        return 1
    fi

    # Check taints vs tolerations
    local node_taints=$(echo "$node_json" | jq -r '.spec.taints // []')
    local ds_tolerations=$(echo "$ds_json" | jq -r '.spec.template.spec.tolerations // []')

    if [[ "$node_taints" != "[]" ]]; then
        log_diagnostic "INFO" "Node $node_name has taints: $(echo "$node_taints" | jq -c .)"

        # Check if DaemonSet tolerates all taints
        local taint_check_result=$(check_taint_toleration "$node_taints" "$ds_tolerations")

        if [[ "$taint_check_result" != "ok" ]]; then
            log_diagnostic "ERROR" "DaemonSet cannot tolerate node taints: $taint_check_result"
            return 1
        fi
    fi

    # Check node selector
    local node_selector=$(echo "$ds_json" | jq -r '.spec.template.spec.nodeSelector // {}')
    if [[ "$node_selector" != "{}" ]]; then
        local node_labels=$(echo "$node_json" | jq -r '.metadata.labels')

        local selector_check=$(check_node_selector_match "$node_labels" "$node_selector")

        if [[ "$selector_check" != "ok" ]]; then
            log_diagnostic "ERROR" "Node $node_name does not match nodeSelector: $selector_check"
            return 1
        fi
    fi

    # Check resource availability
    check_node_resource_availability "$node_name" "$ds_json"

    log_diagnostic "INFO" "Node $node_name constraints analysis completed"
}

function check_taint_toleration() {
    local node_taints="$1"
    local ds_tolerations="$2"

    # Use kubectl to simulate scheduling decision
    local temp_pod=$(mktemp)

    cat > "$temp_pod" <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: taint-test-pod
spec:
  tolerations: $(echo "$ds_tolerations")
  containers:
  - name: test
    image: alpine:latest
    command: ["sleep", "3600"]
  nodeSelector:
    kubernetes.io/hostname: "$node_name"
EOF

    # Test if pod would be scheduled
    if kubectl apply --dry-run=server -f "$temp_pod" >/dev/null 2>&1; then
        rm -f "$temp_pod"
        echo "ok"
    else
        rm -f "$temp_pod"
        echo "taint_toleration_mismatch"
    fi
}

function check_node_selector_match() {
    local node_labels="$1"
    local node_selector="$2"

    # Check each selector requirement
    echo "$node_selector" | jq -r 'to_entries[] | "\(.key)=\(.value)"' | while read -r requirement; do
        local key="${requirement%%=*}"
        local value="${requirement##*=}"

        local node_value=$(echo "$node_labels" | jq -r --arg key "$key" '.[$key] // "not_found"')

        if [[ "$node_value" != "$value" ]]; then
            echo "selector_mismatch_${key}"
            return 1
        fi
    done

    echo "ok"
}

function check_node_resource_availability() {
    local node_name="$1"
    local ds_json="$2"

    log_diagnostic "INFO" "Checking resource availability on node: $node_name"

    # Get node capacity and allocatable resources
    local node_capacity=$(kubectl describe node "$node_name" | grep -A 10 "Capacity:" | grep -E "(cpu|memory)" | awk '{print $1 $2}')
    local node_allocatable=$(kubectl describe node "$node_name" | grep -A 10 "Allocatable:" | grep -E "(cpu|memory)" | awk '{print $1 $2}')

    log_diagnostic "INFO" "Node $node_name capacity: $node_capacity"
    log_diagnostic "INFO" "Node $node_name allocatable: $node_allocatable"

    # Get DaemonSet resource requests
    local ds_resources=$(echo "$ds_json" | jq -r '.spec.template.spec.containers[] | .resources.requests // {}')

    if [[ "$ds_resources" != "{}" ]]; then
        log_diagnostic "INFO" "DaemonSet resource requests: $(echo "$ds_resources" | jq -c .)"

        # Check if resources can be satisfied (basic check)
        local cpu_request=$(echo "$ds_resources" | jq -r '.cpu // "0"')
        local memory_request=$(echo "$ds_resources" | jq -r '.memory // "0"')

        if [[ "$cpu_request" != "0" || "$memory_request" != "0" ]]; then
            log_diagnostic "INFO" "DaemonSet requests: CPU=$cpu_request, Memory=$memory_request"
        fi
    fi
}

function generate_resolution_suggestions() {
    local namespace="$1"
    local daemonset_name="$2"

    log_diagnostic "INFO" "Generating resolution suggestions for $namespace/$daemonset_name"

    # Get DaemonSet and node information
    local ds_json=$(kubectl get daemonset "$daemonset_name" -n "$namespace" -o json)
    local nodes_json=$(kubectl get nodes -o json)

    # Common resolution strategies
    cat <<EOF

🔧 Resolution Suggestions for DaemonSet $namespace/$daemonset_name:

1. Node Taint Issues:
   - Check for unexpected taints: kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, taints: .spec.taints}'
   - Remove problematic taints: kubectl taint node <node-name> <taint-key>-
   - Add tolerations to DaemonSet if taints are intentional

2. Node Selector Issues:
   - Verify node labels: kubectl get nodes --show-labels
   - Update node labels: kubectl label node <node-name> <key>=<value>
   - Modify DaemonSet nodeSelector if too restrictive

3. Resource Constraints:
   - Check node resource usage: kubectl describe nodes
   - Reduce DaemonSet resource requests if possible
   - Add nodes with sufficient resources

4. Node Readiness Issues:
   - Check kubelet status: systemctl status kubelet
   - Check container runtime: systemctl status docker/containerd
   - Review kubelet logs: journalctl -u kubelet -f

5. Network Issues:
   - Verify CNI plugin status on problematic nodes
   - Check pod CIDR allocation
   - Test network connectivity between nodes

EOF

    log_diagnostic "INFO" "Resolution suggestions generated"
}

function create_diagnostic_report() {
    local namespace="${1:-all}"
    local daemonset_name="${2:-all}"

    log_diagnostic "INFO" "Creating comprehensive diagnostic report"

    cat > "$DIAGNOSTIC_REPORT" <<EOF
{
  "diagnostic_info": {
    "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "cluster_context": "$(kubectl config current-context)",
    "kubernetes_version": "$(kubectl version -o json 2>/dev/null | jq -r '.serverVersion.gitVersion' || echo 'unknown')",
    "target_namespace": "$namespace",
    "target_daemonset": "$daemonset_name"
  },
  "cluster_summary": {
    "total_nodes": $(kubectl get nodes --no-headers | wc -l),
    "ready_nodes": $(kubectl get nodes -o json | jq '[.items[] | select(.status.conditions[] | select(.type=="Ready" and .status=="True"))] | length'),
    "total_daemonsets": $(kubectl get daemonset -A --no-headers | wc -l),
    "problematic_daemonsets": $(kubectl get daemonset -A -o json | jq '[.items[] | select(.status.desiredNumberScheduled != .status.numberReady)] | length')
  },
  "detailed_analysis": "See diagnostic log: $DIAGNOSTIC_LOG",
  "recommendations": [
    "Review node taints and DaemonSet tolerations",
    "Verify node readiness and resource availability",
    "Check cluster events for scheduling failures",
    "Validate network connectivity and CNI status"
  ]
}
EOF

    log_diagnostic "INFO" "Diagnostic report created: $DIAGNOSTIC_REPORT"
    cat "$DIAGNOSTIC_REPORT" | jq .
}

function run_automated_fixes() {
    local namespace="$1"
    local daemonset_name="$2"

    log_diagnostic "INFO" "Running automated fixes for common DaemonSet issues"

    # Fix 1: Remove common problematic taints
    local problematic_taints=(
        "node.cloudprovider.kubernetes.io/uninitialized"
        "node.kubernetes.io/not-ready"
        "node.kubernetes.io/unreachable"
    )

    for taint in "${problematic_taints[@]}"; do
        local nodes_with_taint=$(kubectl get nodes -o json | jq -r --arg taint "$taint" '.items[] | select(.spec.taints[]? | select(.key == $taint)) | .metadata.name')

        for node in $nodes_with_taint; do
            log_diagnostic "INFO" "Attempting to remove taint $taint from node $node"

            # Check if taint should be automatically removed
            if [[ "$taint" == "node.cloudprovider.kubernetes.io/uninitialized" ]]; then
                local node_ready=$(kubectl get node "$node" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
                if [[ "$node_ready" == "True" ]]; then
                    log_diagnostic "INFO" "Removing initialization taint from ready node $node"
                    kubectl taint node "$node" "$taint:NoSchedule-" || true
                fi
            fi
        done
    done

    # Fix 2: Restart DaemonSet if needed
    log_diagnostic "INFO" "Restarting DaemonSet to trigger rescheduling"
    kubectl rollout restart daemonset "$daemonset_name" -n "$namespace" || true

    # Fix 3: Wait and re-check
    sleep 30

    log_diagnostic "INFO" "Automated fixes completed, re-checking status"
    analyze_specific_daemonset "$namespace" "$daemonset_name"
}

# Main diagnostic workflow
function run_comprehensive_diagnostics() {
    local namespace="${1:-}"
    local daemonset_name="${2:-}"

    log_diagnostic "INFO" "Starting comprehensive DaemonSet diagnostics"

    analyze_cluster_state
    analyze_daemonset_status "$namespace" "$daemonset_name"

    if [[ -n "$namespace" && -n "$daemonset_name" ]]; then
        generate_resolution_suggestions "$namespace" "$daemonset_name"
    fi

    create_diagnostic_report "$namespace" "$daemonset_name"

    log_diagnostic "INFO" "Comprehensive diagnostics completed"

    echo ""
    echo "🔍 Diagnostic Summary"
    echo "===================="
    echo "📄 Diagnostic log: $DIAGNOSTIC_LOG"
    echo "📊 Diagnostic report: $DIAGNOSTIC_REPORT"
    echo ""
    echo "Next steps:"
    echo "1. Review detailed diagnostic log"
    echo "2. Apply suggested resolutions"
    echo "3. Monitor DaemonSet status after changes"
}

# Execution
case "${1:-help}" in
    "diagnose")
        run_comprehensive_diagnostics "${2:-}" "${3:-}"
        ;;
    "cluster")
        analyze_cluster_state
        ;;
    "daemonset")
        if [[ -n "${2:-}" && -n "${3:-}" ]]; then
            analyze_specific_daemonset "$2" "$3"
        else
            analyze_daemonset_status
        fi
        ;;
    "fix")
        if [[ -n "${2:-}" && -n "${3:-}" ]]; then
            run_automated_fixes "$2" "$3"
        else
            echo "Usage: $0 fix <namespace> <daemonset-name>"
        fi
        ;;
    "report")
        create_diagnostic_report "${2:-all}" "${3:-all}"
        ;;
    *)
        echo "Kubernetes DaemonSet Diagnostics Tool"
        echo "===================================="
        echo ""
        echo "Usage: $0 {diagnose|cluster|daemonset|fix|report} [namespace] [daemonset-name]"
        echo ""
        echo "Commands:"
        echo "  diagnose [ns] [ds]    - Run comprehensive diagnostics"
        echo "  cluster               - Analyze cluster state"
        echo "  daemonset [ns] [ds]   - Analyze specific DaemonSet"
        echo "  fix <ns> <ds>         - Apply automated fixes"
        echo "  report [ns] [ds]      - Generate diagnostic report"
        ;;
esac

Advanced Monitoring and Prevention Strategies

Proactive DaemonSet Health Monitoring

Implement comprehensive monitoring systems to prevent DaemonSet scheduling issues:

# Advanced DaemonSet monitoring configuration
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: daemonset-scheduling-alerts
  namespace: kube-system
  labels:
    app: daemonset-monitoring
spec:
  groups:
  - name: daemonset.scheduling
    rules:
    - alert: DaemonSetPodsNotScheduled
      expr: |
        (
          kube_daemonset_status_desired_number_scheduled
          -
          kube_daemonset_status_number_ready
        ) > 0
      for: 5m
      labels:
        severity: warning
        component: scheduling
      annotations:
        summary: "DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} has unscheduled pods"
        description: "DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} has {{ $value }} pods that are not scheduled on nodes for more than 5 minutes"
        runbook_url: "https://runbooks.company.com/daemonset-scheduling"

    - alert: DaemonSetSchedulingStuck
      expr: |
        (
          kube_daemonset_status_desired_number_scheduled
          -
          kube_daemonset_status_number_ready
        ) > 0
      for: 30m
      labels:
        severity: critical
        component: scheduling
      annotations:
        summary: "DaemonSet scheduling stuck for {{ $labels.namespace }}/{{ $labels.daemonset }}"
        description: "DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} has been unable to schedule pods for more than 30 minutes"

    - alert: NodeWithoutDaemonSetPods
      expr: |
        (
          count by (node) (kube_node_info{node=~".+"})
          unless
          count by (node) (kube_pod_info{created_by_kind="DaemonSet", node=~".+"})
        ) > 0
      for: 10m
      labels:
        severity: warning
        component: scheduling
      annotations:
        summary: "Node {{ $labels.node }} missing DaemonSet pods"
        description: "Node {{ $labels.node }} does not have any DaemonSet pods scheduled"

    - alert: DaemonSetUpdateStuck
      expr: |
        (
          kube_daemonset_status_desired_number_scheduled
          -
          kube_daemonset_status_updated_number_scheduled
        ) > 0
      for: 15m
      labels:
        severity: warning
        component: rollout
      annotations:
        summary: "DaemonSet update stuck for {{ $labels.namespace }}/{{ $labels.daemonset }}"
        description: "DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} update has been stuck for more than 15 minutes"

---
# Automated DaemonSet health checker
apiVersion: batch/v1
kind: CronJob
metadata:
  name: daemonset-health-checker
  namespace: kube-system
spec:
  schedule: "*/5 * * * *"  # Every 5 minutes
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          serviceAccount: daemonset-health-checker
          containers:
          - name: health-checker
            image: bitnami/kubectl:latest
            command: ["/bin/bash"]
            args:
            - -c
            - |
              set -euo pipefail

              echo "🔍 Starting DaemonSet health check"

              # Check all DaemonSets
              daemonsets=$(kubectl get daemonset -A -o json)

              # Find DaemonSets with scheduling issues
              problematic_ds=$(echo "$daemonsets" | jq -r '
                .items[] |
                select(.status.desiredNumberScheduled != .status.numberReady) |
                "\(.metadata.namespace),\(.metadata.name),\(.status.desiredNumberScheduled),\(.status.numberReady)"
              ')

              if [[ -n "$problematic_ds" ]]; then
                echo "⚠️  Found DaemonSets with scheduling issues:"
                echo "$problematic_ds" | while IFS=',' read -r namespace name desired ready; do
                  echo "  $namespace/$name: $ready/$desired ready"

                  # Check for common issues
                  # 1. Node taints
                  nodes_with_init_taint=$(kubectl get nodes -o json | jq -r '
                    .items[] |
                    select(.spec.taints[]? | select(.key == "node.cloudprovider.kubernetes.io/uninitialized")) |
                    .metadata.name
                  ')

                  if [[ -n "$nodes_with_init_taint" ]]; then
                    echo "    Found nodes with initialization taint: $nodes_with_init_taint"

                    for node in $nodes_with_init_taint; do
                      node_ready=$(kubectl get node "$node" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
                      if [[ "$node_ready" == "True" ]]; then
                        echo "    Auto-removing initialization taint from ready node: $node"
                        kubectl taint node "$node" "node.cloudprovider.kubernetes.io/uninitialized:NoSchedule-" || echo "    Failed to remove taint"
                      fi
                    done
                  fi

                  # 2. Check for not ready nodes
                  not_ready_nodes=$(kubectl get nodes -o json | jq -r '
                    .items[] |
                    select(.status.conditions[] | select(.type=="Ready" and .status!="True")) |
                    .metadata.name
                  ')

                  if [[ -n "$not_ready_nodes" ]]; then
                    echo "    Found not ready nodes: $not_ready_nodes"
                  fi
                done
              else
                echo "✅ All DaemonSets are healthy"
              fi

              echo "🔍 DaemonSet health check completed"

---
# DaemonSet troubleshooting dashboard
apiVersion: v1
kind: ConfigMap
metadata:
  name: daemonset-troubleshooting-dashboard
  namespace: kube-system
data:
  dashboard.json: |
    {
      "dashboard": {
        "title": "DaemonSet Scheduling Health",
        "panels": [
          {
            "title": "DaemonSet Status Overview",
            "type": "stat",
            "targets": [
              {
                "expr": "kube_daemonset_status_desired_number_scheduled",
                "legendFormat": "Desired Pods"
              },
              {
                "expr": "kube_daemonset_status_number_ready",
                "legendFormat": "Ready Pods"
              }
            ]
          },
          {
            "title": "Scheduling Success Rate",
            "type": "gauge",
            "targets": [
              {
                "expr": "kube_daemonset_status_number_ready / kube_daemonset_status_desired_number_scheduled * 100",
                "legendFormat": "Success Rate %"
              }
            ]
          },
          {
            "title": "DaemonSet Pods per Node",
            "type": "heatmap",
            "targets": [
              {
                "expr": "count by (node) (kube_pod_info{created_by_kind=\"DaemonSet\"})",
                "legendFormat": "{{ node }}"
              }
            ]
          },
          {
            "title": "Node Taints",
            "type": "table",
            "targets": [
              {
                "expr": "kube_node_spec_taint",
                "legendFormat": "{{ node }} - {{ key }}"
              }
            ]
          },
          {
            "title": "Recent Scheduling Events",
            "type": "logs",
            "targets": [
              {
                "expr": "kube_pod_container_status_waiting_reason{reason=~\".*Scheduling.*|.*Taint.*\"}",
                "legendFormat": "Scheduling Issues"
              }
            ]
          }
        ]
      }
    }

---
# Automated recovery system
apiVersion: apps/v1
kind: Deployment
metadata:
  name: daemonset-recovery-controller
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: daemonset-recovery-controller
  template:
    metadata:
      labels:
        app: daemonset-recovery-controller
    spec:
      serviceAccount: daemonset-recovery-controller
      containers:
      - name: controller
        image: bitnami/kubectl:latest
        command: ["/bin/bash"]
        args:
        - -c
        - |
          set -euo pipefail

          echo "🤖 Starting DaemonSet recovery controller"

          while true; do
            echo "Checking for DaemonSet issues..."

            # Find DaemonSets with persistent scheduling issues
            problematic_ds=$(kubectl get daemonset -A -o json | jq -r '
              .items[] |
              select(
                .status.desiredNumberScheduled != .status.numberReady and
                (.metadata.labels["recovery.disabled"] // "false") != "true"
              ) |
              "\(.metadata.namespace),\(.metadata.name)"
            ')

            if [[ -n "$problematic_ds" ]]; then
              echo "Found problematic DaemonSets, initiating recovery..."

              echo "$problematic_ds" | while IFS=',' read -r namespace name; do
                echo "Processing DaemonSet: $namespace/$name"

                # Apply common fixes
                # 1. Remove initialization taints from ready nodes
                ready_nodes_with_init_taint=$(kubectl get nodes -o json | jq -r '
                  .items[] |
                  select(
                    (.spec.taints[]? | select(.key == "node.cloudprovider.kubernetes.io/uninitialized")) and
                    (.status.conditions[] | select(.type=="Ready" and .status=="True"))
                  ) |
                  .metadata.name
                ')

                for node in $ready_nodes_with_init_taint; do
                  echo "Removing initialization taint from node: $node"
                  kubectl taint node "$node" "node.cloudprovider.kubernetes.io/uninitialized:NoSchedule-" || echo "Failed to remove taint"
                done

                # 2. Restart DaemonSet if no progress for extended time
                last_update=$(kubectl get daemonset "$name" -n "$namespace" -o jsonpath='{.status.observedGeneration}' || echo "0")
                creation_time=$(kubectl get daemonset "$name" -n "$namespace" -o jsonpath='{.metadata.creationTimestamp}')

                # Simple restart trigger (can be enhanced with more sophisticated logic)
                echo "Triggering DaemonSet restart for: $namespace/$name"
                kubectl patch daemonset "$name" -n "$namespace" -p '{"spec":{"template":{"metadata":{"annotations":{"kubectl.kubernetes.io/restartedAt":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}}}}}'

                # 3. Add annotation to prevent immediate re-processing
                kubectl annotate daemonset "$name" -n "$namespace" \
                  "recovery.processed=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
                  --overwrite

                sleep 10
              done
            else
              echo "All DaemonSets appear healthy"
            fi

            # Wait before next check
            sleep 300  # 5 minutes
          done

Enterprise Integration and Compliance

Comprehensive Audit and Compliance Framework

Implement enterprise-grade audit and compliance for DaemonSet operations:

# DaemonSet compliance and audit configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: daemonset-compliance-config
  namespace: kube-system
data:
  compliance-requirements.yaml: |
    security_requirements:
      pod_security_standards:
        - "All DaemonSets must comply with restricted PSS"
        - "Security contexts must be properly configured"
        - "Non-root containers required where possible"

      network_security:
        - "Network policies must be defined for DaemonSet pods"
        - "Host networking limited to essential components"
        - "Port access restricted to necessary services"

      resource_management:
        - "Resource requests and limits must be specified"
        - "QoS class must be appropriate for workload"
        - "Node resource consumption monitored"

    operational_requirements:
      scheduling_constraints:
        - "Critical DaemonSets must tolerate all node taints"
        - "Node selectors must be justified and documented"
        - "Scheduling policies must prevent resource conflicts"

      lifecycle_management:
        - "Rolling update strategies must be configured"
        - "Health checks must be implemented"
        - "Graceful termination must be supported"

      monitoring_requirements:
        - "Resource usage must be monitored"
        - "Scheduling health must be tracked"
        - "Performance metrics must be collected"

---
# Automated compliance checker
apiVersion: batch/v1
kind: CronJob
metadata:
  name: daemonset-compliance-checker
  namespace: kube-system
spec:
  schedule: "0 6 * * *"  # Daily at 6 AM
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          serviceAccount: daemonset-compliance-checker
          containers:
          - name: compliance-checker
            image: bitnami/kubectl:latest
            command: ["/bin/bash"]
            args:
            - -c
            - |
              set -euo pipefail

              echo "🔍 Starting DaemonSet compliance check"

              compliance_report="/tmp/daemonset-compliance-$(date +%Y%m%d).json"

              # Initialize report
              cat > "$compliance_report" <<EOF
              {
                "report_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
                "cluster": "$(kubectl config current-context)",
                "compliance_checks": {
                  "security": {},
                  "resource_management": {},
                  "scheduling": {},
                  "monitoring": {}
                },
                "violations": [],
                "summary": {}
              }
              EOF

              # Get all DaemonSets
              daemonsets=$(kubectl get daemonset -A -o json)

              total_ds=$(echo "$daemonsets" | jq '.items | length')
              compliant_ds=0
              violations=0

              echo "$daemonsets" | jq -c '.items[]' | while read -r ds; do
                namespace=$(echo "$ds" | jq -r '.metadata.namespace')
                name=$(echo "$ds" | jq -r '.metadata.name')

                echo "Checking compliance for: $namespace/$name"

                # Security compliance checks
                security_context=$(echo "$ds" | jq -r '.spec.template.spec.securityContext // {}')
                containers=$(echo "$ds" | jq -r '.spec.template.spec.containers[]')

                # Check for non-root containers
                root_containers=$(echo "$containers" | jq -r 'select(.securityContext.runAsUser == 0 or .securityContext.runAsUser == null)')
                if [[ -n "$root_containers" ]]; then
                  echo "  ⚠️  Running as root user"
                  violations=$((violations + 1))
                fi

                # Resource management checks
                containers_without_resources=$(echo "$containers" | jq -r 'select(.resources.requests == null or .resources.limits == null)')
                if [[ -n "$containers_without_resources" ]]; then
                  echo "  ⚠️  Missing resource requests/limits"
                  violations=$((violations + 1))
                fi

                # Scheduling checks
                tolerations=$(echo "$ds" | jq -r '.spec.template.spec.tolerations // []')
                if [[ "$tolerations" == "[]" ]]; then
                  echo "  ⚠️  No tolerations specified (may not schedule on all nodes)"
                fi

                # Health check compliance
                liveness_probe=$(echo "$containers" | jq -r 'select(.livenessProbe != null)')
                readiness_probe=$(echo "$containers" | jq -r 'select(.readinessProbe != null)')

                if [[ -z "$liveness_probe" ]]; then
                  echo "  ⚠️  Missing liveness probe"
                  violations=$((violations + 1))
                fi

                if [[ -z "$readiness_probe" ]]; then
                  echo "  ⚠️  Missing readiness probe"
                  violations=$((violations + 1))
                fi

                echo "  ✅ Compliance check completed for $namespace/$name"
              done

              # Generate final report
              echo ""
              echo "📊 Compliance Summary"
              echo "===================="
              echo "Total DaemonSets: $total_ds"
              echo "Compliance violations: $violations"

              if [[ $violations -eq 0 ]]; then
                echo "✅ All DaemonSets are compliant"
              else
                echo "⚠️  Compliance violations detected"
              fi

              echo "📄 Detailed report: $compliance_report"

---
# Service accounts and RBAC for compliance tools
apiVersion: v1
kind: ServiceAccount
metadata:
  name: daemonset-health-checker
  namespace: kube-system

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: daemonset-recovery-controller
  namespace: kube-system

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: daemonset-compliance-checker
  namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: daemonset-management
rules:
- apiGroups: [""]
  resources: ["nodes", "pods", "events"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["daemonsets"]
  verbs: ["get", "list", "watch", "patch", "update"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["patch"]  # For removing taints

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: daemonset-health-checker
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: daemonset-management
subjects:
- kind: ServiceAccount
  name: daemonset-health-checker
  namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: daemonset-recovery-controller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: daemonset-management
subjects:
- kind: ServiceAccount
  name: daemonset-recovery-controller
  namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: daemonset-compliance-checker
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: daemonset-management
subjects:
- kind: ServiceAccount
  name: daemonset-compliance-checker
  namespace: kube-system

Conclusion

Kubernetes DaemonSet scheduling troubleshooting requires systematic diagnostic approaches that examine the complete scheduling pipeline, from node conditions and taints to resource availability and network constraints. By implementing the comprehensive diagnostic frameworks, automated monitoring systems, and enterprise-grade compliance tools outlined in this guide, platform engineering teams can effectively prevent, diagnose, and resolve complex DaemonSet scheduling issues in production environments.

The key to successful DaemonSet management lies in proactive monitoring, automated remediation of common issues, and maintaining comprehensive audit trails that support both operational efficiency and regulatory compliance. As Kubernetes clusters grow in complexity and scale, these systematic approaches become increasingly critical for maintaining reliable infrastructure services that depend on DaemonSet deployments.

Regular testing of diagnostic procedures, continuous improvement of automation systems, and thorough documentation of resolution strategies ensure your Kubernetes infrastructure remains resilient and capable of supporting mission-critical workloads that depend on consistent DaemonSet scheduling across all cluster nodes.