菜单
开源

管理和调试错误

“Loki: 网关错误。502”

当 Grafana Loki 作为数据源添加到 Grafana 中时,可能会出现此错误,表明 Grafana 无法连接到 Loki。可能的原因有很多:

  • 如果 Loki 是使用 Docker 部署的,并且 Grafana 和 Loki 未运行在同一节点上,请检查您的防火墙以确保节点可以连接。
  • 如果 Loki 是使用 Kubernetes 部署的
    • 如果 Grafana 和 Loki 位于同一命名空间中,请将 Loki URL 设置为 http://$LOKI_SERVICE_NAME:$LOKI_PORT
    • 否则,请将 Loki URL 设置为 http://$LOKI_SERVICE_NAME.$LOKI_NAMESPACE:$LOKI_PORT

“数据源已连接,但未接收到任何标签。请验证 Loki 和 Promtail 配置是否正确。”

当 Loki 作为数据源添加到 Grafana 中时,可能会出现此错误,表明 Grafana 已连接到 Loki,但 Loki 尚未从 Promtail 收到任何日志。可能的原因有很多:

  • Promtail 正在运行并收集日志,但无法连接到 Loki 发送日志。检查 Promtail 的输出。
  • Promtail 在 Loki 准备就绪之前就开始向 Loki 发送日志。这可能发生在测试环境中,Promtail 已经读取并发送了所有日志。您可以这样做:
    • 在 Loki 之后启动 Promtail,例如 60 秒后。
    • 要强制 Promtail 重新发送日志消息,请删除 positions 文件(默认位置 /tmp/positions.yaml)。
  • 由于配置问题,Promtail 正在忽略目标,并且没有读取任何日志。
    • 可以通过在 Promtail 中开启调试日志,查找 dropping target, no labelsignoring target 消息来检测此问题。
  • Promtail 找不到您的日志文件位置。检查 scrape_configs 是否包含用于在您的工作节点上查找日志的有效路径设置。
  • 您的 pod 运行时的标签与 Promtail 配置读取的标签不同。检查 scrape_configs 进行验证。

Loki 超时错误

Loki 504 错误、上下文取消和处理请求错误可能有许多可能的原因。

  • 检查 Loki 配置

    • Loki 配置 limits_config.query_timeout
    • server.http_server_read_timeout
    • server.http_server_write_timeout
    • server.http_server_idle_timeout
  • 检查您的 Loki 部署。如果您在 Loki 前面(即 Loki 和 Grafana 之间)有一个反向代理,请检查任何配置的超时设置,例如 NGINX 代理读取超时。

  • 其他原因。要确定问题是与 Loki 本身还是与 Grafana 或客户端错误等其他系统有关,请尝试尽可能直接地运行 LogCLI 查询。例如,如果在虚拟机上运行,请在本地机器上运行查询。如果在 Kubernetes 集群中运行,则端口转发 Loki HTTP 端口,然后尝试在那里运行查询。如果您没有遇到超时,则考虑以下原因:

    • 调整 Grafana dataproxy 超时。为 Grafana 配置足够大的 dataproxy 超时。
    • 检查客户端与 Grafana 之间的反向代理或负载均衡器的超时设置。对 Grafana 的查询是从您的本地浏览器发起的,Grafana 充当代理(dataproxy)。因此,必须配置从您的客户端到 Grafana 的连接超时。

缓存生成错误

Loki 缓存生成编号错误 (Loki >= 2.6)

加载缓存生成编号错误

  • 症状

    • Loki 在日志中暴露出错误,消息为 msg="error loading cache generation numbers" err="unexpected status code: 403"msg="error getting cache gen numbers from the store"
  • 调查

    • 检查 /metrics 上的指标 loki_delete_cache_gen_load_failures_total,这是问题发生的指示器。如果该值大于 1,则表示该组件存在问题。

    • 尝试对路由发送 Http GET 请求:/loki/api/v1/cache/generation_numbers

      • 如果响应为 "deletion is not available for this tenant",则表示该租户未启用删除 API。要启用此 API,请通过配置设置将该租户的 allow_deletes 设置为 true。查看更多 删除文档

目标故障排除

Promtail 提供了两个可用于了解其服务发现工作原理的网页。

服务发现页面 (/service-discovery) 显示所有已发现的目标及其重新打标签前后的标签,以及目标被丢弃的原因。

目标页面 (/targets) 仅显示正在活跃抓取的目标及其相应的标签、文件和位置。

