12.3. 配置 LokiStack 日志存储
在日志记录文档中,LokiStack 指的是 Loki 和 Web 代理与 OpenShift Container Platform 身份验证集成的日志记录组合。LokiStack 的代理使用 OpenShift Container Platform 身份验证来强制实施多租户。Loki 将日志存储指代为单个组件或外部存储。
12.3.1. 为 cluster-admin 用户角色创建新组
以 cluster-admin
用户身份查询多个命名空间的应用程序日志,其中集群中所有命名空间的字符总和大于 5120,会导致错误 Parse error: input size too long (XXXX > 5120)
。为了更好地控制 LokiStack 中日志的访问,请使 cluster-admin
用户成为 cluster-admin
组的成员。如果 cluster-admin
组不存在,请创建它并将所需的用户添加到其中。
使用以下步骤为具有 cluster-admin
权限的用户创建新组。
流程
输入以下命令创建新组:
$ oc adm groups new cluster-admin
输入以下命令将所需的用户添加到
cluster-admin
组中:$ oc adm groups add-users cluster-admin <username>
输入以下命令在组中添加
cluster-admin
用户角色:$ oc adm policy add-cluster-role-to-group cluster-admin cluster-admin
12.3.2. 集群重启过程中的 LokiStack 行为
在日志记录版本 5.8 及更新版本中,当 OpenShift Container Platform 集群重启时,Loki ingestion 和查询路径将继续在节点的可用 CPU 和内存资源中运行。这意味着 OpenShift Container Platform 集群更新过程中,LokiStack 没有停机。此行为通过使用 PodDisruptionBudget
资源来实现。Loki Operator 为 Loki 置备 PodDisruptionBudget
资源,它决定了每个组件必须可用的最少 pod 数量,以确保特定条件下正常操作。
12.3.3. 配置 Loki 以容忍节点故障
在日志记录 5.8 及更新的版本中,Loki Operator 支持设置 pod 反关联性规则,以请求同一组件的 pod 调度到集群中的不同可用节点上。
关联性是 pod 的一个属性,用于控制它们希望调度到的节点。反关联性是 pod 的一个属性,用于阻止 pod 调度到某个节点上。
在 OpenShift Container Platform 中,可以借助 pod 关联性和 pod 反关联性来根据其他 pod 上的键/值标签限制 pod 有资格调度到哪些节点。
Operator 会为所有 Loki 组件设置默认、首选的 podAntiAffinity
规则,其中包括 compactor
, distributor
, gateway
, indexGateway
, ingester
, querier
, queryFrontend
, 和 ruler
组件。
您可以通过在 requiredDuringSchedulingIgnoredDuringExecution
字段中配置所需的设置来覆盖 Loki 组件的首选 podAntiAffinity
设置:
ingester 组件的用户设置示例
apiVersion: loki.grafana.com/v1 kind: LokiStack metadata: name: logging-loki namespace: openshift-logging spec: # ... template: ingester: podAntiAffinity: # ... requiredDuringSchedulingIgnoredDuringExecution: 1 - labelSelector: matchLabels: 2 app.kubernetes.io/component: ingester topologyKey: kubernetes.io/hostname # ...
12.3.4. 支持区域的数据复制
在日志记录 5.8 及更新的版本中,Loki Operator 通过 pod 拓扑分布限制支持区感知数据复制。启用这个功能可提高可靠性,并防止出现单一区域故障的日志丢失。在将部署大小配置为 1x.extra-small
, 1x.small
, 或 1x.medium
时,replication.factor
字段会自动设置为 2。
为确保正确复制,您需要至少具有与复制因子指定的可用区数量。虽然可用区可能会比复制因素更多,但区域数量较少可能会导致写入失败。每个区域应托管相等的实例数量,以实现最佳操作。
启用区复制的 LokiStack CR 示例
apiVersion: loki.grafana.com/v1 kind: LokiStack metadata: name: logging-loki namespace: openshift-logging spec: replicationFactor: 2 1 replication: factor: 2 2 zones: - maxSkew: 1 3 topologyKey: topology.kubernetes.io/zone 4
12.3.4.1. 从失败的区恢复 Loki pod
在 OpenShift Container Platform 中,当特定可用区资源无法访问时,会发生区失败。可用性区域是云提供商数据中心内的隔离区域,旨在增强冗余和容错能力。如果您的 OpenShift Container Platform 集群没有配置为处理此操作,则区失败可能会导致服务或数据丢失。
Loki pod 是 StatefulSet 的一部分,它们附带 StorageClass
对象置备的 PVC。每个 Loki pod 及其 PVC 驻留在同一区域中。当在集群中发生区故障时,StatefulSet 控制器会自动尝试恢复失败的区中受影响的 pod。
以下流程将删除失败的区中的 PVC,以及其中包含的所有数据。为了避免完成数据丢失的 LokiStack
CR 的 replication factor 字段,应该始终设置为大于 1 的值,以确保 Loki 复制。
先决条件
- 日志记录版本 5.8 或更高版本。
-
验证
LokiStack
CR 是否具有大于 1 的复制因素。 - control plane 检测到区失败,故障区中的节点由云供应商集成标记。
StatefulSet 控制器会自动尝试重新调度失败的区中的 pod。因为关联的 PVC 也位于失败的区中,所以自动重新调度到不同的区无法正常工作。您必须手动删除失败的区中 PVC,以便在新区中成功重新创建有状态 Loki Pod 及其置备的 PVC。
流程
运行以下命令,列出处于
Pending
状态的 pod:oc get pods --field-selector status.phase==Pending -n openshift-logging
oc get pods
输出示例NAME READY STATUS RESTARTS AGE 1 logging-loki-index-gateway-1 0/1 Pending 0 17m logging-loki-ingester-1 0/1 Pending 0 16m logging-loki-ruler-1 0/1 Pending 0 16m
- 1
- 这些 pod 处于
Pending
状态,因为它们对应的 PVC 位于失败的区中。
运行以下命令,列出处于
Pending
状态的 PVC:oc get pvc -o=json -n openshift-logging | jq '.items[] | select(.status.phase == "Pending") | .metadata.name' -r
oc get pvc
输出示例storage-logging-loki-index-gateway-1 storage-logging-loki-ingester-1 wal-logging-loki-ingester-1 storage-logging-loki-ruler-1 wal-logging-loki-ruler-1
运行以下命令,删除 pod 的 PVC:
oc delete pvc __<pvc_name>__ -n openshift-logging
然后,运行以下命令来删除 pod:
oc delete pod __<pod_name>__ -n openshift-logging
成功删除这些对象后,应在可用区域中自动重新调度它们。
12.3.4.1.1. 对处于终止状态的 PVC 进行故障排除
如果 PVC 元数据终结器被设置为 kubernetes.io/pv-protection
,PVC 可能会处于 terminating 状态。删除终结器应该允许 PVC 成功删除。
运行以下命令删除每个 PVC 的终结器,然后重试删除。
oc patch pvc __<pvc_name>__ -p '{"metadata":{"finalizers":null}}' -n openshift-logging
12.3.5. 对 Loki 日志的精细访问
在日志记录 5.8 及更高版本中,Red Hat OpenShift Logging Operator 默认不授予所有用户对日志的访问权限。作为管理员,您需要配置用户访问权限,除非 Operator 已升级并且以前的配置已就位。根据您的配置和需要,您可以使用以下内容配置对日志的精细访问:
- 集群范围内的策略
- 命名空间范围策略
- 创建自定义 admin 组
作为管理员,您需要创建适合部署的角色绑定和集群角色绑定。Red Hat OpenShift Logging Operator 提供以下集群角色:
-
cluster-logging-application-view
授予读取应用程序日志的权限。 -
cluster-logging-infrastructure-view
授予读取基础架构日志的权限。 -
cluster-logging-audit-view
授予读取审计日志的权限。
如果您从以前的版本升级,则额外的集群角色 logging-application-logs-reader
和关联的集群角色绑定 logging-all-authenticated-application-logs-reader
提供向后兼容性,允许任何经过身份验证的用户在命名空间中读取访问权限。
在查询应用程序日志时,具有命名空间权限的用户必须提供命名空间。
12.3.5.1. 集群范围内的访问
集群角色绑定资源引用集群角色,以及设置集群范围的权限。
ClusterRoleBinding 示例
kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: logging-all-application-logs-reader roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-logging-application-view 1 subjects: 2 - kind: Group name: system:authenticated apiGroup: rbac.authorization.k8s.io
12.3.5.2. 命名空间访问
RoleBinding
资源可用于 ClusterRole
对象来定义用户或组可以访问日志的命名空间。
RoleBinding 示例
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: allow-read-logs
namespace: log-test-0 1
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-logging-application-view
subjects:
- kind: User
apiGroup: rbac.authorization.k8s.io
name: testuser-0
- 1
- 指定此
RoleBinding
应用到的命名空间。
12.3.5.3. 自定义 admin 组访问
如果您的大型部署具有多个需要更广泛的权限的用户,您可以使用 adminGroup
字段创建一个自定义组。属于 LokiStack
CR 的 adminGroups
字段中指定的任何组的成员的用户被视为管理员。
如果管理员还分配了 cluster-logging-application-view
角色,则管理员用户可以访问所有命名空间中的所有应用程序日志。
LokiStack CR 示例
apiVersion: loki.grafana.com/v1 kind: LokiStack metadata: name: logging-loki namespace: openshift-logging spec: tenants: mode: openshift-logging 1 openshift: adminGroups: 2 - cluster-admin - custom-admin-group 3
其他资源
12.3.6. 使用 Loki 启用基于流的保留
使用日志记录版本 5.6 及更高版本,您可以根据日志流配置保留策略。这些规则可全局设置,每个租户或两个都设置。如果同时配置这两个,则租户规则会在全局规则之前应用。
如果没有在 s3 存储桶或 LokiStack 自定义资源 (CR) 中定义保留周期,则不会修剪日志,它们会永久保留在 s3 存储桶中,这可能会填满 s3 存储。
虽然日志记录版本 5.9 和更高版本支持模式 v12,但建议使用 v13。
要启用基于流的保留,请创建一个
LokiStack
CR:AWS 的基于流的全局保留示例
apiVersion: loki.grafana.com/v1 kind: LokiStack metadata: name: logging-loki namespace: openshift-logging spec: limits: global: 1 retention: 2 days: 20 streams: - days: 4 priority: 1 selector: '{kubernetes_namespace_name=~"test.+"}' 3 - days: 1 priority: 1 selector: '{log_type="infrastructure"}' managementState: Managed replicationFactor: 1 size: 1x.small storage: schemas: - effectiveDate: "2020-10-11" version: v11 secret: name: logging-loki-s3 type: aws storageClassName: gp3-csi tenants: mode: openshift-logging
AWS 的基于流的基于流的保留示例
apiVersion: loki.grafana.com/v1 kind: LokiStack metadata: name: logging-loki namespace: openshift-logging spec: limits: global: retention: days: 20 tenants: 1 application: retention: days: 1 streams: - days: 4 selector: '{kubernetes_namespace_name=~"test.+"}' 2 infrastructure: retention: days: 5 streams: - days: 1 selector: '{kubernetes_namespace_name=~"openshift-cluster.+"}' managementState: Managed replicationFactor: 1 size: 1x.small storage: schemas: - effectiveDate: "2020-10-11" version: v11 secret: name: logging-loki-s3 type: aws storageClassName: gp3-csi tenants: mode: openshift-logging
2 应用 LokiStack
CR:
$ oc apply -f <filename>.yaml
12.3.7. Loki 速率限制错误故障排除
如果 Log Forwarder API 将超过速率限制的大量信息转发到 Loki,Loki 会生成速率限制(429
)错误。
这些错误可能会在正常操作过程中发生。例如,当将 logging 添加到已具有某些日志的集群中时,logging 会尝试充分利用现有日志条目时可能会出现速率限制错误。在这种情况下,如果添加新日志的速度小于总速率限值,历史数据最终会被处理,并且不要求用户干预即可解决速率限制错误。
如果速率限制错误持续发生,您可以通过修改 LokiStack
自定义资源(CR)来解决此问题。
LokiStack
CR 在 Grafana 托管的 Loki 上不可用。本主题不适用于 Grafana 托管的 Loki 服务器。
Conditions
- Log Forwarder API 配置为将日志转发到 Loki。
您的系统向 Loki 发送大于 2 MB 的消息块。例如:
"values":[["1630410392689800468","{\"kind\":\"Event\",\"apiVersion\":\ ....... ...... ...... ...... \"received_at\":\"2021-08-31T11:46:32.800278+00:00\",\"version\":\"1.7.4 1.6.0\"}},\"@timestamp\":\"2021-08-31T11:46:32.799692+00:00\",\"viaq_index_name\":\"audit-write\",\"viaq_msg_id\":\"MzFjYjJkZjItNjY0MC00YWU4LWIwMTEtNGNmM2E5ZmViMGU4\",\"log_type\":\"audit\"}"]]}]}
输入
oc logs -n openshift-logging -l component=collector
后,集群中的收集器日志会显示包含以下错误消息之一的行:429 Too Many Requests Ingestion rate limit exceeded
Vector 错误消息示例
2023-08-25T16:08:49.301780Z WARN sink{component_kind="sink" component_id=default_loki_infra component_type=loki component_name=default_loki_infra}: vector::sinks::util::retries: Retrying after error. error=Server responded with an error: 429 Too Many Requests internal_log_rate_limit=true
Fluentd 错误消息示例
2023-08-30 14:52:15 +0000 [warn]: [default_loki_infra] failed to flush the buffer. retry_times=2 next_retry_time=2023-08-30 14:52:19 +0000 chunk="604251225bf5378ed1567231a1c03b8b" error_class=Fluent::Plugin::LokiOutput::LogPostError error="429 Too Many Requests Ingestion rate limit exceeded for user infrastructure (limit: 4194304 bytes/sec) while attempting to ingest '4082' lines totaling '7820025' bytes, reduce log volume or contact your Loki administrator to see if the limit can be increased\n"
在接收结束时也会看到这个错误。例如,在 LokiStack ingester pod 中:
Loki ingester 错误消息示例
level=warn ts=2023-08-30T14:57:34.155592243Z caller=grpc_logging.go:43 duration=1.434942ms method=/logproto.Pusher/Push err="rpc error: code = Code(429) desc = entry with timestamp 2023-08-30 14:57:32.012778399 +0000 UTC ignored, reason: 'Per stream rate limit exceeded (limit: 3MB/sec) while attempting to ingest for stream
流程
更新
LokiStack
CR 中的ingestionBurstSize
和ingestionRate
字段:apiVersion: loki.grafana.com/v1 kind: LokiStack metadata: name: logging-loki namespace: openshift-logging spec: limits: global: ingestion: ingestionBurstSize: 16 1 ingestionRate: 8 2 # ...
12.3.8. 配置 Loki 以容许 memberlist 创建失败
在 OpenShift 集群中,管理员通常使用非专用 IP 网络范围。因此,Loki memberlist 配置会失败,因为默认情况下,它只使用私有 IP 网络。
作为管理员,您可以为 memberlist 配置选择 pod 网络。您可以修改 LokiStack CR,以使用 hashRing
spec 中的 podIP
。要配置 LokiStack CR,请使用以下命令:
$ oc patch LokiStack logging-loki -n openshift-logging --type=merge -p '{"spec": {"hashRing":{"memberlist":{"instanceAddrType":"podIP","type": "memberlist"}}}}'
LokiStack 示例,使其包含 podIP
apiVersion: loki.grafana.com/v1 kind: LokiStack metadata: name: logging-loki namespace: openshift-logging spec: # ... hashRing: type: memberlist memberlist: instanceAddrType: podIP # ...