Loki 是一款易于水平扩展、高可用的日志聚合系统。
对比其他日志聚合系统,Loki 具有的优势:
我们使用 Grafana 官方提供的 Helm Charts 部署一套 Loki 日志系统,包括以下组件:
兼容 AWS S3 API 的对象存储都可以,例如:
Loki 与存储之间需要有大带宽,不推荐跨云跨区域部署。
需要具有以下权限的访问密钥:
不同云平台授权策略有差异,如果遇到权限不足,请改成整个 Bucket 完整读写权限。
## 添加加速镜像仓库
helm repo add grafana "https://helm-charts.itboon.top/grafana" --force-update
helm repo update grafana
## 添加官方仓库
# helm repo add grafana "https://grafana.github.io/helm-charts" --force-update
# helm repo update grafana
加速镜像仓库 完全从官方克隆
## values-loki.yaml
fullnameOverride: loki
rbac:
namespaced: true
loki:
auth_enabled: false
image:
# registry: docker.io
# repository: grafana/loki
tag: 2.9.6
readinessProbe:
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 1
## loki.config
commonConfig:
## set to 1, otherwise more replicas are needed to connect to grafana
replication_factor: 1
storage:
bucketNames:
chunks: Your_Loki_Bucket
ruler: Your_Loki_Bucket
admin: Your_Loki_Bucket
type: s3
s3:
## s3 access, AWS S3 或者兼容 S3 API 的对象存储都可以
endpoint: cos.ap-guangzhou.myqcloud.com
accessKeyId: Your_Access_Key_ID
secretAccessKey: Your_Secret_Access_Key
compactor:
working_directory: /var/loki/retention
shared_store: s3
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ingester:
max_transfer_retries: 0
# max_chunk_age: 2h # default = 2h
# chunk_idle_period: 30m # default = 30m
# chunk_target_size: 1572864
chunk_encoding: zstd
autoforget_unhealthy: true
storage_config:
tsdb_shipper:
active_index_directory: /var/loki/tsdb-index
cache_location: /var/loki/tsdb-cache
cache_ttl: 72h
shared_store: s3
schemaConfig:
configs:
- from: 2024-01-01
store: tsdb
object_store: s3
schema: v12
index:
prefix: loki_tsdb_index_
period: 24h
limits_config:
ingestion_rate_strategy: local # default = "global"
# retention_period: 240h
ingestion_rate_mb: 20 # default = 4
ingestion_burst_size_mb: 100 # default = 6
per_stream_rate_limit: 6MB # default = 3MB
per_stream_rate_limit_burst: 50MB # default = 15MB
max_concurrent_tail_requests: 20
max_cache_freshness_per_query: 10m
max_query_length: 72h
max_line_size: 256kb
max_line_size_truncate: true
## [max_streams_matchers_per_query: <int> | default = 1000]
## [max_query_bytes_read: <int> | default = 0B]
shard_streams:
enabled: true
desired_rate: 2097152 #2MiB
server:
grpc_server_max_recv_msg_size: 32000100 # default = 4194304
grpc_server_max_send_msg_size: 32000100 # default = 4194304
test:
enabled: false
monitoring:
lokiCanary:
enabled: false
dashboards:
enabled: false
selfMonitoring:
enabled: false
grafanaAgent:
installOperator: false
serviceMonitor:
enabled: false
#sidecar:
# resources:
# limits:
# cpu: 200m
# memory: 500Mi
# requests:
# cpu: 10m
# memory: 50Mi
gateway:
replicas: 1
#resources:
# limits:
# cpu: 1
# memory: 2Gi
# requests:
# cpu: 50m
# memory: 200Mi
#service:
# type: LoadBalancer
backend:
replicas: 1
persistence:
size: 20Gi
enableStatefulSetAutoDeletePVC: false
#storageClass: null
#resources:
# limits:
# cpu: 2
# memory: 8Gi
# requests:
# cpu: 100m
# memory: 500Mi
write:
replicas: 1
persistence:
size: 20Gi
#storageClass: null
#resources:
# limits:
# cpu: 2
# memory: 8Gi
# requests:
# cpu: 500m
# memory: 4Gi
read:
replicas: 3
resources:
limits:
cpu: 1
memory: 2Gi
requests:
cpu: 50m
memory: 100Mi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 15
targetCPUUtilizationPercentage: 90
values-loki.yaml
文件。endpoint
, bucketnames
, access_key_id
, secret_access_key
正确的 endpoint 字段不含 Bucket 名称
## 部署 Loki
helm upgrade --install loki \
--namespace loki \
--create-namespace \
-f values-loki.yaml \
--version 5.47.1 \
grafana/loki
## values-promtail.yaml
image:
tag: 2.9.6
#resources:
# limits:
# cpu: 2
# memory: 2Gi
# requests:
# cpu: 100m
# memory: 512Mi
config:
clients:
- url: http://loki-gateway/loki/api/v1/push
snippets:
extraLimitsConfig: |
max_line_size: 256kb
max_line_size_truncate: true
readline_rate_enabled: true
readline_rate: 110000 # default = 10000
readline_burst: 810000 # default = 10000
pipelineStages:
- cri: {}
# - match:
# ## 过滤某些 namespace
# selector: '{namespace=~"Your_Namespace"}'
# action: drop
# - match:
# ## 过滤某些 container
# selector: '{container=~"Your_Container_Name"}'
# action: drop
- json:
expressions:
log: log
- output:
source: log
- multiline:
## 跨行合并
firstline: '^\S'
max_wait_time: 3s
max_lines: 2000
#- match:
# ## 匹配标签的日志将进行额外管道处理
# selector: '{container=~"java.*"}'
# stages:
# - multiline:
# firstline: '^[A-Z]{3,9} +\['
# max_wait_time: 3s
# max_lines: 2000
# - regex:
# expression: '^(?P<level>[A-Z]{3,9}) +\[.*'
# #source: log
# - labels:
# level:
将上面的 Values 保存到 values-promtail.yaml
文件。
## 部署 Promtail
helm upgrade --install promtail \
--namespace loki \
--create-namespace \
-f values-promtail.yaml \
--version 6.15.5 \
grafana/promtail
## values-grafana.yaml
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Loki
type: loki
url: http://loki-gateway
access: proxy
jsonData:
maxLines: 500
# ingress:
# enabled: true
# ingressClassName: nginx
# annotations: {}
# # kubernetes.io/ingress.class: nginx
# # kubernetes.io/tls-acme: "true"
# hosts:
# - grafana.example.com
resources:
limits:
cpu: 100m
memory: 1Gi
requests:
cpu: 20m
memory: 128Mi
将上面的 Values 保存到 values-grafana.yaml
文件。
## 部署 Grafana
helm upgrade --install grafana \
--namespace loki \
--create-namespace \
-f values-grafana.yaml \
--version 7.3.7 \
grafana/grafana
获取 Grafana 初始 admin 密码:
## 获取 Grafana 初始 admin 密码
kubectl get secret -n loki grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
上面的部署案例已经在数据压缩、索引、HPA 等方面进行优化了。
Loki 默认使用 gzip 压缩算法,但是 gzip 解压速度比较慢,推荐使用 zstd 压缩,两者的比较请参考 从 gzip 切换到 zstd
loki:
ingester:
chunk_encoding: zstd
Loki v2.8 引入的 TSDB 比旧版本的索引方案具有更优的性能,请参考 官方文档
loki:
storage_config:
tsdb_shipper:
loki:
limits_config:
ingestion_rate_strategy: local # default = "global"
# retention_period: 240h
ingestion_rate_mb: 20 # default = 4
ingestion_burst_size_mb: 100 # default = 6
per_stream_rate_limit: 6MB # default = 3MB
per_stream_rate_limit_burst: 50MB # default = 15MB
max_concurrent_tail_requests: 20
max_cache_freshness_per_query: 10m
max_query_length: 72h
max_line_size: 256kb
max_line_size_truncate: true
## [max_streams_matchers_per_query: <int> | default = 1000]
## [max_query_bytes_read: <int> | default = 0B]
shard_streams:
enabled: true
desired_rate: 2097152 #2MiB
server:
grpc_server_max_recv_msg_size: 32000100 # default = 4194304
grpc_server_max_send_msg_size: 32000100 # default = 4194304
假如日志格式是这样的:
[INFO] Reloading
[INFO] plugin/reload: Running configuration SHA512 = 637429c29e6628b9c013e5f8bd5211d4564943dd9f2dd6eeb506a5a2993177f61da856d85e9ed3c8020ebde2b4abbc232f057d9ba5d9df8247d706893feb8754
[INFO] Reloading complete
[ERROR] plugin/errors: 2 cm-cn-central-00001.albatross.10086.cn. HTTPS: read tcp 10.4.63.250:47580->100.100.2.136:53: i/o timeout
在部署 Promtail 的时候可以提取日志级别作为标签:
- match:
## 匹配容器名以 java 开头的容器
selector: '{container=~"java.*"}'
stages:
- multiline:
## 跨行合并
firstline: '^\[[A-Z]{3,9}\] '
max_wait_time: 3s
max_lines: 2000
- regex:
expression: '^\[(?P<level>[A-Z]{3,9})\] '
#source: log
- labels:
level:
上面这个案例会提取每条日志从行首开始中括号里的大写字母并打上 level 标签,查询条件加上 level 标签可以显著提升查询效率。
自定义标签需要根据日志格式和内容进行设置,这里仅仅演示一下实现方法。
不要使用动态标签,关于动态标签并没有固定的标准。假如一个 Pod 一小时日志量有 100 万条,某个标签会产生超过 1 万个值,那这个标签肯定就属于动态标签。标签需要把日志分类打散,但是不能太散。
查询的语句的标签和时间区段决定了 Loki 需要从存储中取出并处理的数据量。如果这个数据量在 10GB 以下,那问题不大。如果达到百GB级别,那就存在性能问题了。
假如有一个 pod coredns-79f4544dbb-8ck2b
, 一天产生超过 100GB 的日志(压缩前 100GB),我们一次性查询一天的日志数据,从中找出符合条件的内容。
{pod="coredns-79f4544dbb-8ck2b"}
查询一天的日志,Loki 一次处理 100GB 日志会比较慢。{pod="coredns-79f4544dbb-8ck2b",level="ERROR}
就很轻松了。解决的办法就是合理设置标签,比如日志级别、功能模块、事件类型等。
查询的语句的标签和时间区段决定了 Loki 需要处理的数据量,标签越具体查询效率越高,以下列举一些查询语句及评分:
{namespace="kube-system"} |= "timeout"
时间区段最近 24 小时{namespace="kube-system",pod=~"coredns-.*"} |= "timeout"
时间区段最近 24 小时{pod="coredns-79f4544dbb-8ck2b"} |= "timeout"
时间区段最近 24 小时{pod="coredns-79f4544dbb-8ck2b"} |= "timeout"
时间区段最近 1 小时{pod="coredns-79f4544dbb-8ck2b",level="ERROR} |= "timeout"
时间区段最近 1 小时如果日志量比较大,建议 Kubernetes 节点选择 10G 以上的网络带宽,因为 Querier 可以分布到多个节点,所以节点网络带宽的压力可以稀释,带宽瓶颈会转移到后端存储。如果云平台对象存储的性能不能满足需求,可以考虑裸机部署 MinIO 存储。
查询性能存在瓶颈并不能掩盖 Loki 独特的优势,实际上微服务架构中的 Loki 异常坚固,哪怕多个大型查询并发造成堵塞,Loki 依然可以稳定地摄入新数据。
后续章节会完善上述内容,敬请期待。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。