ปัญหาที่ทุกคนเจอ
Pod พัง — kubectl logs ออก 50,000 บรรทัด ใช้เวลา 30 นาที scroll หา error
ปัญหา 90% ของการ debug ช้า:
- ใช้
kubectl logsแบบไม่มี filter - อ่าน log ของ pod ที่ผิดเครื่อง
- log ไม่มีรูปแบบ — grep ไม่เจอ
- ไม่รู้ว่าควรดู
--previousหรือไม่
คำสั่งพื้นฐานที่ใช้ให้คล่อง
Log ปัจจุบัน
kubectl logs <pod>
Container ที่ crash ไปแล้ว
kubectl logs <pod> --previous
--previous (alias -p) = log ของ container instance ก่อนหน้า — สำคัญมากตอน CrashLoopBackOff
Follow real-time
kubectl logs -f <pod>
Tail หลังสุด N บรรทัด
kubectl logs --tail=200 <pod>
Since เวลาที่กำหนด
# ตั้งแต่ 5 นาทีที่แล้ว
kubectl logs --since=5m <pod>
# ตั้งแต่ timestamp
kubectl logs --since-time=2026-05-03T10:00:00Z <pod>
Multi-container pod
kubectl logs <pod> -c <container-name>
# log ทุก container
kubectl logs <pod> --all-containers=true
Pod หลายตัวที่ label เดียว
kubectl logs -l app=myapp --tail=50
Timestamp prefix
kubectl logs --timestamps <pod>
ผลลัพธ์:
2026-05-03T10:23:45.123Z INFO Server started
2026-05-03T10:23:46.231Z ERROR DB connection failed
เทคนิคหา Root Cause เร็วๆ
1. ลด noise ด้วย grep
# เฉพาะ ERROR
kubectl logs <pod> | grep -i error
# ERROR + 5 บรรทัดถัดไป (context)
kubectl logs <pod> | grep -A 5 -i error
# ERROR + 5 ก่อน + 5 หลัง
kubectl logs <pod> | grep -B 5 -A 5 -i error
# multiple pattern
kubectl logs <pod> | grep -iE "error|fail|exception|panic"
# exclude noise
kubectl logs <pod> | grep -v "health check"
2. หา error ตัวแรก
kubectl logs <pod> | grep -i error | head -1
มักเป็น root cause — error ตัวที่ 2-N เป็น cascade
3. ดูตอนรอบนี้ + รอบเก่า
# combine ดูทั้ง 2 รอบ
( kubectl logs <pod> --previous; kubectl logs <pod> ) \
| grep -i error
4. Stream multi-pod พร้อมกัน
stern (install: brew install stern):
# log ของ pod ที่มี label app=myapp
stern -l app=myapp
# เฉพาะ container ชื่อ app
stern -l app=myapp -c app
# filter ด้วย regex
stern -l app=myapp --include "ERROR|WARN"
# exclude
stern -l app=myapp --exclude "health"
# ตั้งแต่ 5 นาที
stern -l app=myapp --since 5m
stern color-code log ของแต่ละ pod คนละสี — debug หลาย pod พร้อมกันสะดวกกว่า kubectl
5. ดูเหตุการณ์ก่อน pod crash
# รวม events + log
kubectl describe pod <pod> | grep -A 10 Events
kubectl logs <pod> --previous --tail=50
Structured Logging — เปลี่ยน game
ถ้า log เป็น JSON — query ด้วย jq ได้:
// app log JSON
import pino from 'pino'
const logger = pino()
logger.info({ user_id: 123, action: 'login' }, 'user logged in')
logger.error({ err, query: 'SELECT...' }, 'DB query failed')
# เฉพาะ level error
kubectl logs <pod> | jq 'select(.level == "error")'
# error ของ user เฉพาะ
kubectl logs <pod> | jq 'select(.user_id == 123 and .level == "error")'
# count error per route
kubectl logs <pod> --tail=10000 \
| jq -r 'select(.level == "error") | .route' \
| sort | uniq -c | sort -rn
หา request ID ตามไปทุก service
ใส่ correlation ID ใน log:
// middleware
import { v4 as uuidv4 } from 'uuid'
import { AsyncLocalStorage } from 'async_hooks'
const asyncStorage = new AsyncLocalStorage<{ requestId: string }>()
app.use((req, res, next) => {
const requestId = req.headers['x-request-id'] ?? uuidv4()
asyncStorage.run({ requestId }, () => next())
})
// logger middleware
const logger = pino({
mixin() {
const store = asyncStorage.getStore()
return store ? { request_id: store.requestId } : {}
},
})
ใน upstream API — forward header:
fetch('https://api.com/...', {
headers: { 'x-request-id': asyncStorage.getStore()?.requestId },
})
หา trail ของ request เดียวกันข้าม service:
# ใน service A
stern -l app=service-a | grep "request_id\":\"abc-123"
# ใน service B
stern -l app=service-b | grep "request_id\":\"abc-123"
Log Levels — ใช้ให้ถูก
| Level | ใช้กับ |
|---|---|
| error | เหตุที่ต้องสนใจทันที (alert) |
| warn | ผิดปกติแต่ไม่ critical (deprecated, retry) |
| info | event สำคัญ (login, payment) |
| debug | รายละเอียด — production ปิด |
| trace | ทุกอย่าง — local เท่านั้น |
production แนะนำ info หรือ warn — ไม่ใช่ debug
ตั้งผ่าน env:
env:
- name: LOG_LEVEL
value: "info"
อย่า log อะไรบ้าง
⚠️ ห้าม:
- Password
- Credit card / CVV
- API key / token
- ข้อมูล PII ที่ PDPA / GDPR ห้าม
ใช้ redact:
const logger = pino({
redact: {
paths: ['password', 'token', 'authorization', 'creditCard.cvv', '*.password'],
censor: '[REDACTED]',
},
})
Centralized Logging — ทางออกถาวร
kubectl logs ใช้ debug realtime — แต่ log หายเมื่อ pod ลบ
ส่งไปเก็บ central:
- Loki + Grafana — light, ฟรี, query ด้วย LogQL
- ELK (Elasticsearch + Kibana) — full search
- Datadog / Splunk — paid SaaS
ดู Centralized Logging ด้วย Loki
ใน Grafana ค้นหา:
{namespace="production",app="myapp"} |= "error"
หาได้ทุก pod ทุกชั่วโมงที่ผ่านมา — แม้ pod ลบไปแล้ว
Tools ที่ทุกคนควรลง
# stern — multi-pod log
brew install stern
# k9s — TUI ดู resource + log
brew install k9s
# kubectl-tail — alternative ของ stern
kubectl krew install tail
# jq — JSON query
brew install jq
# yq — YAML query
brew install yq
# Lnav — interactive log viewer
brew install lnav
Cheat Sheet เวลา debug ด่วน
"Application down"
# 1. ดู pod ที่ผิดปกติ
kubectl get pods -A | grep -v Running | grep -v Completed
# 2. log ของ pod ที่ crash (--previous)
kubectl logs <bad-pod> --previous --tail=50
# 3. หา error
kubectl logs <bad-pod> --previous | grep -iE "error|fail|panic" | head -5
# 4. event ก่อน crash
kubectl describe pod <bad-pod> | grep -A 10 Events
"Slow response"
# 1. log ของ app
stern -l app=myapp --since 10m | grep -iE "slow|timeout"
# 2. ดู resource
kubectl top pods -A --sort-by=memory
# 3. ดู readiness probe fail
kubectl describe pod -l app=myapp | grep -A 5 readiness
"5xx spike"
# log nginx ingress
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx \
--tail=500 | awk '$9 ~ /^5/'
# หรือใน Loki
{namespace="ingress-nginx"} | json | status =~ "5.."
"DB query slow"
# Postgres log
kubectl logs <postgres-pod> --tail=200 | grep "duration:"
# กรองเฉพาะ > 1000ms
kubectl logs <postgres-pod> --tail=10000 \
| grep -oP 'duration: \d+\.\d+' \
| awk '$2 > 1000'
Lessons Learned
- อ่าน error แรกก่อน — error ตัวถัดมามักเป็น cascade
--previousคือเพื่อนที่ดี — ตอน CrashLoopBackOff- JSON log + jq = debug เร็วกว่า text log 5 เท่า
- stern > kubectl logs สำหรับ multi-pod
- Correlation ID ทุก request — debug cross-service ได้ใน 1 minutes
- ส่ง log ไป Loki — ไม่หาย ไม่ขึ้นกับ pod lifecycle
ก่อน publish app ใหม่ ตั้งให้ครบ
- [ ] Structured log (JSON)
- [ ] Log level config ผ่าน env
- [ ] Redact sensitive data
- [ ] Correlation/request ID
- [ ] Health endpoint logged
- [ ] Centralized log shipping (Promtail/Vector)
- [ ] Alert rule บน error rate
สรุป
debug log ที่ดี = ฝีมือ + tool
ใช้:
kubectl logs --previousตอน crashgrep -A 5 errorหา contextsternหลาย podjqสำหรับ structured log- centralized (Loki) สำหรับ history
structured logging + correlation ID ใส่ตั้งแต่ project เริ่ม — debug 6 เดือนข้างหน้าขอบคุณตัวเอง
อ่านต่อ: