ระบบเก็บบันทึก (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": {}
}
}
}
}'
