Root Cause Diagnosis
Docker exit code 137 indicates that a process inside the container was forcefully terminated by the Linux kernel’s Out-Of-Memory (OOM) Killer (SIGKILL signal 9 + offset 128). On low-memory ARM architectures (such as AWS Graviton t4g.nano/micro or Raspberry Pi 4 with 1GB–2GB RAM), page size differences (e.g., 64KB pages vs standard 4KB pages on x86) and higher memory overhead per allocation accelerate memory exhaustion under heavy I/O or multi-threaded build workloads. Without explicit swap space or container memory limits, system RAM exhausts quickly during intensive operations like npm build or GCC/Clang compilation, causing the kernel OOM killer to select the main Docker process.
Quick Fix
Create and enable a 2GB swap file immediately to prevent the host kernel from invoking the OOM killer on container processes:
sudo fallocate -l 2G /swapfile || sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
Verify swap is active:
free -h
Step-by-Step Resolution
Step 1: Make Swap Allocation Persistent
Ensure the swap space survives host reboots by updating /etc/fstab.
- Open the system file:
sudo nano /etc/fstab - Append the following entry to the end of the file:
/swapfile swap swap defaults 0 0
Step 2: Configure System Swappiness and Cache Pressure
Tune kernel memory management parameters in /etc/sysctl.conf to prioritize swap usage without causing severe thrashing on slow flash or EBS storage.
- Edit system runtime parameters:
sudo nano /etc/sysctl.conf - Add or update the following values:
vm.swappiness=20 vm.vfs_cache_pressure=50 - Apply settings immediately:
sudo sysctl -p
Step 3: Enforce Docker Resource Limits
Prevent a single container from consuming all system RAM and triggering host-wide memory panics.
Option A: Docker Compose
Add mem_limit or deployment resource constraints in docker-compose.yml:
version: '3.8'
services:
app:
image: my-arm-app:latest
deploy:
resources:
limits:
memory: 768M
reservations:
memory: 256M
# Optional fallback for v2 compose syntax:
# mem_limit: 768m
Option B: Docker CLI
Pass memory and swap parameters explicitly in the docker run command:
docker run -d \
--name arm_app \
--memory="768m" \
--memory-swap="1536m" \
my-arm-app:latest
Step 4: Limit Parallel Build Jobs (For Compiler/Build OOM Outages)
If Exit Code 137 occurs during build steps (e.g., docker build), restrict multi-core parallel worker instances that consume memory exponentially on ARM nodes.
- Node.js/npm: Set allocation flags in your Dockerfile:
ENV NODE_OPTIONS="--max-old-space-size=512" - Make/C++/Rust Compilation: Restrict build threads in your Dockerfile:
RUN make -j2 # Limit to 2 concurrent jobs instead of -j$(nproc)
Why This Fails for Some Users
- Btrfs or ZFS Filesystems:
fallocatefails on filesystems with copy-on-write (CoW) enabled (such as Btrfs on Fedora/Arch ARM images). You must useddto create the zero-filled file directly, disable CoW usingchattr +C /swapfile, and format before enabling. - Kernel Page Size Mismatch (64KB vs 4KB): Certain ARM kernel distributions (e.g., RHEL/CentOS on Graviton, Ubuntu 64k kernel variants) use a 64KB memory page size instead of 4KB. Memory allocations are rounded up to the nearest page size, increasing internal fragmentation and baseline RAM utilization by up to 20-30%.
- cgroup v2 Swap Controller Disabled: On Debian and Ubuntu ARM releases, cgroup memory swap accounting might be disabled by default in boot flags. If
docker run --memory-swapproduces a warning or fails, enable it in /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="systemd.unified_cgroup_hierarchy=1 cgroup_enable=memory swapaccount=1"Runsudo update-gruband reboot the host. - AWS EBS Burst Credit Exhaustion: Creating swap on burstable storage (e.g.,
gp2/gp3on EC2 instances) can lead to severe I/O throttling once burst credits deplete. If the kernel waits too long for swap I/O completion, the container may stall or trigger host-leve