关于日志收集,鄙人最早接触到的是 ELK 那一套(Elasticsearch、Logstash 和 Kibana),最近我青训营的项目也是差不多的架构,但是这一套下来资源占用也太可怕了(特别是 Elasticsearch ,太重了)

image-20230319212648673

image-20230319213630597

go-zero 官方也说了,这一套不建议在小规模的服务上使用,而我一般的实际项目也没多大规模,根本用不上这么重的解决方案,所以我需要找一套更轻量的解决方案

翻了一圈,感觉推荐 Grafana + Loki 的不少

然后我就跑去 Loki官方文档

image-20230319220344596

这是官方文档中的快速上手的架构图,为了让你感受它的可扩展性,就把内部的读写部分拆出来运行,其实不用这么复杂,直接一个单体也可以

折腾了一圈,大概是这么个逻辑:首先是要有一个 Client(例如图中的 Promtail )去拉取运行日志喂给 Loki ,然后 Loki 去读写 Storage(例如图中的 Minio ),那日志要怎么方便地查看呢?用 Grafana ,这东西界面做的真的很好看

为了让你快速理解与上手,我简化了一下官方 Demo,docker-compose 中只包含四个服务:

  • 产生日志的程序:和官方一样使用了 flog 来不停地向标准输出中放入假日志

  • Loki:用于打包日志、打标签等

  • Client:用于拉取日志交给 Loki,Loki 支持多种客户端,你可以在 Grafana Loki clients 中查看支持的所有客户端

    我知道有一个 Docker Driver ,但是这东西要给 Docker 装插件,感觉有点麻烦,还是和官方例子一样使用了 Promtail

  • Storage:用于保存日志,你可以在 Storage 中查看所有支持的存储介质,甚至存储为本地文件都行

    这里和官方例子一样使用了兼容亚马逊 S3协议的 minio 作为存储介质

  • Grafana:用于提供一个好看的可视化界面

先新建一个文件夹,进去创建三个文件:

1
2
3
4
.
|-- docker-compose.yaml
|-- loki-config.yaml
`-- promtail-config.yaml

docker-compose.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
version: "3"

networks:
loki:


services:
loki:
image: grafana/loki:2.7.1
container_name: loki
ports:
- 3100:3100
volumes:
- ./loki-config.yaml:/etc/loki/local-config.yaml
command: -config.file=/etc/loki/local-config.yaml
depends_on:
- minio
networks:
- loki

promtail:
image: grafana/promtail:2.7.1
container_name: promtail
volumes:
- ./promtail-config.yaml:/etc/promtail/promtail-config.yaml
- /var/run/docker.sock:/var/run/docker.sock # 直接把本机的docker套接字映射进去,这样就可以直接抓取所有容器的日志了
command: -config.file=/etc/promtail/promtail-config.yaml
networks:
- loki

grafana:
image: grafana/grafana:latest
container_name: grafana
environment:
- GF_PATHS_PROVISIONING=/etc/grafana/provisioning
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
ports:
- 3000:3000
command: -config /etc/grafana/grafana.ini
networks:
- loki

minio:
image: minio/minio
container_name: minio
entrypoint:
- sh
- -euc
- |
mkdir -p /data/loki-data && \
mkdir -p /data/loki-ruler && \
minio server /data
environment:
- MINIO_ACCESS_KEY=loki
- MINIO_SECRET_KEY=supersecret
- MINIO_PROMETHEUS_AUTH_TYPE=public
- MINIO_UPDATE=off
ports:
- 9000
volumes:
- ./.data/minio:/data
networks:
- loki

flog:
image: mingrammer/flog
container_name: flog
command: -f json -d 1s -l
networks:
- loki

loki-config.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
---
auth_enabled: false
server:
http_listen_port: 3100
memberlist:
join_members:
- loki:7946
schema_config:
configs:
- from: 2021-08-01
store: boltdb-shipper
object_store: s3
schema: v11
index:
prefix: index_
period: 24h
common:
path_prefix: /loki
replication_factor: 1
storage:
s3:
endpoint: http://minio:9000
insecure: true
bucketnames: loki-data
access_key_id: loki
secret_access_key: supersecret
s3forcepathstyle: true
ring:
kvstore:
store: memberlist
ruler:
storage:
s3:
bucketnames: loki-ruler

promtail-config.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server:
http_listen_port: 9080
grpc_listen_port: 0

positions:
filename: /tmp/positions.yaml

clients:
- url: http://loki:3100/loki/api/v1/push
tenant_id: tenant1

scrape_configs:
- job_name: flog_scrape
docker_sd_configs: # 对于promtail来说,又可以定义各种日志来源,请见 https://grafana.com/docs/loki/latest/clients/promtail/configuration/#scrape_configs
- host: unix:///var/run/docker.sock # 这里直接从docker套接字拿日志
refresh_interval: 5s
relabel_configs:
- source_labels: ['__meta_docker_container_name'] # 根据容器名打标签分类
regex: '/(.*)'
target_label: 'container' # 标签名为 container

准备好了之后,运行 docker-compose 文件

1
docker-compose up

然后来到 127.0.0.1:3000 进入Grafana

image-20230319224216330

点击左下角添加数据源,选择 Loki

image-20230319224322305

URL填写为 http://loki:3100

image-20230319224436992

再来到 Explore,选择要看的容器为 flog

image-20230319224456334

它居然会自动提示你添加 JSON 解析

image-20230319224653449

然后你就可以根据字段添加检索条件了,比方说状态码限定为 200

image-20230319224734800

我只能说简直不要太舒服了

接下来你就可以把这一套放在你的项目里面了,你可以监听某个容器,或者监听某个日志文件,又或者监听某个卡夫卡队列,都可以,随便你折腾了

(PS:你的容器不能启用 tty https://github.com/grafana/loki/issues/5950#issuecomment-1223979118

image-20230320123644774

最后来看看资源占用,内存 200MB 左右,相对来说轻量了不少