loki 自定义部署配置

前言

之前有简单的提到 loki 的部署和基本的一些使用,能支持用户最基本的在 k8s 中的部署和使用,非常简单。但是因为很多配置是默认的以至于并不满足需求,所以这里就来更新一下一些自定义配置的更改以便更好的支持当前的使用。下面举例包括:

  • 过期日志如何删除?如何只保留 14 天的日志
  • 如何更换 loki 的存储位置
  • 非 stdout 输出日志的项目如何进行日志采集?
  • 日志采集 promtail 配置有什么需要注意的地方

下面以 helm 默认部署 loki 之后为例进行修改

如何配置定期删除过期日志

我们最常见的一个需求就是只保留固定天数的日志,因为由于日志量大,所以过期的日志不做保留,以避免磁盘占用量过大。那么在 loki 里面配置也很简单。

官方文档位置:https://grafana.com/docs/loki/latest/operations/storage/retention/

如果你使用 helm 进行部署,那么 loki 的配置文件位置是在 Secrets 下的,名称默认为 loki。

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
chunk_store_config:
max_look_back_period: 24h
limits_config:
enforce_metric_name: false
reject_old_samples: true
reject_old_samples_max_age: 168h
schema_config:
configs:
- from: "2020-10-24"
index:
period: 24h
prefix: index_
chunks:
period: 24h
prefix: chunk_
object_store: filesystem
schema: v11
store: boltdb-shipper
storage_config:
boltdb_shipper:
active_index_directory: /data/loki/boltdb-shipper-active
cache_location: /data/loki/boltdb-shipper-cache
cache_ttl: 24h
shared_store: filesystem
filesystem:
directory: /data/loki/chunks
table_manager:
retention_deletes_enabled: true
retention_period: 24h

最重要的配置就是 table_manager 其中的 24h 就表示只保存 24 小时的日志

这里第一个坑就出现了,注意 loki 需要配置的保留时间必须为 24 小时的倍数,比如你配置 1h 或者 23h 都是会报错的,详情问题见:https://cloud.tencent.com/developer/article/1668946

其他的配置中:max_look_back_period 指的是最大的查询时间,reject_old_samples_max_age 是拒绝采样的时间,还有 chunk 以多少小时分隔等,比较好理解,详情见文档即可。

如果想知道删除是否生效(很多人都以为删除配置了之后好像看不出来到底是否有效),可以过一段时间后直接在 loki 的日志中搜索:{app=”loki”} |= “retention” ,当出现 file has exceeded the retention period, removing it 则证明删除配置生效,表示当前检测到了过期的日志主动将它删除了

如何修改 loki 存储日志位置

当我们的日志收集上来之后,loki 会进行存储和压缩,变成一个个 chunk 那么默认的情况下,以 helm 部署的话,给到的存储是 volumes 挂到了 emptyDir

第二个坑就是,如果默认以 helm 部署 loki 不做修改配置,那么只要 loki 重启那么之前收集的日志就全都会被删除

故你只需要将存储位置找个 volumes 挂载就可以了,这里我使用的是我指定的一个 pvc,这里就不赘述这个 pvc 和 pv 的创建了。

在 loki 的 statefulset 的配置中修改对应位置

1
2
3
- name: storage
persistentVolumeClaim:
claimName: persistent-volume-loki-claim

这里还有一个坑,因为挂载的 volume 的路径权限不同,可能出现没有权限写入的问题,故可能需要在配置中指定 root 权限或者根据具体权限进行调整,详情问题见:https://github.com/grafana/loki/issues/2018

1
2
3
4
securityContext:
runAsGroup: 0
runAsNonRoot: false
runAsUser: 0

当然存储不一定要存文件,loki 还支持存储到别的地方如:Cassandra、GCS 等 https://grafana.com/docs/loki/latest/storage/

非 stdout 日志(以文件形式) 如何进行采集

使用 helm 部署 loki 的时候,默认会部署 loki-promtail 的 daemonset 然后利用 promail 的 k8s 发现机制去发现所有 pod 对应的日志,从而进行收集。这样收集非常方便,在于你不需要对原有的项目部署做任何的处理,但是,因为采集的是 pod 的日志,那么如果有一些项目只是将日志输出到文件中如何进行采集呢?