在 Kubernetes 上,您可以通过本地端口转发 Promtail 端口(使用 Helm 时为 90803101)访问这两个页面

bash
$ kubectl port-forward loki-promtail-jrfg7 9080

然后,在 Web 浏览器中访问 https://:9080/service-discovery

调试输出

Loki 和 Promtail 都支持通过添加命令行选项来设置日志级别标志

bash
loki -log.level=debug
bash
promtail -log.level=debug

创建目标失败,ioutil.ReadDir: readdirent: not a directory

Promtail 配置中包含一个 __path__ 条目指向一个 Promtail 找不到的目录。

连接到 Promtail Pod 进行故障排除

首先检查上面的目标故障排除部分。如果仍无法解答您的问题,您可以连接到 Promtail Pod 进行进一步调查。

如果您的集群中以 DaemonSet 方式运行 Promtail,则每个节点上都会有一个 Promtail Pod,因此请先确定您需要调试哪个 Promtail。

shell
$ kubectl get pods --all-namespaces -o wide
NAME                                   READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE
...
nginx-7b6fb56fb8-cw2cm                 1/1     Running   0          41d   10.56.4.12     node-ckgc   <none>
...
promtail-bth9q                         1/1     Running   0          3h    10.56.4.217    node-ckgc   <none>

该输出已截断,仅突出显示我们关心的两个 pod,您可以使用 -o wide 标志查看它们正在运行的 NODE。

您需要将您关注的 Pod(在此示例中为 NGINX)的节点与在同一节点上运行的 Promtail 相匹配。

要进行调试,您可以连接到 Promtail Pod

shell
kubectl exec -it promtail-bth9q -- /bin/sh

连接后,验证 /etc/promtail/promtail.yml 中的配置是否包含您期望的内容。

还要检查 /var/log/positions.yaml(通过 Helm 部署时为 /run/promtail/positions.yaml 或为 positions.file 指定的任何值),并确保 Promtail 正在跟踪您期望的日志。

您可以通过查看 /var/log/containers 中的 Promtail 容器日志来检查 Promtail 日志。

为 Loki 启用跟踪

通过将环境变量 JAEGER_AGENT_HOST 设置为 Jaeger 运行的主机名和端口,可以使用 Jaeger 对 Loki 进行跟踪。

如果您使用 Helm 部署,请使用以下命令

bash
$ helm upgrade --install loki loki/loki --set "loki.tracing.enabled=true"
  --set "read.extraEnv[0].name=JAEGER_AGENT_HOST"    --set "read.extraEnv[0].value=<JAEGER_AGENT_HOST>"
  --set "write.extraEnv[0].name=JAEGER_AGENT_HOST"   --set "write.extraEnv[0].value=<JAEGER_AGENT_HOST>"
  --set "backend.extraEnv[0].name=JAEGER_AGENT_HOST" --set "backend.extraEnv[0].value=<JAEGER_AGENT_HOST>"
  --set "gateway.extraEnv[0].name=JAEGER_AGENT_HOST" --set "gateway.extraEnv[0].value=<JAEGER_AGENT_HOST>"

在 Istio Sidecar 中运行 Loki

Istio sidecar 与 Pod 一起运行。它拦截进出 Pod 的所有流量。当 Pod 尝试使用给定协议与另一个 Pod 通信时,Istio 使用 协议选择 来检查目标服务。此机制使用端口名称约定(例如,http-my-portgrpc-my-port)来确定如何处理此出站流量。然后,Istio 可以执行授权和智能路由等操作。

当一个 Pod 使用主机名与另一个 Pod 通信时,这工作正常。但是,Istio 不允许 Pod 使用 IP 地址与另一个 Pod 通信,除非流量类型是 tcp

Loki 内部使用 DNS 解析不同组件的 IP 地址。Loki 尝试向这些 Pod 的 IP 地址发送请求。Loki 服务定义了 grpc (:9095/:9096) 端口,因此 Istio 会认为这是 grpc 流量。它将不允许 Loki 组件使用 IP 地址相互访问。因此,流量将失败,并且环将保持不健康状态。

此问题的解决方案是向 Loki 组件的所有 grpc (:9095) 和 grpclb (:9096) 服务端口添加 appProtocol: tcp。这会覆盖 Istio 的协议选择,并强制 Istio 将此流量视为原始 tcp,从而允许 Pod 使用原始 IP 地址进行通信。

这会禁用 Istio 流量拦截机制的一部分,但仍然启用 mTLS。这允许 Pod 通过 grpc 使用 IP 地址相互通信。