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.
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.
Deploy thành công chỉ cho biết app hoạt động tại một thời điểm. Production cần phát hiện khi:
- Website down.
- API trả lỗi.
- RAM cạn.
- Disk đầy.
- Container restart.
- Database mất kết nối.
- Chứng chỉ sắp hết hạn.
- Backup không chạy.
Monitoring là quá trình thu thập tín hiệu, đánh giá trạng thái và gửi cảnh báo.
Bốn nhóm tín hiệu cơ bản
Availability
Dịch vụ có truy cập được không?
HTTP 200?
DNS hoạt động?
Port 443 mở?
Errors
HTTP 5xx
Exception
Database timeout
Container crash
Latency
p50
p95
p99
Average có thể che request rất chậm.
Saturation
CPU
RAM
Swap
Disk
Inode
Connection
Queue
Healthcheck là gì?
Healthcheck xác định service có hoạt động không.
GET /health
{
"status": "ok"
}
HTTP:
200 OK
Liveness và readiness
Liveness
Process còn sống và không bị kẹt nghiêm trọng?
Readiness
Service đã sẵn sàng nhận request?
App có thể sống nhưng chưa ready vì database chưa kết nối hoặc migration chưa xong.
Khi cần, tách:
/health/live
/health/ready
Healthcheck không nên
- Chạy query nặng.
- Ghi dữ liệu.
- Gọi quá nhiều service.
- Lộ secret.
- Luôn trả 200 dù dependency chết.
Kiểm tra bằng curl
curl \
--fail \
--silent \
--show-error \
https://api.deployeasy.vn/health
Xem timing:
curl \
-o /dev/null \
-s \
-w 'status=%{http_code} time=%{time_total}\n' \
https://api.deployeasy.vn/health
Systemd service
systemctl status nginx
systemctl status ssh
systemctl status postgresql
systemctl --failed
systemctl dùng để kiểm tra và điều khiển systemd service.
Journalctl
Log service:
sudo journalctl -u nginx
Realtime:
sudo journalctl -u nginx -f
Trong 30 phút:
sudo journalctl -u nginx --since "30 minutes ago"
Chỉ lỗi:
sudo journalctl -p err --since today
Boot hiện tại:
sudo journalctl -b
Boot trước:
sudo journalctl -b -1
Dung lượng:
journalctl --disk-usage
Không xóa log ngay khi sự cố xảy ra.
Nginx log
/var/log/nginx/access.log
/var/log/nginx/error.log
Theo dõi:
sudo tail -f /var/log/nginx/error.log
Lọc 5xx theo log format mặc định:
awk '$9 ~ /^5/' /var/log/nginx/access.log | tail
Field có thể khác nếu log format đã đổi.
Log riêng:
access_log /var/log/nginx/deployeasy.access.log;
error_log /var/log/nginx/deployeasy.error.log;
PM2 monitoring
pm2 list
pm2 monit
pm2 logs
pm2 logs deployeasy-api --lines 200
Theo dõi:
- Status.
- Restart count.
- CPU.
- Memory.
- Uptime.
Restart count tăng liên tục cần điều tra.
Docker monitoring
docker compose ps
docker compose logs -f
docker stats
Health:
docker inspect \
--format='{{json .State.Health}}' \
CONTAINER_NAME | jq
Restart:
docker inspect \
--format='{{.RestartCount}}' \
CONTAINER_NAME
Container running chưa chắc app healthy.
Docker healthcheck
services:
api:
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://127.0.0.1:3000/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))",
]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
Command healthcheck phải tồn tại trong image.
CPU và load
uptime
top
htop
nproc
Load average không bằng trực tiếp phần trăm CPU. Cần xem số CPU, I/O wait và process.
RAM và swap
free -h
vmstat 1
Tìm OOM:
sudo journalctl -k | grep -i -E 'out of memory|killed process'
Hoặc:
dmesg --ctime | grep -i -E 'out of memory|killed process'
Exit code 137 thường liên quan SIGKILL; OOM là nguyên nhân phổ biến nhưng không phải duy nhất.
Disk
df -h
du -sh /var/log/*
du -sh /var/lib/docker/*
Tìm thư mục lớn:
sudo du -xhd1 / | sort -h
Tránh quét sâu vào giờ cao điểm nếu I/O hạn chế.
Inode
df -i
Có thể còn GB trống nhưng không tạo file được vì hết inode.
Docker disk
docker system df
Dọn có chọn lọc:
docker image prune
docker builder prune
Không prune toàn bộ production thiếu kiểm soát.
Network và port
sudo ss -tulpn
sudo ss -s
dig deployeasy.vn
curl -Iv https://deployeasy.vn
PostgreSQL
sudo -u postgres psql -c "SELECT now();"
Docker:
docker compose exec database \
pg_isready \
-U deployeasy \
-d deployeasy
Theo dõi:
- Connection.
- Query chậm.
- Lock.
- Disk.
- Backup.
- Autovacuum.
Structured log
Thay vì:
Something failed
Dùng:
{
"level": "error",
"message": "Database connection failed",
"service": "deployeasy-api",
"requestId": "abc123",
"timestamp": "2026-07-10T03:00:00Z"
}
Không log:
- Password.
- Token.
- Cookie.
- Private key.
- Secret env.
- Dữ liệu cá nhân không cần thiết.
Request ID
X-Request-ID: abc123
Dùng cùng request ID ở Nginx và API để theo dõi request qua hệ thống.
Log level
debug
info
warn
error
fatal
Không bật debug liên tục trên production vì log nhiều và có thể lộ dữ liệu.
Log rotation
Nginx:
ls /etc/logrotate.d/
PM2:
pm2 install pm2-logrotate
Docker:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Journal:
journalctl --disk-usage
Uptime monitoring bên ngoài
Monitoring ngay trên VPS không phát hiện được khi toàn VPS mất mạng.
Dùng một dịch vụ hoặc máy khác kiểm tra:
https://deployeasy.vn/health
Cảnh báo qua email, chat hoặc hệ thống incident.
Dùng retry trước cảnh báo để giảm false alarm.
Alert phải actionable
Tốt:
API production trả 5xx 12% trong 5 phút,
dashboard..., runbook...
Kém:
Something wrong
Mỗi alert cần:
- Service.
- Environment.
- Metric.
- Threshold.
- Thời gian.
- Link log.
- Hành động ban đầu.
Threshold tham khảo
Disk > 80%: warning
Disk > 90%: critical
Healthcheck fail nhiều lần: critical
Certificate < 14 ngày: warning
Backup quá hạn: critical
Restart count tăng: warning
Điều chỉnh theo hệ thống thực tế.
Monitoring chứng chỉ
echo | openssl s_client \
-servername deployeasy.vn \
-connect deployeasy.vn:443 2>/dev/null |
openssl x509 -noout -enddate
Certbot timer vẫn có thể lỗi, nên cần kiểm tra độc lập.
Monitoring backup
Kiểm tra:
- File mới nhất.
- Kích thước.
- Upload offsite.
- Exit code.
- Restore test.
Ví dụ tìm backup trong 25 giờ:
find /var/backups/deployeasy \
-type f \
-name '*.dump' \
-mmin -1500 \
-print
Runbook website down
1. Xác nhận từ mạng ngoài
2. Kiểm tra DNS
3. Kiểm tra HTTPS
4. Kiểm tra Nginx
5. Kiểm tra app/container
6. Kiểm tra database
7. Kiểm tra RAM/disk
8. Xem log đúng thời điểm
9. Rollback nếu do deploy
10. Ghi timeline
Lệnh nhanh:
curl -Iv https://deployeasy.vn
sudo systemctl status nginx
pm2 list
docker compose ps
free -h
df -h
sudo journalctl -p err --since "30 minutes ago"
Chỉ chạy lệnh phù hợp với stack.
Sau sự cố
Postmortem:
Sự cố gì?
Bắt đầu lúc nào?
Phát hiện ra sao?
Ảnh hưởng ai?
Nguyên nhân gốc?
Điều gì kéo dài sự cố?
Khắc phục tạm thời?
Hành động phòng ngừa?
Ai phụ trách?
Không dùng postmortem để đổ lỗi cá nhân.
Stack theo giai đoạn
Ban đầu
Healthcheck
Journal/PM2/Docker logs
Uptime monitor ngoài VPS
Disk/RAM alert
Backup alert
Trung bình
Metrics
Dashboard
Centralized logs
Error tracking
Alert routing
Lớn
Tracing
SLO/SLI
On-call
Incident management
Capacity planning
Không cần cài stack phức tạp chỉ cho một blog tĩnh.
Checklist
[ ] Health endpoint
[ ] External uptime monitor
[ ] Nginx error log
[ ] Structured app log
[ ] Secret được che
[ ] Restart alert
[ ] CPU/RAM/swap
[ ] Disk và inode
[ ] Database readiness
[ ] Certificate expiry
[ ] Backup freshness
[ ] Log rotation
[ ] Alert có runbook
[ ] Rollback procedure
[ ] Postmortem
Câu hỏi thường gặp
Log có phải monitoring không?
Log là một tín hiệu. Monitoring còn có metric, healthcheck và alert.
Container running có nghĩa app tốt không?
Không. App có thể chạy nhưng endpoint lỗi hoặc database down.
Website ít người dùng có cần monitoring không?
Có, nhưng bắt đầu đơn giản với uptime, disk, backup và certificate.
Có nên tự restart khi healthcheck fail?
Có thể, nhưng restart liên tục có thể che lỗi. Cần giới hạn và cảnh báo.
Kết luận
Monitoring tốt giúp phát hiện sớm, chẩn đoán nhanh và phục hồi có kiểm soát. Bắt đầu từ healthcheck, log, tài nguyên và backup.
Nguồn tham khảo
Đọc tiếp
Bài viết liên quan
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.
Đọ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 →