在收集 k8s 应用日志的时候,官方给出了两种方案,一种是DaemonSet 另一种方案就是 Sidecar 将 promtail 作为一个 sidecar 挂到对应的你需要采集日志的 deployment 中,并且指定对应的文件路径即可。https://grafana.com/docs/loki/latest/clients/promtail/installation/

而这里我们需要使用的就是 sidecar 的部署方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
containers:
- name: promtail
image: grafana/promtail:2.1.0
imagePullPolicy: Always
args:
- "-config.file=/etc/promtail/promtail.yaml"
- "-client.url=http://loki.your-namespace.svc.cluster.local:3100/loki/api/v1/push"
volumeMounts:
- name: promtail-config-volume
mountPath: /etc/promtail
- name: your-app
mountPath: /logs
readOnly: true
ports:
- name: http-metrics
containerPort: 3101
protocol: TCP
env:
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName

这里需要注意的是:

  • protail 的配置文件应该做个 configmap
  • args 中需要指定正确的 loki 推送的路径,注意其中的 namespace 要正确
  • 需要将日志的位置挂载到 promtail 中,这样 promtail 才可以访问到这个日志文件
  • promtail 的版本最好和当前 loki 部署时对应的 promtail 版本一致避免问题

下面就是 promtail 的配置了,这个配置可以根据自己的需要进行调整,主要是采集的频率,文件位置等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
client:
backoff_config:
max_period: 5s
max_retries: 20
min_period: 100ms
batchsize: 102400
batchwait: 1s
timeout: 10s
server:
http_listen_port: 3101

positions:
filename: /logs/promtail/positions.yaml

target_config:
sync_period: 10s
scrape_configs:
- job_name: custom
static_configs:
- targets:
- localhost
labels:
job: your-app-name
__path__: /logs/*.log

这里需要注意:

  • positions:这个 positions 的文件是记录了当前采集日志采集到了多少行,如果你的日志文件是持久化进行存储的,那么这个地方的 positions 文件也需要持久化存储,如果没有配置,默认是放在 var 下面,这样的话重启就会丢失,即重启后日志会重新从第一行开始读取,导致日志重复。
  • scrape_configs 这边还可以指定额外的标签,经过实际测试,当前我的版本为 2.1.0 是不支持 relabel pod 中的标签,但是你可以通过环境变量的方式去传递所需要的标签具体见下文
  • 在 grafana 中展示筛选的时候需要使用 你定义的 label 或者使用 filename 做筛选,才能正确查询到你收集的对应日志

当然针对不同的日志格式 promtail 支持 pipeline 的处理,具体见 https://www.qikqiak.com/k8strain2/logging/loki/promtail/#pipeline

使用环境变量的传递 pod 信息作为 label

我们采集文件类型的日志时,势必想知道当前的日志是由那个 pod 来的,这个方案我也寻找了很久,因为 loki 本身不支持这样操作,所以我们需要通过环境变量的方式去传递进 sidecar 中,这样就能使用 pod 的信息作为 label 来发送了

首先我们需要修改部署文件中的 args 参数添加 -config.expand-env=true ,然后再 env 中指定你需要传递的环境变量,这里我指定了 pod 的名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
containers:
- name: promtail
image: grafana/promtail:2.1.0
imagePullPolicy: Always
args:
- "-config.expand-env=true"
- "-config.file=/etc/promtail/promtail.yaml"
- "-client.url=http://loki.your-namespace.svc.cluster.local:3100/loki/api/v1/push"
env:
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name

然后你就可以在配置文件中使用 ${} 来获取到对应的环境变量的值了,这里我指定了上面传递的 POD_NAME

1
2
3
4
5
6
7
8
9
scrape_configs:
- job_name: custom
static_configs:
- targets:
- localhost
labels:
pod: ${POD_NAME}
job: your-app-name
__path__: /logs/*.log

参考链接

日志收集配置:https://blog.cong.moe/post/2020-08-08-use_loki_as_k8s_log_collector_2/

实际使用案例:https://mp.weixin.qq.com/s/-IvWfhXbm3WXFIBtbrhX-A 这个案例给我很多数据支持,如果建立在这个案例真实的情况下,实际我们现在的使用情况应该 loki 是足够满足的,包括存储容量和查询效率均可以满足当前我们自身的使用需求