Why Six Desktop Chrome Containers Locked a Production NAS: CPU WebGL Emulation, Btrfs D-State, and Offloading to iGPU
The storage appliance that stopped responding
The incident surfaced when reverse-proxied management dashboards and cloud drive services on a Synology DS1821+ NAS simultaneously timed out. Direct HTTPS handshakes succeeded and certificates matched, but backend requests hung indefinitely.
Opening an SSH terminal to the host revealed extreme resource exhaustion:
# uptime
09:42:15 up 42 days, 18:22, 1 user, load average: 27.42, 25.18, 22.04
# free -m
total used free shared buff/cache available
Mem: 7842 7410 112 340 320 180
Swap: 4096 3980 116
On a 4-core AMD Ryzen V1500B embedded platform, a load average above 27 meant that more than twenty processes were trapped in execution queues or uninterruptible kernel sleep. Memory was 94% utilized, and swap was almost completely exhausted.
The primary consumers were six desktop Chrome containers (lscr.io/linuxserver/chrome) hosting automation sessions for generative AI, document processing, and browser pipelines.
Anatomy of a Btrfs D-state freeze
The DS1821+ platform lacks an integrated GPU. Modern web applications—particularly canvas-heavy interfaces, document renderers, and video previews—rely heavily on WebGL. Without a hardware acceleration device passed through (/dev/dri), Chromium transparently falls back to CPU emulation using SwiftShader or llvmpipe.
This architectural mismatch created a three-stage cascade:
- CPU Saturation: Six headless/streaming browser instances ran software rasterization simultaneously, pegging all 4 physical cores at 100% utilization.
- Aggressive Swapping: As browser renderers allocated temporary graphic buffers, the kernel was forced to swap anonymous pages to mechanical spinning rust (
/volume1), introducing massive I/O wait. - Storage Transaction Lockup: When the container manager attempted to delete an ephemeral diagnostic container, the Docker daemon invoked a Btrfs subvolume deletion (
btrfs subvolume delete). Under saturated disk queues, the filesystem transaction stalled in kernel D-state (uninterruptible sleep).
Because the Btrfs root transaction lock was held, other system services—including local PostgreSQL instances, socket listeners, and reverse proxy workers—locked up as soon as they performed synchronous filesystem writes. The entire machine froze.
The migration: offloading to an Intel iGPU host
The long-term fix was to separate storage appliances from GPU-bound browser automation workloads.
The browser automation fleet was relocated to a dedicated unRaid compute server equipped with an Intel Core i9-13900K and an integrated Intel UHD Graphics 770 processor.
🔍 docker-compose.yml — iGPU hardware-accelerated Chrome worker (17 lines)
services:
chrome-worker:
image: lscr.io/linuxserver/chrome:latest
container_name: chrome-worker
devices:
- /dev/dri/renderD128:/dev/dri/renderD128
- /dev/dri/card0:/dev/dri/card0
environment:
- CHROME_CLI=--remote-debugging-port=9222 --user-data-dir=/config/profile --enable-features=VaapiVideoDecodeLinuxGL --ignore-gpu-blocklist --use-gl=angle --use-angle=gl
deploy:
resources:
limits:
memory: 3072M
restart: "no"
Passing /dev/dri/renderD128 enabled native hardware decoding and WebGL rendering directly on the silicon. Furthermore, changing container policy from restart: unless-stopped to an on-demand orchestration model ensured that idle worker browsers stay shut down at 0% CPU and 0 MB RAM until explicitly awakened by automation jobs.
The result
The impact on the storage appliance was immediate:
- Terminating the six soft-rendering containers on the NAS recovered 7.5 GB of committed memory (physical RAM + swap) and stopped swap thrashing.
- Host load average plunged from 27.42 down to 6.80 within minutes.
- Trapped Btrfs transactions committed cleanly, restoring cloud drive and portal responses to sub-second latencies.
- On the Intel compute node, automated browser workflows executed with native GPU hardware acceleration, reducing graphic-heavy script latency by more than 60%.
Dealing with flaky containers, cloud cost bloat, or unexplained outages?
Real production reliability comes from understanding the kernel and the protocol layers, not just restarting containers. I manage 162 containers across 3 hosts running 24/7 client workloads.