为什么要统一采集日志
- 集群中同一个服务部署了多个实例,每个实例日志各自分散在不同服务器上,无法预知某条日志在哪台服务器。
- 处理一个请求,可能会跨越多个服务,想查看属于同一请求的全链路日志,不可能是每台服务器分别去查。
实践方案
- 使用 Elasticsearch 保存日志;
- 使用 Logstash 采集日志,切割日志,转化为结构化的信息,并发送到 Elasticsearch;
- 业务服务的日志文件输出到宿主机的指定目录;
- 在 Kibana 查看采集的日志。
部署前提
- 已经有可用的 Elasticsearch 集群,本文中不涉及 ES 集群本身的部署;
- 如果 ES 集群是安全模式的,还要拿到 SSL 证书;
- 业务服务已经部署好,可以正常输出日志;
- 已经有可用的 Kibana ,本文中不涉及 Kibana 本身的部署。
部署Logstash
为什么选用 Logstash
据资源显示,Filebeat 运行时占用的资源比 Logstash 少一些,使用性价比更高。但是我这次使用的 ES 集群是安全模式,公有云厂商却不能提供 Filebeat 所需的 SSL 证书文件,所以改用 Logstash。
上传 Logstash-oss 镜像
因为是要往 ES 发送数据,必须使用 Logstash-oss 的镜像,版本号最好和 ES 的版本相同。
下载地址 www.docker.elastic.co/r/logstash/…。
创建 SSL 证书配置项
kind: ConfigMap
apiVersion: v1
metadata:
name: ssl-certificate.cer
namespace: mojiayi-prod-logging
data:
ssl-certificate.cer: |
从 cer 文件复制得来的证书内容
创建 Logstash 启动配置
- 在 input 区块中指定被采集的日志文件目录;
- 在 filter 区块中使用 gork 对日志进行切割,转换成结构化信息;
- 在 output 区块中添加往 ES 发送信息的配置项。
kind: ConfigMap
apiVersion: v1
metadata:
name: logstash.conf
namespace: mojiayi-prod-logging
data:
logstash.conf: |-
input{
file{
path => "/tmp/logs/*"
}
}
filter {
grok {
match => {"message" => "%{TIMESTAMP_ISO8601:time}\|%{DATA:level}\|%{DATA:traceId}\|%{DATA:thread}\|%{DATA:className}\|%{NUMBER:line}\|%{DATA:methodName}\|%{GREEDYDATA:logMsg}"}
}
}
output{
elasticsearch{
user => "es的用户名"
password => "es的密码"
hosts => ["es的IP和端口"]
cacert => "ssl .cer文件的绝对地址"
index => "log-%{+yyyy.MM.dd}"
manage_template => false
ilm_enabled => false
ssl => true
ssl_certificate_verification => true
}
}
创建Logstash守护进程
- 通过守护进程,没有专门指定亲和性时,会自动在每个节点上创建一个 Logstash 实例;
- 把 ConfigMap 中配置的 SSL 证书和 Logstash 启动配置挂载到容器中。
kind: DaemonSet
apiVersion: apps/v1
metadata:
name: logstash
namespace: mojiayi-prod-logging
spec:
selector:
matchLabels:
app: logstash
version: v1
template:
metadata:
creationTimestamp: null
labels:
app: logstash
version: v1
spec:
volumes:
- name: vol-ssl-certificate
configMap:
name: ssl-certificate.cer
defaultMode: 420
- name: vol-logstash-conf
configMap:
name: logstash.conf
defaultMode: 420
- name: vol-logstash-yml
configMap:
name: logstash.yml
defaultMode: 420
- name: logs
hostPath:
path: /tmp/logs
type: ''
containers:
- name: container-logstash
image: 镜像域名/组织名/docker.elastic.co/logstash/logstash-oss:7.6.2
args:
- '-f'
- /usr/local/share/logstash.conf
resources:
limits:
cpu: 250m
memory: 512Mi
requests:
cpu: 100m
memory: 100Mi
volumeMounts:
- name: vol-logstash-yml
readOnly: true
mountPath: /usr/local/share/logstash.yml
subPath: logstash.yml
- name: vol-logstash-conf
readOnly: true
mountPath: /usr/local/share/logstash.conf
subPath: logstash.conf
- name: vol-ssl-certificate
readOnly: true
mountPath: /usr/local/share/css-certificate.cer
subPath: ssl-certificate.cer
- name: logs
mountPath: /tmp/logs
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
securityContext: {}
imagePullSecrets:
- name: default-secret
schedulerName: default-scheduler
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 0
revisionHistoryLimit: 10
在Kibana查看日志
查看有哪些日志索引
GET _cat/indices
尝试查找某次请求的日志
GET aps-log-2022.11.20/_search
{
"query": {
"match": {
"traceId": "413e9bf076c04084b2223e44739520ad"
}
},
"_source": [".time","level", "traceId", "className", "methodName", "line", "path", "logMsg"],
"sort": [
{
"@timestamp": {
"order": "asc"
}
}
]
}