Sửa lỗi Killed và exit code 137 khi build Docker, Next.js
Giải thích exit code 137, SIGKILL, Linux OOM Killer và cách kiểm tra RAM, swap, Docker limit khi build Next.js hoặc Node.js trên VPS.
Mục lục bài viết
VPS & Hosting cho dự án của bạn
Khám phá các gói máy chủ và lưu trữ phù hợp từ website cá nhân đến ứng dụng production.
Bạn chạy:
npm run build
hoặc:
docker build .
Sau một lúc terminal chỉ hiện:
Killed
Docker có thể báo:
process exited with code 137
Exit code 137 thường liên quan tới process nhận SIGKILL. Trên VPS RAM thấp, nguyên nhân rất phổ biến là Linux OOM Killer dừng process để cứu hệ thống khi hết bộ nhớ.
Tuy nhiên, không nên kết luận mọi 137 đều là OOM. Process cũng có thể bị người dùng hoặc hệ thống gửi SIGKILL vì lý do khác.
Exit code 137 có nghĩa gì?
Unix process thoát do signal thường được biểu diễn:
128 + signal number
SIGKILL là signal số 9:
128 + 9 = 137
Vì vậy:
exit code 137
nghĩa là process bị kill bằng SIGKILL.
SIGKILL không thể được process bắt hoặc xử lý graceful shutdown.
OOM là gì?
OOM là viết tắt của:
Out Of Memory
Khi hệ thống không còn đủ RAM và swap cho yêu cầu bộ nhớ, kernel có thể kích hoạt OOM Killer để chọn một hoặc nhiều process dừng.
Mục tiêu là giúp hệ thống còn khả năng hoạt động thay vì treo hoàn toàn.
Vì sao build Next.js dùng nhiều RAM?
Build có thể chạy:
- TypeScript.
- Bundler.
- Minification.
- Static page generation.
- Image/source map processing.
- Worker song song.
- Dependency compilation.
RAM dùng trong build thường cao hơn RAM khi app chạy.
Một VPS 1 GB có thể chạy app nhỏ sau build nhưng không đủ để tự build source.
Vì sao Docker build bị 137?
Docker build process vẫn dùng tài nguyên của host hoặc giới hạn builder/container.
Các giai đoạn tốn RAM:
RUN npm ci
RUN npm run build
Nếu host chỉ có khoảng 1 GB RAM, Node.js và package manager có thể bị OOM.
Bước 1: Kiểm tra RAM
free -h
Ví dụ:
total used free shared buff/cache available
Mem: 957Mi 700Mi 70Mi 20Mi 187Mi 120Mi
Swap: 0B 0B 0B
Quan tâm available, không chỉ free.
Kiểm tra realtime:
watch -n 1 free -h
Hoặc:
htop
Bước 2: Tìm log OOM Killer
sudo journalctl -k |
grep -i -E 'out of memory|oom|killed process'
Theo thời gian:
sudo journalctl -k \
--since "30 minutes ago" |
grep -i -E 'out of memory|oom|killed process'
Hoặc:
dmesg --ctime |
grep -i -E 'out of memory|oom|killed process'
Ví dụ:
Out of memory: Killed process 12345 (node)
Đây là bằng chứng mạnh rằng process bị OOM.
Bước 3: Kiểm tra cgroup/Docker
Container có thể bị OOM vì giới hạn riêng dù host còn RAM.
Kiểm tra:
docker inspect CONTAINER_NAME \
--format '{{.State.OOMKilled}}'
Kết quả:
true
Xem giới hạn:
docker inspect CONTAINER_NAME \
--format 'Memory={{.HostConfig.Memory}}'
Docker stats:
docker stats
Compose có thể có:
mem_limit: 512m
App vượt 512 MB sẽ bị kill dù host có nhiều hơn.
Bước 4: Xác định process dùng RAM
ps aux --sort=-%mem | head -n 15
Hoặc:
top
htop
Docker:
docker stats --no-stream
Có thể PostgreSQL, PM2, Docker daemon và app cũ đang chiếm RAM trước khi build.
Bước 5: Kiểm tra swap
swapon --show
free -h
Nếu không có swap:
Swap: 0B
VPS RAM thấp dễ OOM khi tải tăng đột ngột.
Tạo swap file
Ví dụ 2 GB:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
Kiểm tra:
swapon --show
free -h
Thêm /etc/fstab:
/swapfile none swap sw 0 0
Test:
sudo mount -a
Swap không thay thế RAM. Build có thể rất chậm khi swap nhiều.
Kiểm tra nhà cung cấp có cho phép swap không.
Swappiness
Xem:
sysctl vm.swappiness
Thay tạm:
sudo sysctl vm.swappiness=10
Cấu hình lâu dài:
/etc/sysctl.d/99-deployeasy.conf
vm.swappiness=10
Không có giá trị tốt nhất cho mọi workload. Cần theo dõi memory pressure.
Giải pháp tốt nhất: Build trong CI
Thay vì build trên VPS:
GitHub Actions
↓ build image/artifact
Container Registry
↓ pull
VPS
VPS chỉ:
docker compose pull
docker compose up -d
Lợi ích:
- Không tốn RAM build trên production.
- Artifact được test.
- Có version.
- Dễ rollback.
- Production không cần source/build tool đầy đủ.
Build artifact ngoài VPS
Next.js standalone:
CI build
↓
.next/standalone
.next/static
public
↓
đóng gói hoặc image
↓
VPS
NestJS:
CI build
↓
dist/
package files
↓
VPS
Phải build cùng architecture/runtime phù hợp, đặc biệt với native dependency.
Tăng RAM VPS
Nếu workload thường xuyên vượt RAM, swap chỉ trì hoãn vấn đề.
Dấu hiệu cần nâng RAM:
- Swap dùng liên tục.
- OOM tái diễn.
- Database bị kill.
- App latency tăng.
- Build và runtime cạnh tranh.
- Memory available thường rất thấp.
VPS chạy Docker + Next.js + NestJS + PostgreSQL thường cần nhiều hơn 1 GB.
Dừng service không cần thiết trước build
Chỉ dùng như biện pháp tạm thời và có kế hoạch downtime.
Ví dụ:
docker compose stop web api
npm run build
docker compose start web api
Rủi ro:
- Website down.
- Build fail và service chưa start lại.
- Database không nên dừng tùy tiện.
CI build vẫn là lựa chọn tốt hơn.
Giảm số worker build
Một số tool hỗ trợ giới hạn concurrency. Cấu hình phụ thuộc framework/version.
Không sử dụng biến hoặc flag không được tài liệu version hiện tại hỗ trợ.
Nguyên tắc:
- Giảm parallelism.
- Tắt source map không cần thiết.
- Giảm plugin nặng.
- Tách build.
- Loại dependency không dùng.
Đo trước/sau.
Node.js heap limit
Node có tùy chọn:
NODE_OPTIONS="--max-old-space-size=1024"
Nhưng tăng heap trên VPS chỉ có 1 GB có thể làm OOM nhanh hơn vì process còn cần native memory và hệ thống cũng cần RAM.
Giảm heap:
NODE_OPTIONS="--max-old-space-size=512"
có thể khiến Node báo JavaScript heap out of memory thay vì kernel kill, nhưng build có thể không hoàn thành.
Không coi --max-old-space-size là cách tạo thêm RAM.
JavaScript heap out of memory khác 137
Node có thể tự báo:
FATAL ERROR: Reached heap limit
JavaScript heap out of memory
Đây là Node heap limit.
Exit 137 là SIGKILL ở cấp OS/cgroup.
Cả hai liên quan memory nhưng cách chẩn đoán khác.
Docker BuildKit resource
Docker Desktop có giới hạn VM riêng. Trên Windows/macOS, tăng memory Docker Desktop có thể cần thiết.
Trên Linux VPS, Docker dùng host/cgroup resource.
Kiểm tra builder:
docker buildx ls
docker info
Multi-stage có giảm RAM build không?
Multi-stage chủ yếu:
- Giảm image runtime.
- Tách build/runtime.
- Tối ưu layer.
Nó không mặc nhiên giảm peak RAM của bước npm run build.
Tuy nhiên, Dockerfile tốt giúp tránh build lại dependency không cần thiết.
Build context quá lớn
Kiểm tra .dockerignore.
Không gửi:
node_modules
.next
.git
logs
backup
uploads
Build context lớn chủ yếu tốn I/O/disk nhưng cũng có thể làm build nặng hơn.
Kiểm tra disk
Khi disk đầy, build có thể fail với lỗi khác, nhưng đôi lúc tình trạng hệ thống trở nên khó chẩn đoán.
df -h
df -i
docker system df
Cả RAM và disk đều phải được kiểm tra.
OOM score
Kernel dùng nhiều yếu tố để chọn process kill.
Xem process:
cat /proc/PID/oom_score
cat /proc/PID/oom_score_adj
Không tùy tiện đặt OOM score để bảo vệ mọi process. Nếu bảo vệ app, kernel có thể kill database hoặc service quan trọng khác.
Giải pháp đúng là đủ tài nguyên và limit hợp lý.
systemd memory limit
Unit có thể có:
MemoryMax=600M
Nếu app vượt, systemd/cgroup có thể kill.
Xem:
systemctl show deployeasy-api \
-p MemoryCurrent \
-p MemoryMax
Kubernetes/container platform
Container có request/limit memory. Vượt limit thường dẫn tới OOMKilled.
Kiểm tra platform events và metric.
Không chỉ tăng limit; tìm memory leak và sizing đúng.
Memory leak
Nếu app RAM tăng liên tục sau nhiều giờ/ngày:
- Heap snapshot.
- Metric process memory.
- Request pattern.
- Cache không giới hạn.
- Listener leak.
- Large object.
- Queue backlog.
Restart chỉ giảm triệu chứng tạm thời.
Quy trình chẩn đoán hoàn chỉnh
1. Ghi lại lệnh và thời điểm
npm run build
10:32
exit 137
2. Xem kernel log
sudo journalctl -k \
--since "10 minutes ago"
3. Xem RAM/swap
free -h
swapon --show
4. Xem process/container
ps aux --sort=-%mem | head
docker stats --no-stream
5. Xem limit
docker inspect
systemctl show
6. Chọn giải pháp
Build CI
Tăng RAM
Thêm swap hỗ trợ
Giảm concurrency
Sửa memory leak
Điều chỉnh limit
Ví dụ VPS 1 GB
Trước build:
Ubuntu + Docker daemon: 250 MB
PostgreSQL: 200 MB
API: 180 MB
Next.js: 200 MB
Available: rất thấp
Build thêm có thể cần hàng trăm MB đến hơn 1 GB, dẫn tới OOM.
Giải pháp hợp lý:
CI build image
VPS chỉ chạy image
hoặc tăng RAM/tách database.
Không nên làm
Chạy lại nhiều lần
Nếu tài nguyên không đổi, kết quả có thể vẫn là OOM và gây downtime.
Tạo swap cực lớn rồi xem như đã sửa
Swap chậm và có thể làm server thrashing.
Tắt OOM Killer
Có thể làm toàn hệ thống treo và không SSH được.
Kill database để nhường RAM
Có nguy cơ mất dịch vụ và recovery không mong muốn.
Checklist
[ ] Xác nhận exit 137 = SIGKILL
[ ] Xem kernel OOM log
[ ] Kiểm tra free -h
[ ] Kiểm tra swap
[ ] Kiểm tra Docker OOMKilled
[ ] Kiểm tra cgroup/systemd limit
[ ] Xem process dùng RAM
[ ] Kiểm tra disk/inode
[ ] Build trong CI nếu có thể
[ ] Image/artifact có version
[ ] Tăng RAM nếu pressure kéo dài
[ ] Theo dõi memory runtime
[ ] Điều tra memory leak nếu RAM tăng liên tục
Câu hỏi thường gặp
Exit 137 luôn là hết RAM phải không?
Không. Nó nghĩa process nhận SIGKILL. OOM là nguyên nhân rất phổ biến, cần xác nhận bằng kernel/cgroup log.
Thêm swap có hết lỗi không?
Có thể giúp tải ngắn hạn nhưng không bảo đảm. Build có thể chậm và workload thường xuyên thiếu RAM vẫn cần nâng cấp.
Tăng Node heap có sửa không?
Chỉ hữu ích nếu Node heap limit là nút thắt và host còn RAM. Trên VPS thiếu RAM, tăng heap có thể làm OOM nặng hơn.
Docker build trên VPS hay CI tốt hơn?
Production VPS nhỏ thường nên pull image đã build/test từ CI.
Kết luận
Khi gặp Killed hoặc exit 137, đừng chỉ chạy lại. Hãy xác minh SIGKILL, kiểm tra OOM log, RAM, swap và container limit. Giải pháp bền vững thường là build ngoài production và cấp đủ tài nguyên.
Nguồn tham khảo
Đọc tiếp
Bài viết liên quan
Monitoring production: Log, healthcheck, CPU, RAM và cảnh báo
Hướng dẫn monitoring VPS và ứng dụng production bằng journalctl, Nginx log, PM2, Docker healthcheck, tài nguyên và cảnh báo.
Đọc bài →Sửa lỗi No space left on device trên VPS và Docker
Hướng dẫn tìm nguyên nhân hết dung lượng hoặc inode, kiểm tra log, Docker image, volume, journal và dọn VPS an toàn không mất dữ liệu.
Đọc bài →Backup và restore PostgreSQL production bằng pg_dump
Hướng dẫn backup PostgreSQL bằng pg_dump, định dạng custom, pg_restore, lịch cron, kiểm tra restore và lưu bản sao ngoài VPS.
Đọc bài →