จัดการ RAM ของ Docker (Windows / WSL2)

อาการที่เจอ

  • เปิด Docker Desktop แล้ว process vmmem / vmmemWSL กิน RAM เกือบทั้งเครื่อง
  • ปิด container หมดแล้ว RAM ก็ยังไม่คืน
  • build ใน container ตายเงียบ ๆ ไม่มี error ชัดเจน (exit code 137 = ถูก OOM killer ฆ่า)
  • build ช้าผิดปกติ เหมือนค้าง ทั้งที่ CPU ไม่เต็ม

สาเหตุ: บน Windows Docker Desktop รันบน WSL2 ซึ่ง VM ตัวนี้จะขยาย RAM ไปเรื่อย ๆ จนถึงเพดาน default (สูงสุด ~50-80% ของ RAM เครื่อง) และไม่คืนให้ Windows

วิธีแก้: ไฟล์ .wslconfig

สร้าง/แก้ไฟล์ C:\Users\<username>\.wslconfig (พิมพ์ %USERPROFILE% ใน File Explorer เพื่อไปที่โฟลเดอร์)

[wsl2]
memory=16GB
processors=16
swap=8GB
autoMemoryReclaim=gradual
ค่าความหมาย
memoryเพดาน RAM ที่ WSL2 (และ Docker ทั้งหมด) ใช้ได้
processorsจำนวน CPU core ที่ให้ WSL2
swapswap file ของ WSL2 — กัน OOM ตอน build หนัก
autoMemoryReclaim=gradualคืน RAM ที่ไม่ได้ใช้ให้ Windows อัตโนมัติ (ค่านี้แก้อาการ “ปิด container แล้ว RAM ไม่คืน”)

หลังแก้ไฟล์ ต้อง restart WSL:

wsl --shutdown

แล้วเปิด Docker Desktop ใหม่ ค่าจึงมีผล (แก้ไฟล์เฉย ๆ ไม่พอ)

เลือกค่าเท่าไหร่ดี

  • memory ≈ 50-75% ของ RAM เครื่อง — เหลือให้ Windows + IDE + browser อย่างน้อย 8GB
    • เครื่อง 32GB → memory=16GB ถึง 20GB
    • เครื่อง 16GB → memory=8GB ถึง 10GB
  • processors ตั้งเท่าจำนวน core จริงได้ ไม่ใช่ตัวที่ทำให้เครื่องอืด (RAM คือตัวปัญหา)
  • swap เผื่อไว้ครึ่งหนึ่งของ memory — ช้ากว่า RAM แต่ดีกว่าโดน OOM kill

ตรวจสอบว่าค่ามีผลจริง

wsl -- free -h        # ดูว่า total ตรงกับที่ตั้งไว้

หรือดู process vmmemWSL ใน Task Manager ว่าเพดานหยุดตามที่ตั้ง

จำกัด RAM ราย container

.wslconfig คุมภาพรวม ถ้าอยากกันไม่ให้ container ตัวเดียวกินหมด:

docker run -m 4g --memory-swap 6g <image>

ใน docker-compose.yml:

services:
  app:
    mem_limit: 4g

กับดักที่เจอบ่อย

1. Node.js heap ไม่เท่ากับ RAM ของ container

Node จำกัด heap ตัวเองแยกต่างหาก (default ~4GB) — เพิ่ม RAM ให้ container อย่างเดียวไม่พอ ถ้า build/test ตายด้วย JavaScript heap out of memory ต้องเพิ่มทั้งสองฝั่ง:

ENV NODE_OPTIONS=--max-old-space-size=8192

และ container ต้องมี RAM มากกว่าค่านี้ ไม่งั้นจะโดน OOM kill (exit 137) แทน

2. เปิด container หลายตัวพร้อมกันตอน build ใหญ่

build หนัก ๆ มักติดที่ การแย่ง CPU/disk ไม่ใช่ compute — มี dev server + database + service อื่น รันอยู่ด้วย build จะช้าลงหลายเท่าจนดูเหมือนค้าง ปิดตัวที่ไม่ใช้ก่อน build:

docker ps -q | xargs docker stop

3. Disk เต็มจาก volume ที่ไม่ได้ลบ

คนละเรื่องกับ RAM แต่มาคู่กัน — volume ที่ไม่มีใครใช้ไม่ถูกลบเอง สะสมได้เป็นร้อย GB

docker system df                       # ดูขนาดรวม (ช้ามากถ้า volume เยอะ)
docker volume ls
docker volume rm <name>                # ลบทีละตัวตามชื่อ

⚠️ ระวัง docker volume prune และ docker image prune -a — ถ้า stack ไม่ได้รันอยู่ ตอนนั้น volume/image ที่ยังใช้อยู่จะถูกนับเป็น “unused” แล้วโดนลบไปด้วย ให้ลบทีละชื่อจะปลอดภัยกว่า

อ้างอิง