Logging และ Metrics
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”Kubernetes ให้ logging กับ metrics มาแค่พอ debug Pod เดียว ณ ตอนนี้ได้ แต่ไม่มีอะไรที่ aggregate หรือเก็บข้อมูลข้ามทั้ง cluster ให้ นั่นคือ stack แยกที่ต้องเพิ่มเข้าไปเอง
kubectl logs: หน้าต่างของตอนนี้ ไม่ใช่หนังสือประวัติศาสตร์
หัวข้อที่มีชื่อว่า “kubectl logs: หน้าต่างของตอนนี้ ไม่ใช่หนังสือประวัติศาสตร์”kubectl logs อ่าน stdout/stderr ของ container ตรงจากโหนดที่รันอยู่ เป็นวิธีเร็วที่สุดที่จะดูว่า Pod กำลังทำอะไรอยู่ ณ วินาทีนี้
# Stream logs live as they are writtenkubectl logs -f deploy/checkout
# A Pod with more than one container: pick which onekubectl logs my-pod -c sidecar
# The container just crashed and restarted: see its last words before it diedkubectl logs my-pod --previous--previous คือ flag ที่คนมักลืมแล้วดันเป็นตัวที่ต้องใช้ที่สุด เวลา container crash-loop log ของ container ตัว ปัจจุบัน จะว่างเปล่าตั้งแต่เริ่ม แต่ --previous จะโชว์ log ของ instance ที่เพิ่ง crash ไป ซึ่งปกติก็ตรงจุดที่มี stack trace อยู่พอดี
ข้อจำกัดสำคัญคือ Kubernetes เองไม่ได้ aggregate หรือเก็บ log พวกนี้ให้ ถ้า Pod ถูกลบ log ของตัวเองก็มักหายไปด้วย ไม่มี “ค้นหา log ข้ามทุก Pod ใน cluster” มาให้ในตัว งานนี้เป็นหน้าที่ของ logging stack แยกต่างหาก โดยทั่วไปจะเป็น node-level agent อย่าง Fluent Bit (หรือ Fluentd/Vector) ที่คอย tail log file ของทุก container แล้วส่งต่อไปยัง backend อย่าง Loki หรือ Elasticsearch ที่ค้นหาและเก็บข้อมูลระยะยาวได้
# A minimal illustration: Fluent Bit runs as a DaemonSet so one agent per node# tails every container's logs and forwards them to a backendapiVersion: apps/v1kind: DaemonSetmetadata: name: fluent-bitspec: selector: matchLabels: app: fluent-bit template: metadata: labels: app: fluent-bit spec: containers: - name: fluent-bit image: fluent/fluent-bit:3.1 volumeMounts: - name: varlog mountPath: /var/log volumes: - name: varlog hostPath: path: /var/logmetrics-server: พอสำหรับ kubectl top กับ autoscaling แค่นั้น
หัวข้อที่มีชื่อว่า “metrics-server: พอสำหรับ kubectl top กับ autoscaling แค่นั้น”metrics-server เป็น cluster add-on เบา ๆ ที่เก็บ CPU กับ memory usage จากทุก kubelet แล้วเก็บไว้ ในหน่วยความจำเท่านั้น ไม่มีประวัติ ไม่มีการ persist ไม่มี alerting มีไว้เพื่อขับเคลื่อนแค่สองอย่างนี้
kubectl top nodeskubectl top pods -n checkout…และ HorizontalPodAutoscaler ที่ poll metrics-server เพื่อตัดสินใจว่าจะ scale Deployment ขึ้นหรือลง
apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: checkoutspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: checkout minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70metrics-server ไม่ใช่ monitoring solution ชัดเจน ถ้าถามว่า “CPU usage เมื่อสามชั่วโมงก่อนเป็นยังไง” หรือ “แจ้งเตือนตอน memory เกิน 90%” metrics-server ตอบไม่ได้เลย เพราะรู้แค่ snapshot ปัจจุบันเท่านั้น
Prometheus + Grafana: stack observability มาตรฐานที่ใช้กันจริง
หัวข้อที่มีชื่อว่า “Prometheus + Grafana: stack observability มาตรฐานที่ใช้กันจริง”สำหรับ observability จริง ๆ ที่ต้องมีข้อมูลย้อนหลัง dashboard และ alerting ตัวมาตรฐานที่ใช้กันคือคู่ Prometheus กับ Grafana
Prometheus ทำงานด้วยการ scrape คือดึง metrics เป็นระยะจาก HTTP endpoint /metrics ที่ workload เปิดไว้ในรูปแบบ text ของ Prometheus เอง แอปและ sidecar หลายตัวเปิด endpoint นี้เอง ส่วนสำหรับสถานะของ object ระดับ cluster (จำนวน replica ของ Deployment, phase ของ Pod, condition ของ node และอื่น ๆ) Prometheus จะ scrape kube-state-metrics ที่เป็น service แยกที่แปลง object ของ Kubernetes API ให้กลายเป็น metrics ของ Prometheus
apiVersion: v1kind: Podmetadata: name: checkout annotations: prometheus.io/scrape: "true" prometheus.io/port: "9090"spec: containers: - name: checkout image: checkout:2.3.0 ports: - containerPort: 9090# A workload's own /metrics endpoint, in Prometheus text formatcurl http://checkout-pod:9090/metricsPrometheus เก็บข้อมูลที่ scrape มาเป็น time series แล้วประเมินตาม alerting rule ที่ตั้งไว้ Grafana ทำหน้าที่เป็น visualization layer อยู่ด้านบน คือ query ไปที่ Prometheus แล้ว render ออกมาเป็น dashboard เช่นแนวโน้ม CPU/memory, request latency, error rate และใช้ขับเคลื่อนการแจ้งเตือนด้วย
flowchart LR
subgraph Logs
stdout["Pod stdout/stderr"] --> agent["Node-level log agent\n(Fluent Bit)"]
agent --> backend["Log backend\n(Loki / Elasticsearch)"]
end
subgraph Metrics
cadvisor["kubelet cAdvisor"] --> ms["metrics-server\n(in-memory)"]
ms --> top["kubectl top / HPA"]
workload["Workload /metrics\n+ kube-state-metrics"] --> prom["Prometheus"]
prom --> grafana["Grafana dashboards"]
end