Containers Advanced

Troubleshooting Kubernetes Pod OOMKilled on Windows WSL2 Ubuntu: Resource Limits Exceeded

Resolve Kubernetes Pod OOMKilled errors on WSL2 Ubuntu by analyzing resource limits, optimizing application memory, and adjusting WSL2 VM allocation.

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Resolve Kubernetes Pod OOMKilled errors on WSL2 Ubuntu by analyzing resource limits, optimizing application memory, and adjusting WSL2 VM allocation.

A Kubernetes Pod experiencing an OOMKilled (Out Of Memory Killed) state is a common headache for developers and system administrators alike, especially when running development or testing clusters on resource-constrained environments like Windows Subsystem for Linux 2 (WSL2) with Ubuntu. This guide provides a highly technical, step-by-step approach to diagnose and resolve such issues.

Symptom & Error Signature

When a Kubernetes pod is OOMKilled, it means the process inside the container attempted to use more memory than it was allocated, leading the kernel to terminate it. You'll typically observe pods repeatedly restarting or failing to transition to a Running state.

You might see the following in your terminal output:

$ kubectl get pods
NAME                       READY   STATUS         RESTARTS      AGE
my-app-pod-abcdefg-hijkl   0/1     OOMKilled      3 (4s ago)    2m
another-pod-123456-789ab   1/1     Running        0             5m

Detailed pod description will show the OOMKilled reason in the Last State of a container:

$ kubectl describe pod my-app-pod-abcdefg-hijkl
Name:         my-app-pod-abcdefg-hijkl
Namespace:    default
Priority:     0
Node:         my-k8s-node-wsl2/172.x.x.x
Start Time:   Thu, 13 Aug 2026 10:00:00 +0000
Labels:       app=my-app
Annotations:  <none>
Status:       Running
IP:           10.x.x.x
IPs:
  IP:  10.x.x.x
Containers:
  my-app:
    Container ID:  containerd://abcdef...
    Image:         my-registry/my-app:latest
    Image ID:      docker.io/my-registry/my-app@sha256:fedcba...
    Port:          8080/TCP
    Host Port:     0/TCP
    Limits:
      memory:  512Mi
    Requests:
      memory:  256Mi
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       OOMKilled
      Exit Code:    137
      Started:      Thu, 13 Aug 2026 10:02:10 +0000
      Finished:     Thu, 13 Aug 2026 10:02:11 +0000
    Ready:          False
    Restart Count:  3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-abcde (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  kube-api-access-abcde:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    Mode:                    420
QoS Class:                   Burstable
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute opExists for 300s
                             node.kubernetes.io/unreachable:NoExecute opExists for 300s
Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Warning  OOMKilled  3m (x4 over 3m)      kubelet            Container my-app was OOMKilled
  Warning  BackOff    2m45s (x5 over 3m)   kubelet            Back-off restarting failed container my-app in pod my-app-pod-abcdefg-hijkl

Within the WSL2 Ubuntu instance, if the OOM condition is severe enough to affect the entire VM, you might also find kernel OOM killer messages in dmesg:

$ dmesg -T | grep -i "oom-killer"
[Thu Aug 13 10:02:11 2026] oom-kill:constraint=CONSTRAINT_MEMCG,nodemask=(null),cpuset=/,mems_allowed=0
[Thu Aug 13 10:02:11 2026] Memory cgroup out of memory: Killed process 12345 (my-app-process) total-vm:xxxxkB, anon-rss:yyyykB, file-rss:zzzzkB, shmem-rss:0kB

Root Cause Analysis

The OOMKilled error indicates that a process within your Kubernetes Pod's container exhausted its allocated memory. This can stem from several underlying issues, often exacerbated in a WSL2 environment:

  1. Pod Resource Limits Misconfiguration: In Kubernetes, you define requests and limits for CPU and memory for each container. limits.memory specifies the maximum memory a container can use. If the application inside the container attempts to allocate memory beyond this limit, the Kubernetes kubelet will terminate the container with an OOMKilled status.

    • requests.memory: The minimum memory guaranteed to the container. The scheduler uses this for placement.
    • limits.memory: The maximum memory the container is allowed to use. Exceeding this triggers the OOM killer.
  2. Application Memory Leak or High Demand: The application itself might have a memory leak, inefficient memory usage, or simply require more memory than initially anticipated for its workload. This is especially common with applications that cache heavily, process large datasets, or have long-running connections.

  3. WSL2 VM Memory Constraints: The entire WSL2 virtual machine, which hosts your Ubuntu distribution and thus your Kubernetes cluster (e.g., K3s, Minikube, Docker Desktop's K8s), has its own memory allocation defined by the Windows host. If the sum of memory used by all processes within the WSL2 VM (including the Kubernetes control plane, Docker daemon, and all running containers) exceeds the WSL2 VM's allocated memory, the host's kernel OOM killer might step in to kill processes within WSL2, or the WSL2 environment itself might become unstable. This is configured via the .wslconfig file.

  4. Kubernetes Node OOM: If you're running a multi-node cluster (uncommon for a single WSL2 instance but possible with tools like K3s creating multiple "nodes" as containers), a specific node might be undersized, leading to resource starvation across multiple pods on that node.

Step-by-Step Resolution

Follow these steps to systematically diagnose and resolve the OOMKilled issue.

1. Inspect Pod & Node Resource Usage

First, confirm the configured memory limits for the problematic pod and check the overall resource usage on your Kubernetes node.

# Get current resource limits for the pod
kubectl describe pod <your-pod-name> | grep -A 5 "Limits:"

# Example output snippet:
#     Limits:
#       memory:  512Mi
#     Requests:
#       memory:  256Mi

# Check current memory usage of pods (requires Metrics Server installed)
kubectl top pod --all-namespaces

# Check current memory usage of nodes (requires Metrics Server installed)
kubectl top node

If kubectl top commands fail, ensure the Kubernetes Metrics Server is installed. For K3s, it's often enabled by default. For Minikube/Docker Desktop, you might need to enable it: minikube addons enable metrics-server kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

2. Analyze Container Logs and Events

Review the logs and events for clues about what the application was doing just before it was killed.

# Get logs from the last termination of the container
kubectl logs <your-pod-name> --previous

# If the pod keeps crashing, this might not show much.
# Get all events related to the pod for a wider context
kubectl get events --field-selector involvedObject.name=<your-pod-name>

Look for application-specific error messages, indications of heavy processing, or large data allocations right before the OOMKilled event.

3. Adjust Pod Resource Limits

If your application genuinely needs more memory or your limits.memory was set too conservatively, increase it.

# Example: my-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: my-registry/my-app:latest
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "512Mi" # Increase request as well
            cpu: "250m"
          limits:
            memory: "1Gi" # Increased memory limit
            cpu: "500m"

Apply the changes:

kubectl apply -f my-deployment.yaml

Simply increasing the limits.memory without understanding the actual memory usage patterns might just defer the problem or transfer the pressure to the entire WSL2 VM. It's a temporary fix if the application has a memory leak or poor resource management.

4. Monitor Application Memory Usage (Inside Container)

For more precise diagnostics, try to get inside the running container and observe memory usage in real-time. This is often challenging with OOMKilled pods, but if it runs for a short period, you might catch it.

  1. If the pod briefly runs:

    kubectl exec -it <your-pod-name> -- bash
    

    Once inside, use tools like free -h, top, or ps aux to observe memory consumption. If bash isn't available, try /bin/sh. You might need to install these tools if the container image is minimal (e.g., Alpine-based).

  2. Using debug containers (Kubernetes 1.23+):

    kubectl debug -it <your-pod-name> --image=ubuntu:latest --target=<container-name-in-pod>
    

    This creates a new ephemeral container that shares the process namespace with your failing container, allowing you to use debugging tools without modifying the original image.

5. Increase WSL2 Memory Allocation

This is critical for Kubernetes on WSL2. By default, WSL2 only uses a fraction of your system's RAM. If your K8s cluster and its workloads demand more, you need to explicitly allocate more memory to the WSL2 VM.

  1. Create or edit .wslconfig: Navigate to your Windows user profile directory: %UserProfile% (e.g., C:UsersYourUsername). Create a file named .wslconfig (if it doesn't exist) or edit it.

    ; .wslconfig
    [wsl2]
    memory=4GB          ; Limits the memory allocated to the WSL2 VM.
                        ; Example: 4GB, 8GB. Adjust based on your host RAM.
    processors=2        ; Limits the number of virtual processors given to the WSL2 VM.
                        ; Example: 2, 4.
    swap=2GB            ; How much swap space to add to the WSL2 VM.
    localhostForwarding=true ; Enable to access WSL2 services from Windows host.
    

    Setting memory too high in .wslconfig can starve your Windows host system, leading to overall system instability and poor performance. Choose a value that leaves ample RAM for Windows applications. A good rule of thumb is 50-75% of your total physical RAM, assuming your K8s workload is your primary use case.

  2. Shut down WSL2 and restart: Open PowerShell or Command Prompt as administrator and execute:

    wsl --shutdown
    

    Then, restart your WSL2 distribution (e.g., by opening Ubuntu terminal) and your Kubernetes cluster.

  3. Verify changes: Inside your WSL2 Ubuntu instance:

    free -h
    

    You should see the updated memory allocation.

6. Check WSL2 Ubuntu Kernel OOM Logs

Even after increasing WSL2 memory, if the OOMKilled persists, check the kernel logs within your WSL2 Ubuntu instance for direct OOM killer messages, which can give more context on what process was being targeted.

dmesg -T | grep -i "oom-killer|memory"

This output can reveal if the WSL2 kernel itself is killing processes (including the container runtime or kubelet) due to overall memory pressure within the VM, rather than just the Kubernetes cgroup limit.

7. Optimize Application Memory Usage

If increasing limits doesn't resolve the issue, or if you want a more robust solution, focus on the application itself:

  • Code Review & Profiling: Identify memory leaks, inefficient data structures, or unnecessary allocations in your application code. Tools like valgrind (C/C++), go tool pprof (Go), memory_profiler (Python), or Java profilers can be invaluable.
  • Garbage Collection Tuning: For languages like Java or Go, fine-tuning garbage collection parameters can reduce memory spikes.
  • Smaller Base Images: Using minimal base images (e.g., Alpine instead of Ubuntu or Debian) for your Docker containers can significantly reduce the container's memory footprint even before your application starts.
  • Caching Strategies: Implement efficient caching or offload heavy processing to external services if possible.

Consider using tools like Prometheus and Grafana within your Kubernetes cluster to monitor resource usage over time. This provides historical data and dashboards to identify trends and potential memory leaks proactively.

By systematically addressing both the Kubernetes resource configuration and the underlying WSL2 memory allocation, you can effectively troubleshoot and resolve OOMKilled issues for your pods running on Windows WSL2 Ubuntu.

👨‍💻

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

🛡️

Our Production Verification Guarantee

Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.