รวม Log จากทุก Pod ด้วย EFK Stack บน K8s

ระบบเก็บบันทึก (Logging) แบบรวมศูนย์บน Kubernetes

เมื่อทำงานกับ Kubernetes ที่มี Pod จำนวนมาย การมองหาข้อมูล log จากแต่ละ Pod จะเป็นงานที่ยุ่งยากและใช้เวลานาน วิธีแก้ปัญหาคือการใช้ระบบเก็บบันทึกแบบรวมศูนย์ (Centralized Logging) โดยใช้ EFK Stack ซึ่งประกอบด้วย Elasticsearch, Fluentd, และ Kibana

ส่วนประกอบของ EFK Stack

Elasticsearch: เป็นฐานข้อมูล (Search Engine) ที่ใช้เก็บข้อมูล log และอนุญาตให้ค้นหาข้อมูล log ได้อย่างรวดเร็ว

Fluentd: เป็นระบบเก็บรวบรวมข้อมูล log จากทุก Pod บน Kubernetes และส่งต่อไปยัง Elasticsearch

Kibana: เป็น Web Interface ที่ใช้สำหรับมองหา วิเคราะห์ และแสดงผลข้อมูล log ที่เก็บไว้ใน Elasticsearch

การติดตั้ง Elasticsearch บน Kubernetes

ใช้ Helm Chart เพื่อติดตั้ง Elasticsearch:

helm repo add elastic https://helm.elastic.co
helm repo update
helm install elasticsearch elastic/elasticsearch \
  --namespace logging \
  --create-namespace \
  --set replicas=3 \
  --set resources.requests.memory="512Mi" \
  --set resources.requests.cpu="250m"

การติดตั้ง Fluentd บน Kubernetes

Fluentd ต้องทำงานบน Node ทั้งหมด เพื่อเก็บรวบรวม log จากทุก Pod ใช้ DaemonSet เพื่อให้ Fluentd ทำงานบน Node แต่ละตัว:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: logging
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      serviceAccount: fluentd
      serviceAccountName: fluentd
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
        env:
        - name: FLUENT_ELASTICSEARCH_HOST
          value: "elasticsearch.logging.svc.cluster.local"
        - name: FLUENT_ELASTICSEARCH_PORT
          value: "9200"
        - name: FLUENT_UID
          value: "0"
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

สร้าง ServiceAccount สำหรับ Fluentd

apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd
  namespace: logging
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: fluentd
rules:
- apiGroups: [""]
  resources:
  - pods
  - namespaces
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: fluentd
roleRef:
  kind: ClusterRole
  name: fluentd
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: fluentd
  namespace: logging

การติดตั้ง Kibana

helm install kibana elastic/kibana \
  --namespace logging \
  --set elasticsearch.hosts[0]=elasticsearch.logging.svc.cluster.local \
  --set elasticsearch.port=9200 \
  --set service.type=LoadBalancer

การเข้าถึง Kibana

kubectl port-forward -n logging svc/kibana 5601:5601
# เข้าไปที่ http://localhost:5601

ตรวจสอบสถานะของ Elasticsearch

kubectl get pods -n logging
kubectl logs -n logging -l app=elasticsearch
kubectl port-forward -n logging svc/elasticsearch 9200:9200
curl http://localhost:9200/_cluster/health

ตรวจสอบสถานะของ Fluentd

kubectl get daemonset -n logging
kubectl logs -n logging daemonset/fluentd
kubectl describe daemonset -n logging fluentd

การกำหนดค่า Index Pattern ใน Kibana

1. เข้าไปที่ Kibana UI (http://localhost:5601)

2. คลิก “Stack Management” → “Index Patterns”

3. คลิก “Create index pattern”

4. ใส่ชื่อ pattern เช่น “logstash-*” หรือ “fluent-*”

5. เลือกเวลา (Time field) เป็น “@timestamp”

6. คลิก “Create index pattern”

การค้นหา Log ใน Kibana

ใช้ Kibana Query Language (KQL) เพื่อค้นหา log:

kubernetes.pod_name:"nginx*"
kubernetes.namespace_name:"default"
level:"ERROR"
@timestamp:["2026-03-01" TO "2026-03-31"]

ทำให้ Elasticsearch ทำงานแบบ High Availability

helm install elasticsearch elastic/elasticsearch \
  --namespace logging \
  --set replicas=3 \
  --set nodeGroup="master" \
  --set roles.master=true \
  --set roles.data=true \
  --set roles.ingest=true \
  --set persistence.enabled=true \
  --set persistence.size=30Gi

การตั้งค่า Retention Policy

กำหนดให้ Elasticsearch ลบ index เก่าโดยอัตโนมัติ:

curl -X PUT http://localhost:9200/_ilm/policy/logs_policy -H 'Content-Type: application/json' -d '{
  "policy": "logs_policy",
  "phases": {
    "hot": {
      "min_age": "0d",
      "actions": {
        "rollover": {
          "max_primary_shard_size": "50GB"
        }
      }
    },
    "warm": {
      "min_age": "7d",
      "actions": {
        "set_priority": {
          "priority": 50
        }
      }
    },
    "delete": {
      "min_age": "30d",
      "actions": {
        "delete": {}
      }
    }
  }
}'