Skip to content

5.1. Troubleshooting Guide


Failure Checklist

When a failure occurs, checking in the following order is recommended.

  1. Determine the scope of impact: whether the whole cluster has failed, or a particular node, namespace, or application
  2. Check node state: carry out the Checking Node State procedure
  3. Check the state of the core cluster components: the API server, etcd, CoreDNS, and so on
  4. Check recent changes: whether there has been a recent deployment, configuration change, or upgrade
  5. Check logs and events: the logs of the pods involved, and the cluster events
  6. Check the MSAP Observability dashboards: narrow the range of causes from the metric trends
  7. Contact the technical support team if needed

Checking Node State

# Check the state of all nodes
kubectl get nodes -o wide

# Details of a particular node (conditions, allocated resources, and so on)
kubectl describe node <node-name>

# Check the node service state (run directly on each node)
systemctl status rke2-server # Master
systemctl status rke2-agent # Worker

# Check the kubelet state
systemctl status kubelet

Node NotReady

  1. Check the conditions (MemoryPressure, DiskPressure, PIDPressure, Ready) with kubectl describe node <node-name>
  2. Connect to the node over SSH and check systemctl status rke2-server (or rke2-agent)
  3. Check whether disk or memory is short (see Handling Failures by Component)
  4. Restart the service if needed
    systemctl restart rke2-agent # for a Worker node

Checking Cluster Component State

OPENMARU COP is based on RKE2, so component health is judged from the state of the system services and the core pods.

# Whether the API server is reachable
kubectl get --raw='/readyz?verbose'

# Check the API server listening port (on a Master node)
ss -tlnp | grep 6443

# etcd cluster state (on a Master node, running etcdctl inside the etcd static pod)
# The host has no etcdctl binary, so run it inside the etcd pod with kubectl exec.
kubectl exec -n kube-system etcd-<master-node> -- etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/var/lib/rancher/rke2/server/tls/etcd/server-ca.crt \
--cert=/var/lib/rancher/rke2/server/tls/etcd/server-client.crt \
--key=/var/lib/rancher/rke2/server/tls/etcd/server-client.key \
endpoint status --cluster -w table

# Check the CoreDNS state
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl run -it --rm debug -n kube-system --image=busybox --restart=Never -- nslookup kubernetes.default

# List unhealthy pods across all namespaces
kubectl get pods -A | grep -v Running

# Check recent cluster events
kubectl get events -A --sort-by='.lastTimestamp' | tail -20

Checking Node Logs

# The RKE2 service log (Master)
journalctl -u rke2-server -f

# The RKE2 service log (Worker)
journalctl -u rke2-agent -f

# Check node resource pressure from pod events
kubectl get events --field-selector reason=Evicted -A

# Check disk usage and clean up unused images
df -h
crictl rmi --prune
journalctl --vacuum-size=1G

Checking the Web Console Dashboard

Check the following first on the main dashboard of the OPENMARU COP Console.

  1. The node state doughnut chart: whether there are NotReady nodes
  2. The pod state doughnut chart: the proportion of pods in Pending/CrashLoopBackOff/Error
  3. The recent event list: events at warning level
  4. The CPU/memory gauges: whether resources are exhausted

When the console itself cannot be reached (a 502 or 504 error), also check Handling Failures by Component - Ingress 502/503.


Handling Failures by Component

SymptomWhat to checkResolution
No communication between podsThe state of the CNI (Canal/Calico) pods, the VXLAN port (4789)Restart the CNI pods, check the VXLAN port in the firewall and security groups
A service is unreachableWhether endpoints exist, the kube-proxy stateCheck the backend pod connection with kubectl get endpoints
No external communicationDNS, NAT, the firewallCheck the node routing table and the firewall policy
A PVC stays PendingThe storage class, the NFS Provisioner stateCheck the events with kubectl describe pvc; check whether the NFS mount is possible with showmount -e <nfs-server>
An NFS mount fails (access denied)The /etc/exports configuration, the firewallCheck the allowed IP ranges on the NFS server
A PV is stuck in TerminatingThe finalizerkubectl patch pv <name> -p '{"metadata":{"finalizers":null}}' (⚠️ whether the storage is actually deleted has to be confirmed separately)
Ingress 502/503The backend pod state, the readiness probeCheck whether the target pod is Ready
A TLS certificate errorWhether the secret exists, its expiry datekubectl get secret <tls-secret> -n <ns> -o yaml, check the cert-manager renewal state
ImagePullBackOffThe ImagePullSecret, registry reachabilityCheck the exact error message in the events from kubectl describe pod
CrashLoopBackOffThe application logCheck the cause of the previous exit with kubectl logs <pod> --previous
OOMKilledThe memory limitConfirm OOMKilled in kubectl describe pod and raise resources.limits.memory
A pod stays Pending (cannot be scheduled)Taints and tolerations, the node selector, insufficient resourcesCheck the reason for the scheduling failure in the Events of kubectl describe pod
Node MemoryPressureExcessive node memory usageSee Handling a Memory Shortage (MemoryPressure) below

