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.
| Tier | Bộ nhớ | Giới hạn tổng hợp lý cho container |
|---|---|---|
| VDS-1 | 2 GB | tối đa 1.5 GB |
| VDS-2 | 4 GB | tối đa 3 GB |
| VDS-3 | 8 GB | tối đa 6.5 GB |
| VDS-4 | 16 GB | tối đa 14 GB |
| VDS-5 | 24 GB | tối đa 21 GB |
| VDS-6 | 32 GB | tố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.
htopvàbtoptoà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ùngdocker stats --no-streamvà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-stoppedvà mộthealthcheck— 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.