Giới thiệu
Trong bài này chúng ta sẽ tìm hiểu cách cài đặt Logstash và FluentD trên Kubernetes để thiết kế một hệ thống thu lập logs.
Việc ghi log và tổng hợp log là rất quan trọng đối với bất kì hệ thống nào. Khi sử dụng Kubernetes để triển khai ứng dụng, log chỉ tồn tại trên một Pod và nếu Pod đó bị xóa đi thì log cũng mất theo. Do đó, nếu muốn truy vết được lỗi của hệ thống, cần có công cụ để thu thập log về một chỗ. Hiện nay, hai Tech Stack phổ biến nhất cho việc log là ELK (Elasticsearch Logstash Kibana) và EFK (Elasticsearch FluentD Kibana). Để thu thập log, ta sẽ sử dụng Sidecar Container để cài đặt Logstash và FluentD lên trên từng Pod.
Logging với Logstash
Ta có thể dùng Logstash để thu thập log từ hệ thống, nhưng từ năm 2015 Elastichsearch đã ra mắt Filebeat để chuyên cho việc theo dõi log, thu thập log và chuyển log đi chỗ khác. Logstash tập trung vào việc nhận log từ nhiều đầu và tiến hành phân tích, lọc và chuyển đổi log thành dạng phù hợp để lưu vào Elasticsearch.
Để làm điều này, ta sẽ triển khai một Pod có Container để ghi log vào tệp tin /var/log/access.log
và một Sidecar Container chạy Filebeat để thu thập log và chuyển đến Logstash.
Tạo một tệp tin tên là filebeat.cm.yaml
để chứa cấu hình Filebeat.
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
labels:
component: filebeat
data:
conf.yaml: |
filebeat.inputs:
- type: log
paths:
- '/var/log/*.log'
output:
logstash:
hosts: [ "logstash:5044" ]
Đầu vào của Filebeat ta đọc từ tệp tin /var/log/*.log
, sau đó ta xuất log này tới Logstash. Tiếp theo ta tạo tệp tin application.yaml
.
apiVersion: apps/v1
kind: Deployment
metadata:
name: busybox
labels:
component: busybox
spec:
strategy:
type: Recreate
selector:
matchLabels:
component: busybox
template:
metadata:
labels:
component: busybox
spec:
containers:
- name: busybox
image: busybox
args:
- sh
- -c
- >
while true;
do
echo $(date) - filebeat log >> /var/log/access.log;
sleep 10;
done
volumeMounts:
- name: log
mountPath: /var/log
- name: filebeat
image: elastic/filebeat:7.16.3
args:
- -c
- /etc/filebeat/conf.yaml
- -e
volumeMounts:
- name: filebeat-config
mountPath: /etc/filebeat
- name: log
mountPath: /var/log
volumes:
- name: log
emptyDir: {}
- name: filebeat-config
configMap:
name: filebeat-config
Trong Pod ở trên ta mount cấu hình của Filebeat vào tệp tin /etc/filebeat/conf.yaml
và sử dụng thuộc tính args
để chỉ định tệp tin cấu hình cho Filebeat. Container ứng dụng sẽ ghi log vào tệp tin /var/log/access.log
10s một lần. Tạo tệp tin logstash.cm.yaml
để chứa cấu hình của Logstash.
apiVersion: v1
kind: ConfigMap
metadata:
name: logstash
labels:
component: logstash
data:
access-log.conf: |
input {
beats {
port => "5044"
}
}
output {
elasticsearch {
hosts => [ "elasticsearch:9200" ]
}
}
Đầu vào ta lấy từ Filebeat sau đó xuất log ra cho Elasticsearch. Tạo tệp tin logstash.yaml
cho Logstash.
apiVersion: apps/v1
kind: Deployment
metadata:
name: logstash
labels:
component: logstash
spec:
strategy:
type: Recreate
selector:
matchLabels:
component: logstash
template:
metadata:
labels:
component: logstash
spec:
containers:
- name: logstash
image: logstash:7.16.3
ports:
- containerPort: 5044
volumeMounts:
- name: logstash-config
mountPath: /usr/share/logstash/pipeline
volumes:
- name: logstash-config
configMap:
name: logstash
---
apiVersion: v1
kind: Service
metadata:
name: logstash
labels:
component: logstash
spec:
ports:
- port: 5044
selector:
component: logstash
Ta mount cấu hình vào thư mục /usr/share/logstash/pipeline
, Logstash sẽ đọc cấu hình từ thư mục này. Tạo Elasticsearch và Kibana với cấu hình cho mục đích thử nghiệm, để tạo Elasticsearch và Kibana trên môi trường thực tế các bạn xem bài này nhé Kubernetes Practice - Elasticsearch Cloud on Kubernetes (ECK). Tệp tin elasticsearch.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: elasticsearch
labels:
component: elasticsearch
spec:
strategy:
type: Recreate
selector:
matchLabels:
component: elasticsearch
template:
metadata:
labels:
component: elasticsearch
spec:
containers:
- name: elasticsearch
image: elasticsearch:7.16.3
ports:
- containerPort: 9200
name: client
- containerPort: 9300
name: nodes
env:
- name: JAVA_TOOL_OPTIONS
value: -Xmx256m -Xms256m
- name: discovery.type
value: single-node
resources:
requests:
memory: 500Mi
cpu: 0.5
limits:
memory: 500Mi
cpu: 0.5
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
labels:
component: elasticsearch
spec:
ports:
- port: 9200
name: client
- port: 9300
name: nodes
selector:
component: elasticsearch
Tệp tin kibana.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
labels:
component: kibana
spec:
strategy:
type: Recreate
selector:
matchLabels:
component: kibana
template:
metadata:
labels:
component: kibana
spec:
containers:
- name: kibana
image: kibana:7.16.3
ports:
- containerPort: 5601
---
apiVersion: v1
kind: Service
metadata:
name: kibana
labels:
component: kibana
spec:
ports:
- port: 5601
selector:
component: kibana
Tạo toàn bộ resource:
kubectl apply -f . --recursive
Dùng port-forward
để truy cập Kibana:
kubectl port-forward svc/kibana 5601:5601
Vào mục Stack Management > Index patterns, sau đó vào mục Discover bạn sẽ thấy log mà ta thu thập được từ busybox
.
Logging với FluentD
FluentD cũng là một công cụ dùng để thu thập log giống như Filebeat và Logstash. FluentD bao gồm các tính năng như theo dõi log, thu thập, phân tích và chuyển đổi log thành dạng thích hợp để lưu vào Elasticsearch. FluentD được phát triển bởi Cloud Native Computing Foundation (CNCF), đây là tổ chức phát triển và bảo trì Kubernetes.
Để thu thập log bằng FluentD, ta sẽ triển khai nó như một Sidecar Container như cách ta dùng Filebeat ở trên. Tạo một tệp tin tên là fluentd.cm.yaml
để chứa cấu hình của FluentD.
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
labels:
component: fluentd
data:
fluent.conf: |
<source>
@type tail
path /var/log/access.log
pos_file /tmp/app.logs.pos
tag app.logs
<parse>
@type none
</parse>
</source>
<match app.logs>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix fluentd
flush_interval 1s
</match>
Ở trong tệp tin cấu hình, ta dùng <source>
để chỉ định nơi ta thu thập log, sau đó ta dùng <match>
để chuyển log tới Elasticsearch. Tiếp theo ta tạo tệp tin application.yaml
.
apiVersion: apps/v1
kind: Deployment
metadata:
name: busybox
labels:
component: busybox
spec:
strategy:
type: Recreate
selector:
matchLabels:
component: busybox
template:
metadata:
labels:
component: busybox
spec:
containers:
- name: busybox
image: busybox
args:
- sh
- -c
- >
while true;
do
echo $(date) - filebeat log >> /var/log/access.log;
sleep 10;
done
volumeMounts:
- name: log
mountPath: /var/log
- name: fluentd
image: govtechsg/fluentd-elasticsearch
volumeMounts:
- name: fluentd-config
mountPath: /fluentd/etc
- name: log
mountPath: /var/log
volumes:
- name: log
emptyDir: {}
- name: fluentd-config
configMap:
name: fluentd-config
Tương như khi ta khai báo Filebeat. Chạy câu lệnh apply để tạo resource.
kubectl apply -f . --recursive
Fluentd Plugin
Điểm quan trọng cần lưu ý là để ta có thể chuyển được log tới Elasticsearch thì cần phải sử dụng Fluentd Elasticsearch Plugin. Ở trên ta đang dùng Image govtechsg/fluentd-elasticsearch
, trong Image này nó có sẵn Elasticsearch Plugin.
Nếu ta dùng Image fluent/fluentd
mặc định của Fluentd thì khi chạy sẽ có lỗi xuất hiện là không tìm thấy cấu hình cho @type elasticsearch
. Để cài Plugin thì ta viết Dockerfile như sau:
FROM fluent/fluentd:v1.12.0-debian-1.0
USER root
RUN gem install fluent-plugin-elasticsearch --version 5.0.3
USER fluent
Danh sách toàn bộ plugin của fluentd https://www.fluentd.org/plugins/all.
Kết luận
Vậy là ta đã tìm hiểu xong cách dùng Sidecar Container để triển khai Logstash và FluentD. ELK (Elasticsearch Logstash Kibana) - EFK (Elasticsearch FluentD Kibana) là hai Tech Stack rất phổ biến và tùy vào trường hợp ta sẽ sử dụng công cụ phù hợp.
Nếu bài viết có gì sai hoặc cần cập nhật thì liên hệ Admin.
Tham gia nhóm chat của DevOps VN tại Telegram.
Kém tiếng Anh và cần nâng cao trình độ giao tiếp: Tại sao bạn học không hiệu quả?