Handling a Memory Shortage (MemoryPressure)

# 1. Check the node memory usage
free -h

# 2. List pods sorted by memory usage (across the cluster)
kubectl top pod -A --sort-by=memory

# 3. Check the memory limit configured per pod
kubectl get pods -A -o custom-columns=\
'NAME:.metadata.name,MEM:.spec.containers[*].resources.limits.memory'

# 4. Clean up unnecessary pods and pods holding excessive memory
kubectl delete pod <pod-name> -n <namespace>

When a node enters MemoryPressure, Kubernetes can automatically evict pods, starting with the lowest priority. Check the list of evicted pods as follows.

kubectl get events --field-selector reason=Evicted -A

Handling Failures by Service

ServiceTypical symptomAction
GitLabThe service fails to startdocker exec -it gitlab gitlab-ctl reconfigure, and gitlab-ctl restart if needed
GitLabA 500 errorRerun the Rails cache and database migration
GitLabGit push/pull fails (Permission denied, Unable to create temporary file)Check the disk space with docker exec -it gitlab df -h; if short, clean up with gitlab-rake gitlab:cleanup:orphan_job_artifact_files; for a permission problem, chown -R git:git /var/opt/gitlab/git-data/repositories/
JenkinsA build fails (DinD/Kaniko)Check the build agent pod log and the PVC mount state
HarborPush/pull failsRetry docker login; check the containerd registry trust configuration on the node (the registry.{sub_domain}.{domain}.{TLD}:8443 entry and the insecure_skip_verify value in /etc/rancher/rke2/registries.yaml)
HarborA vulnerability scan failsCheck whether the Trivy database is up to date
ArgoCDSign-in failsSign in again with the value of argocd-initial-admin-secret
ArgoCDSynchronization failsReconnect the repository and force a synchronization (argocd app sync <app> --force)
KeycloakSSO sign-in failsCheck the client redirect URI configuration
KeycloakLDAP integration failsCheck the LLDAP service state and the network connection
KeycloakToken or session expiry (Token expired, Session has expired)Extend the Access Token Lifespan and SSO Session Max under Realm Settings > Tokens in the Keycloak Admin Console, or adjust them from the CLI with kcadm.sh update realms/openmaru -s accessTokenLifespan=1800 -s ssoSessionMaxLifespan=86400
OPENMARU COP ConsoleUnreachable (502)Check the Console pod and Ingress state
OPENMARU COP ConsoleConnection to the cluster failsCheck the validity of the RBAC and ServiceAccount token
MSAP ObservabilityLogs are not collectedCheck the Fluent Bit DaemonSet state with kubectl get pods -n openmaru-logging -l app.kubernetes.io/name=fluent-bit; check the OpenTelemetry Collector state (kubectl get pods -n openmaru-observ -l app.kubernetes.io/name=openmaru-observ-otel-collector) and its health check (wget -qO- http://localhost:13133/health)
MSAP ObservabilityA dashboard does not load, or a data source errorCheck the state of all pods with kubectl get pods -n openmaru-observ; check ClickHouse (-l app.kubernetes.io/name=openmaru-observ-clickhouse) and, if needed, kubectl rollout restart statefulset/openmaru-observ-server -n openmaru-observ

Keycloak token and session expiry - the Console screen: In the Keycloak Admin Console, select the target realm (openmaru) and check or extend the Access Token Lifespan value on the Realm settings > Tokens tab. (SSO Session Max is on the Sessions tab of the same screen.)

Keycloak Realm settings - Tokens

Handling GPU Failures

These are the failures that occur in an environment with GPU nodes, and what to do about them.

Actions by Symptom

SymptomCauseAction
A GPU pod stays PendingThe device is already held by another workloadCheck what is holding it with kubectl get resourceclaims -A. If the aim is sharing, change it to reference the ResourceClaim by name
A GPU pod stays Pending with cannot allocate all claimsDevice partitioning is off, so one claim holds the whole deviceCheck the device's allowMultipleAllocations and the cluster feature gate
The pod is Running but GPU computation failsThe device was not injected into the containerCheck nvidia-smi -L inside the pod. If the list is empty, check the driver and device injection configuration
A workload terminates suddenlyAnother workload on the same GPU used all the memoryGPU memory is not physically divided. Rebalance the total memory of the workloads running together
The node does not show a GPUA problem with the driver or the GPU OperatorCheck the state of the components with kubectl get pods -n gpu-operator
The device list (resourceslices) is emptyA problem with the DRA driverCheck the kubelet plugin state with kubectl get pods -n nvidia-dra-driver-gpu

A Problem with the DRA Driver kubelet Plugin

This is the case where, after raising the driver version, the plugin is in CrashLoopBackOff and the log shows the following.

Error: error creating driver: unable to get checkpoint: checkpoint is corrupted

The checkpoint file left by the previous version is not compatible with the new one. It happens only on that node; nodes with no record of device allocation are unaffected.

Caution: When the plugin does not work, pods that were using the GPU get stuck in Terminating. There is nothing left to clean the device up.

# 1) Empty the GPU workloads from that node
kubectl scale deploy -n <namespace> <workload> --replicas=0

# 2) Back up the checkpoint and delete it
ssh root@<node> 'cp -a /var/lib/kubelet/plugins/gpu.nvidia.com/checkpoint.json \
/tmp/checkpoint.json.bak-$(date +%H%M%S) && \
rm -f /var/lib/kubelet/plugins/gpu.nvidia.com/checkpoint.json'

# 3) Recreate the plugin pod
kubectl delete pod -n nvidia-dra-driver-gpu \
-l app.kubernetes.io/name=dra-driver-nvidia-gpu \
--field-selector spec.nodeName=<node>

# 4) Restore the workload
kubectl scale deploy -n <namespace> <workload> --replicas=1

When Time-slicing Configuration Is Left Behind

Even after time-slicing is turned off, the configuration can remain in three places and keep working. The GPU Operator installation script checks for this and reports it, and the cleanup order has to be kept.

Caution: Deleting the ConfigMap first leaves a volume reference in the DaemonSet and the pod cannot start (MountVolume.SetUp failed). Empty the ClusterPolicy first.

kubectl patch clusterpolicy cluster-policy --type=merge \
-p '{"spec":{"devicePlugin":{"config":{"name":"","default":""}}}}'
kubectl label node <node> nvidia.com/device-plugin.config-
kubectl delete cm time-slicing-config-all -n gpu-operator
kubectl rollout restart ds/nvidia-device-plugin-daemonset ds/gpu-feature-discovery -n gpu-operator

Caution: After the cleanup, the GPU count the node advertises drops, so some of the pods that were using that GPU become Pending. Check the workloads before doing this and secure a maintenance window.


Restoring from a Master Backup (etcd)

OPENMARU COP backs up and restores the cluster state (all Kubernetes resource definitions) through etcd snapshots.

Creating a Snapshot (Scheduled Backup)

rke2 etcd-snapshot save --name <snapshot-name>

# List the saved snapshots
rke2 etcd-snapshot ls

ℹ️ Note: The scheduled backup can be automated at installation time through the backup-related settings in env.yaml.

Restoring from a Snapshot

🚨 Warning: This work returns the entire cluster state to the moment of the snapshot and cannot be undone. Always create an additional snapshot of the current state before proceeding.

  1. Stop the RKE2 service on the Master node to be restored

    systemctl stop rke2-server
  2. Rebuild the cluster from the snapshot

    rke2 server --cluster-reset --cluster-reset-restore-path=<snapshot-path>
  3. Restart the RKE2 service

    systemctl start rke2-server
  4. Check whether the remaining Master nodes have to rejoin the cluster (usually they rejoin after their data directory is cleared)

  5. Verify after the restore

    kubectl get nodes -o wide
    kubectl get pods -A | grep -v Running

⚠️ Caution: --cluster-reset is a last resort. Where possible, first try to bring things back with the Node NotReady and Checking Cluster Component State procedures, and carry out the etcd restore only when recovery is impossible. Discussing it with the technical support team before starting is recommended.