สถาปัตยกรรม ELK (โยงกับ lab ของคุณ)
คุณมี ELK labs ครบ 6 อันใน docker/elk/ แล้ว บทนี้จะจัดระเบียบความรู้นั้นให้เป็นภาพเดียว: แต่ละชิ้นทำอะไร, ต่อกันยังไง, และ lab 01→06 พาคุณเดินทางผ่านอะไรบ้าง
ELK / Elastic Stack คืออะไร
"ELK" มาจาก 3 ตัวหลัก + Beats (เลยเรียก "Elastic Stack" ในปัจจุบัน):
แอป → [Filebeat] → [Logstash] → [Elasticsearch] → [Kibana]
เก็บ log แปลง/parse เก็บ+ค้นหา ดู+dashboard
| ส่วนประกอบ | หน้าที่ | เทียบกับโลก metrics |
|---|---|---|
| Beats (Filebeat) | agent เบาๆ ที่เก็บ log จากไฟล์/container แล้วส่งต่อ | คล้าย exporter/agent |
| Logstash | รับ log มา parse/แปลง/enrich แล้วส่งเข้า ES | คล้าย processing pipeline |
| Elasticsearch | เก็บ log แบบ index + ค้นหาเร็ว (search engine) | คล้าย TSDB แต่สำหรับ text |
| Kibana | UI ค้น log + ทำ dashboard | คล้าย Grafana (แต่ของ log) |
ทำไมต้องมี Logstash คั่น ทั้งที่ Filebeat ส่งเข้า ES ตรงๆ ก็ได้? — Logstash เก่งเรื่องแปลงข้อมูลหนักๆ (grok, mutate, enrich จาก DB) ถ้า log เป็น JSON ดีอยู่แล้ว หลายทีมข้าม Logstash ไปเลย (Filebeat → ES ตรงๆ) เพื่อลด component นี่คือ trade-off ที่ lab ของคุณค่อยๆ สอน
ไล่ flow ทีละขั้น
1. Filebeat — เก็บ log
อ่าน log จากไฟล์ (/var/log/app/*.log) หรือจาก Docker container โดยตรง แล้วส่งต่อ ข้อดีคือเบามาก (เขียนด้วย Go) รันเป็น agent ข้างแอปได้
2. Logstash — แปลง (pipeline: input → filter → output)
input { beats { port => 5044 } } # รับจาก Filebeat
filter {
json { source => "message" } # parse JSON (lab-05 ของคุณ)
date { match => ["timestamp","ISO8601"] } # ตั้ง @timestamp ให้ถูก
}
output { elasticsearch { hosts => [...] } } # ส่งเข้า ES
3. Elasticsearch — เก็บและค้น
เก็บ log เป็น document ใน index (เช่น app-logs-2026.08.20) ทำ inverted index ให้ค้น full-text ได้เร็ว
4. Kibana — ดู สร้าง index pattern แล้วค้น/filter/ทำ dashboard บน log เหล่านั้น
แผนที่ lab 01→06 ของคุณ
lab ที่คุณทำมาไม่ได้สุ่ม — มันคือการเดินทางจากง่ายไปซับซ้อน:
| Lab | โฟกัส | สิ่งที่เพิ่มเข้ามา |
|---|---|---|
| lab-01-basic-elk | ELK ขั้นพื้นฐาน | แอป → ไฟล์ log → Logstash อ่านไฟล์ → ES → Kibana |
| lab-02-better-logs | log ที่ดีขึ้น | ปรับปรุงรูปแบบ log ให้ parse ง่ายขึ้น |
| lab-03-filebeat | เพิ่ม Filebeat | แยกหน้าที่เก็บ log ออกมาเป็น agent (Beats → Logstash) |
| lab-04-maps-to-nestjs | mapping ฟิลด์ | จัดการ field mapping สำหรับ log จากแอป NestJS |
| lab-05-structured-nestjs | structured JSON | ขยับมา JSON logging เต็มตัว (บทที่ 30!) — json filter แทน grok |
| lab-06-stdout | autodiscovery + scale | Filebeat autodiscover + Docker labels รองรับหลาย service (README มีคู่มือ scaling) |
สังเกต pattern การเรียนรู้: เริ่มจากอ่านไฟล์ตรงๆ → แยก agent (Filebeat) → ทำ log ให้มีโครงสร้าง (JSON) → scale ด้วย autodiscovery นี่คือเส้นทางเดียวกับที่ทีมจริงวิวัฒน์ระบบ log ของตัวเอง คุณเดินมาถูกทางแล้ว
เชื่อมโยงกับสิ่งที่เพิ่งเรียน
- lab-05 ใช้ JSON logging = structured logging จากบทที่ 30 — เพราะ log มีโครงสร้างดี Logstash เลยแค่
json { source => "message" }ไม่ต้อง grok ที่เปราะ - lab-06 autodiscovery = แนวคิด service discovery แบบเดียวกับ Prometheus (บทที่ 20) — ระบบหา target/source เองเมื่อ service เกิด-ดับ
- index ตามวัน (
app-logs-%{+yyyy.MM.dd}) = การจัดการ retention (บทที่ 30) — ลบ index เก่าทิ้งได้เป็นก้อน
ELK vs ทางเลือกอื่น (Loki)
ELK ทรงพลังแต่กิน resource (ES ต้องการ RAM เยอะ) ทางเลือกที่เบากว่าคือ Grafana Loki:
| ELK (Elasticsearch) | Loki | |
|---|---|---|
| index | full-text ทั้ง log (ค้นทุกคำได้) | index แค่ label (เบากว่ามาก) |
| resource | หนัก (RAM เยอะ) | เบา |
| ค้นเนื้อหา | เร็วมาก | ต้อง scan (ช้ากว่า) |
| คู่กับ | Kibana | Grafana (รวมกับ metrics ได้) |
ไม่มีอันไหน "ดีกว่า" แบบ absolute — ELK เหมาะเมื่อต้องค้น log เนื้อหาลึกบ่อยๆ, Loki เหมาะเมื่ออยากได้ของเบาและรวมหน้าจอกับ Grafana metrics คุณเรียน ELK มาแล้วเข้าใจ concept ก็ย้ายไป Loki ได้ไม่ยาก
สรุป
- Elastic Stack: Filebeat (เก็บ) → Logstash (แปลง) → Elasticsearch (เก็บ+ค้น) → Kibana (ดู)
- Logstash ข้ามได้ถ้า log เป็น JSON ดีอยู่แล้ว (Filebeat → ES ตรง)
- lab 01→06 ของคุณ = เส้นทางจาก ELK พื้นฐาน → Filebeat → JSON → autodiscovery/scale
- structured JSON (lab-05) ทำให้ pipeline ง่ายลงมาก
- ทางเลือกเบากว่า: Loki (index แค่ label, รวมกับ Grafana)
จบ Module 3! คุณเห็นภาพรวม log ทั้งหมดแล้ว ต่อไป Module 4 — เสาสุดท้ายที่ repo ยังไม่มี: Traces