Bí kíp giới hạn tài nguyên Docker: Đừng để một Container ‘kéo sập’ cả Server

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

Nỗi ám ảnh mang tên “Treo Server”

Cảnh tượng con server Linux đang chạy mượt bỗng dưng “đứng hình”, SSH không phản hồi, web báo lỗi 504 là nỗi ám ảnh của bất kỳ ai làm Ops. Mình từng nếm trái đắng khi một container Node.js bị memory leak, ngốn sạch 16GB RAM chỉ trong 10 phút. Kết quả là Kernel phải kích hoạt OOM (Out Of Memory) Kill, dọn dẹp luôn cả những tiến trình quan trọng khác để cứu vãn hệ thống.

Vấn đề nằm ở chỗ: Mặc định, Docker cho phép container xài xối xả tài nguyên host. Nếu không đặt “vòng kim cô” bằng Resource Limits, anh em đang tự đặt hệ thống vào tình thế nguy hiểm. Việc giới hạn này mang lại 3 lợi ích sát sườn:

  • Chặn đứng lỗi Noisy Neighbor: Không để một service “hâm dở” làm ảnh hưởng đến hàng xóm chung nhà.
  • Tối ưu hóa chi phí: Mình từng quản lý cluster 50+ node và việc đặt limit chuẩn giúp giảm 35% chi phí hạ tầng Cloud nhờ gom cụm container hiệu quả hơn.
  • Hệ thống luôn có khe thở: Đảm bảo máy chủ luôn dư tài nguyên cho các tác vụ quản trị và logging.

Cấu hình RAM (Memory Limits): Sống còn cho độ ổn định

RAM là thứ dễ cạn kiệt nhất. Trong Docker, anh em cần phân biệt rõ hai ngưỡng sau.

Hard Limit (–memory)

Đây là trần cuối cùng. Nếu container cố tình vượt qua con số này, nó sẽ bị Kernel “trảm” ngay lập tức. Thường mình sẽ đặt mức này gấp 1.5 lần mức sử dụng trung bình của app.

docker run -d --name production-api --memory="1g" nginx

Ví dụ trên ép app chỉ được phép chạm mốc tối đa 1GB RAM.

Soft Limit (–memory-reservation)

Đây là con số mang tính cam kết. Container có thể dùng quá ngưỡng này nếu server đang rảnh. Tuy nhiên, khi tài nguyên bắt đầu hụt, Docker sẽ ép container nhả RAM về đúng mức reservation.

docker run -d --name worker-app --memory="2g" --memory-reservation="512m" my-app

Cách cấu hình này rất linh hoạt: App chạy bình thường ở 512MB, nhưng lúc xử lý dữ liệu nặng có thể vọt lên 2GB mà không lo bị kill.

Kiểm soát sức mạnh CPU

CPU khác RAM ở chỗ: Nếu vượt mức, container chỉ bị chậm lại (throttling) chứ không chết. Nhưng nếu để một container chiếm 100% CPU liên tục, toàn bộ server sẽ lag điên cuồng.

Dùng tham số –cpus

Đây là cách trực quan nhất. Giả sử server có 8 core và anh em muốn giới hạn app dùng tối đa 2.5 core, hãy chạy:

docker run -d --name heavy-task --cpus="2.5" python-worker

CPU Shares (–cpu-shares)

Tham số này dùng để phân chia thứ bậc ưu tiên. Nếu app A đặt 1024 và app B đặt 512, khi cả hai cùng tranh giành CPU, app A sẽ được ưu tiên gấp đôi thời gian xử lý so với app B.

Đừng quên giới hạn Disk I/O (IOPS)

Nhiều anh em bỏ quên IOPS cho đến khi ổ cứng bị nghẽn cổ chai. Một container ghi log quá dày hoặc chạy database nặng có thể làm treo toàn bộ IO của máy chủ. Thực tế, mình luôn giới hạn tốc độ ghi cho các tác vụ backup hoặc crawler.

docker run -d --name backup-job \
  --device-write-bps /dev/sda:20mb \
  ubuntu-backup

Lệnh này khóa tốc độ ghi vào ổ cứng /dev/sda không quá 20MB/s, giúp hệ thống vẫn phản hồi tốt khi đang backup.

Triển khai chuẩn với Docker Compose

Trong môi trường thực tế, Docker Compose là công cụ chính. Từ bản 3, cấu hình tài nguyên nằm trong mục deploy. Đây là cấu hình mình thường dùng cho các service API:

version: '3.8'
services:
  backend-api:
    image: nodejs-api:v2.1
    deploy:
      resources:
        limits:
          cpus: '0.50' # Giới hạn nửa core
          memory: 1G
        reservations:
          cpus: '0.10'
          memory: 256M
    restart: unless-stopped

Giám sát và “Tra tấn” thử nghiệm

Đừng bao giờ đoán mò. Hãy dùng lệnh docker stats để xem trực tiếp mức độ tiêu thụ tài nguyên. Bạn sẽ thấy ngay cột MEM USAGE / LIMIT để biết app của mình đang tiêu tốn bao nhiêu % so với ngưỡng cho phép.

Thử nghiệm Stress Test

Để kiểm chứng, hãy dùng image progrium/stress để giả lập tình huống ngốn RAM. Nếu bạn giới hạn 200MB mà ép nó chạy 300MB, bạn sẽ thấy container bị kill ngay tắp lự. Việc này giúp mình tự tin hơn nhiều khi đẩy code lên Production.

Lời khuyên cuối: Đừng đợi server sập mới bắt đầu cấu hình. Hãy coi Resource Limits là một phần của quy chuẩn triển khai. Hãy bắt đầu với con số thoải mái, sau đó tinh chỉnh dần dựa trên dữ liệu thực tế từ docker stats.

Share: