Skip to content
VDS · Docker và container

Giới hạn bộ nhớ và CPU cho container

Cách đặt mức trần bộ nhớ và CPU cho một container, tại sao nếu không có nó thì một dịch vụ làm sập tất cả các dịch vụ khác, và cách nhận biết một tiến trình bị kernel kill.

Cập nhật 23 tháng 8, 2026

Mặc định, một container có thể chiếm toàn bộ bộ nhớ và toàn bộ số nhân trên máy. Trên VDS-1 với hai gigabyte, điều này kết thúc theo cách dễ đoán: một dịch vụ phình to, kernel bắt đầu kill các tiến trình, và thứ sập không phải nó mà là cơ sở dữ liệu bên cạnh.

Cách đặt giới hạn

services:
  app:
    image: ghcr.io/example/app:1.5.0
    deploy:
      resources:
        limits:
          memory: 768M
          cpus: "1.0"
        reservations:
          memory: 256M

Compose áp dụng deploy.resources.limits ngay cả với một lệnh docker compose up -d đơn giản. Tương đương cho docker run:

docker run -d --memory 768m --cpus 1.0 --memory-swap 768m <image>

Đặt --memory-swap bằng --memory sẽ cấm swap: một cú crash thẳng thắn vẫn tốt hơn một cái máy gần như đứng yên suốt nhiều giờ.

Nên cấp bao nhiêu

Hãy bắt đầu từ tier của bạn và chừa lại một chút dư địa cho hệ thống.

TierBộ nhớGiới hạn tổng hợp lý cho container
VDS-12 GBtối đa 1.5 GB
VDS-24 GBtối đa 3 GB
VDS-38 GBtối đa 6.5 GB
VDS-416 GBtối đa 14 GB
VDS-524 GBtối đa 21 GB
VDS-632 GBtối đa 29 GB

Phần còn lại là thứ hệ thống, bộ đệm tệp và chính Docker cần. Tổng các giới hạn lớn hơn lượng bộ nhớ không phải là một lỗi cấu hình — đó là một thảm họa đang chờ xảy ra.

Về CPU: cpus: "1.0" là một nhân đầy đủ. VDS-1 chỉ có một nhân, nên giới hạn CPU ở đó chẳng có mấy ý nghĩa, nhưng trên VDS-4 trở lên thì đáng để giữ cho cấu hình máy chủ không chiếm hết cả sáu nhân.

Thực tế tiêu tốn bao nhiêu

docker stats --no-stream
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}"
free -h

Theo dõi dịch vụ trong một ngày dưới tải và đặt giới hạn vào khoảng một lần rưỡi mức đỉnh. Một giới hạn quá chặt còn tệ hơn không có: dịch vụ sẽ khởi động lại đúng lúc bạn cần nó nhất.

htop và btop toàn màn hình chỉ hoạt động trong console “Screen” (VNC). Console văn bản không truyền kích thước cửa sổ, ở đó luôn là 80×24, và giao diện sẽ vỡ tan. Để đo nhanh trong console văn bản, hãy dùng docker stats --no-stream và free -h.

Cách nhận biết nó bị kill vì bộ nhớ

docker inspect -f '{{.State.ExitCode}} {{.State.OOMKilled}}' <container>
sudo dmesg -T | grep -i -E "out of memory|killed process"

Mã thoát 137 cùng với OOMKilled: true là một phán quyết rõ ràng. Từ đó bạn có hai lựa chọn: nâng giới hạn nếu nó được đặt quá thấp, hoặc tìm hiểu vì sao ứng dụng cứ tiếp tục phình ra — một rò rỉ bộ nhớ không được chữa khỏi bằng cách thêm bộ nhớ, chỉ bị trì hoãn mà thôi.

Java và những trường hợp đặc biệt khác

Máy ảo Java đôi khi vẫn nhìn thấy bộ nhớ của máy chủ thay vì giới hạn của container, và định cỡ heap với phần dư địa vốn không tồn tại. Hãy đặt nó một cách tường minh:

environment:
  JAVA_TOOL_OPTIONS: "-Xmx512m -Xms256m"

Điều tương tự cũng áp dụng cho PostgreSQL (shared_buffers) và bất kỳ dịch vụ nào có pool riêng.

Những lỗi thường gặp

  • Hoàn toàn không đặt giới hạn. Nguyên nhân phổ biến nhất của “cái máy đơ cứng, không gì phản hồi”.
  • Có giới hạn, nhưng không có health check. Container bị kill và không bao giờ khởi động lại. Hãy thêm restart: unless-stopped và một healthcheck — xem cập nhật container.
  • Bạn quên mất đĩa. Bạn đã giới hạn bộ nhớ, nhưng các thao tác ghi lại đụng trần: xem tốc độ đĩa.