Loki multitenant on Infrastructure Openshift cluster

loki logging

*file: 01loki.md *

68. Je definována komponenta LOKI včetně jejího účelu, provozního modelu a práci s daty

1. Proč centrální LOKI

Na centrální LOKI cluster se v tento okamžik díváme jako na dlouhodé úložiště logů pro OPS. Nemáme ambice nahrazovat budoucí řešení Monolog. Hlavní výrazná změna Loki oproti ELK je ta že LOKI neindexuje všechny řádky logů, ale pouze metadata logu. Díky tomu je výrazně rychlejší ale zároveň na heuristické analýzy spíše méně vhodný. Pro potřeby OPS však naprosto dostačující.

Logy na jednotlivých clusterech budou uloženy v lokálním ES s relativně krátkou retencí. Všechny logy budou zároveň z jednotlivých OCP clusterů přez CLusterLogForwarder směrovány do OCP Infra clusteru. Pro každý cluster vznikne instance LOKI s backendem postaveným nad S3 storage. Nebudeme tedy provozovat multitenanci na úrovni LOKI, každá instance bude mít svojí vlastní S3 storage a svoje vlastní endpointy, následně bude samostatný i Grafana datasource směřující do instance Loki.

2. Instance LOKI

2.1. Izolace tenantů

Instalaci provedeme samostatnou instancí Loki per cluster, se všemi samostatnými endpointy. Každý cluster z kterého budou logy propagovány budou mít vlastní S3 bucket.

Izolace tenantu

Izolace tenantu

2.2. Multitenantí přístup

Grafana Loki does not come with any included authentication layer. Operators are expected to run an authenticating reverse proxy in front of your services, such as NGINX using basic auth or an OAuth2 proxy. Note that when using Loki in multi-tenant mode, Loki requires the HTTP header X-Scope-OrgID to be set to a string identifying the tenant; the responsibility of populating this value should be handled by the authenticating reverse proxy.

O oddělení přistupu k datům na úrovni rozdílných RBAC a tenantů uvažujeme ale zatím nejsme ve fázi kdy by bylo zřejmé jak multitenantnost implementovat na úrovni Grafany, zároveň bychom byli nuceni použít jeden S3 bucket

Pro implementaci na úrovni lokiho bychom mohli použít multitenant proxy ale zatím přesunuji do backlogu.

3. Transport logů do LOKI

Pro transport logů bude pooužit CRD ClusterLogForwarder na jednotlivých clusterech

3.1. ClusterLogForwarder definition

apiVersion: "logging.openshift.io/v1"
kind: ClusterLogForwarder
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "2"
    argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
  name: instance
  namespace: openshift-logging
spec:
  inputs:
  #argocd jako samostatny input
  - name: argocd
    application:
      namespaces:
      - csas-argocd-sys
      - csas-argocd-app
  - name: events
    application:
      namespaces:
        - openshift-logging
      selector:
        matchLabels:
          component: eventrouter

  outputs:
  - name: external-elasticsearch
    type: "elasticsearch"
    url: https://deva-monolog-elastic.vs.csin.cz:9200
    secret:
      name: external-elasticsearch-secret
  - name: loki
    type: "loki"
    url: http://loki-tocp4s.apps.iocp4s.csin.cz
    loki:
      # tenantKey: kubernetes.namespace_name
      # definice labelu ktere budou komponovat index
      labelKeys: [log_type, openshift.labels.logtype, kubernetes.namespace_name, kubernetes.pod_name, kubernetes_host, kubernetes.container_name]
  # Kafka pro aplikacni logy
  - name: kafka-app-in
    type: kafka
    secret:
      name: kafka-credentials
    kafka:
      brokers:
      - tls://ppkafpl02.vs.csin.cz:9095/
      - tls://pbkafpl02.vs.csin.cz:9095/
      - tls://ppkafpl03.vs.csin.cz:9095/
      - tls://pbkafpl03.vs.csin.cz:9095/
      - tls://ppkafpl04.vs.csin.cz:9095/
      - tls://pbkafpl04.vs.csin.cz:9095/
      topic: "LOG.OCP.TOCP4S_PROD_APP_IN"
  # Kafka pro auditni logy
  - name: kafka-aud-in
    type: kafka
    secret:
      name: kafka-credentials
    kafka:
      brokers:
      - tls://ppkafpl02.vs.csin.cz:9095/
      - tls://pbkafpl02.vs.csin.cz:9095/
      - tls://ppkafpl03.vs.csin.cz:9095/
      - tls://pbkafpl03.vs.csin.cz:9095/
      - tls://ppkafpl04.vs.csin.cz:9095/
      - tls://pbkafpl04.vs.csin.cz:9095/
      topic: "LOG.OCP.TOCP4S_PROD_AUD_IN"
  # Kafka pro event logy
  - name: kafka-evt-in
    type: kafka
    secret:
      name: kafka-credentials
    kafka:
      brokers:
        - tls://ppkafpl02.vs.csin.cz:9095/
        - tls://pbkafpl02.vs.csin.cz:9095/
        - tls://ppkafpl03.vs.csin.cz:9095/
        - tls://pbkafpl03.vs.csin.cz:9095/
        - tls://ppkafpl04.vs.csin.cz:9095/
        - tls://pbkafpl04.vs.csin.cz:9095/
      topic: "LOG.OCP.TOCP4S_PROD_EVT_IN"

  pipelines:
  - name: argocd-logs
    inputRefs:
    - argocd
    outputRefs:
    - loki
    labels:
      logtype: argocd #openshift.labels.logtype = argocd
      clustername: tocp4s #openshift.lables.clustername =tocp4s
  - name: events-logs
    inputRefs:
      - events
    outputRefs:
      - kafka-evt-in
    labels:
      logtype: event
      clustername: tocp4s

  - name: audit-logs
    inputRefs:
    - audit
    - argocd
    outputRefs:
    - default #internal ES
    - kafka-aud-in
    labels:
      logtype: audit #openshift.labels.logtype = audit
      clustername: tocp4s

  - name: infrastructure-logs
    inputRefs:
    - infrastructure
    outputRefs:
    - default
    - loki
    labels:
      logtype: infrastructure
      clustername: tocp4s

  - name: application-logs
    inputRefs:
    - application
    outputRefs:
    - default
    - kafka-app-in
    - external-elasticsearch
    labels:
      logtype: application
      clustername: tocp4s

pipeline:

  • application - logy kontejnerů generované uživatelskými aplikacemi běžícími v clusteru, vyjímkou jsou infrastrukturní logy
  • infrastructure - logy kontejnerů běžící v namespacech openshift*, kube*, nebo default projects a journal logy pocházející filesystému jednotlivých nodů
  • audit - Audit generovány přez auditd, Kubernetes API server, OpenShift API server, a OVN network.

3.2 Custom labels

    labels:
      cluster_name: tocp4s
      environment: test

Tyto custom labely budou ve struktuře logu jako .openshift.labels

3.3 Log směrovaný do instance Loki

{
  "@timestamp": "2023-03-26T15:49:35.802233556+00:00",
  "message": "image-registry.openshift-image-registry.svc:5000",
  "docker": {
    "container_id": "af7e75f2224a44bee9dfe7ae6e62d967652b8d2fc93f0a9e6a666a597a7ad853"
  },
  "kubernetes": {
    "container_name": "node-ca",
    "namespace_name": "openshift-image-registry",
    "pod_name": "node-ca-pdcmn",
    "container_image": "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:56dd1db2c4ae562d09a457e4a9c121a76cdb8835503b860996646e9d4460a0ce",
    "container_image_id": "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:56dd1db2c4ae562d09a457e4a9c121a76cdb8835503b860996646e9d4460a0ce",
    "pod_id": "fe8191dc-449a-461b-9967-6c2693e406f9",
    "pod_ip": "10.88.56.70",
    "host": "infra01",
    "labels": {
      "controller-revision-hash": "649f4968fd",
      "name": "node-ca",
      "pod-template-generation": "18"
    },
    "master_url": "https://kubernetes.default.svc",
    "namespace_id": "7c4c2cad-62ee-4823-9ce9-df7249887717",
    "namespace_labels": {
      "kubernetes.io/metadata.name": "openshift-image-registry",
      "olm.operatorgroup.uid/d91045da-eef8-42ee-ba26-bcb6fc7a6a7a": "",
      "openshift.io/cluster-monitoring": "true",
      "pod-security.kubernetes.io/audit": "privileged",
      "pod-security.kubernetes.io/enforce": "privileged",
      "pod-security.kubernetes.io/warn": "privileged"
    },
    "flat_labels": [
      "controller-revision-hash=649f4968fd",
      "name=node-ca",
      "pod-template-generation=18"
    ]
  },
  "level": "unknown",
  "hostname": "infra01",
  "pipeline_metadata": {
    "collector": {
      "ipaddr4": "10.88.56.70",
      "inputname": "fluent-plugin-systemd",
      "name": "fluentd",
      "received_at": "2023-03-26T15:49:35.802497+00:00",
      "version": "1.14.6 1.6.0"
    }
  },
  "openshift": {
    "sequence": 404273,
    "cluster_id": "605219f2-ae45-4d06-a9a6-7903ec67c69d",
    "labels": {
      "cluster_name": "tocp4s",
      "log_type": "infrastructure"
    }
  },
  "viaq_msg_id": "ODM2NjFjZDUtMWE5Mi00ZmE5LTkxMzUtY2ZmN2ViNzMzOTZl",
  "log_type": "infrastructure"
}

3.4 Loki labels

Použité labelKeys které definují index

labelKeys: [log_type, openshift.labels.logtype, kubernetes.namespace_name, kubernetes.pod_name, kubernetes_host, kubernetes.container_name ]

4. použité KOMPONENTY LOKI

LOKI komponenty

  • Distributor
  • Ingester
  • Querier
  • Query frontend
  • Compactor
  • Index Gateway
  • Ruler
LOKI architektura

LOKI architektura

5. Instalace LOKI

Vycházíme z nemodifikovaného helmchartu pro loki distributed, service account LOKI a CRB na SCC anyuid je aplikován ručně

helm repo add grafana https://grafana.github.io/helm-charts
helm install loki grafana/loki-distributed -n loki -f values.yaml
# stav komponent v runtime
pod/loki-tocp4s-compactor-947cbb56f-l72zd
pod/loki-tocp4s-distributor-65766845f9-2849b
pod/loki-tocp4s-distributor-65766845f9-7wdbp
pod/loki-tocp4s-distributor-65766845f9-dr5jq
pod/loki-tocp4s-index-gateway-0
pod/loki-tocp4s-index-gateway-1
pod/loki-tocp4s-index-gateway-2
pod/loki-tocp4s-ingester-66b7c49d74-29jvh
pod/loki-tocp4s-ingester-66b7c49d74-64lpj
pod/loki-tocp4s-ingester-66b7c49d74-9bx66
pod/loki-tocp4s-ingester-66b7c49d74-mfcr7
pod/loki-tocp4s-ingester-66b7c49d74-rxqhp
pod/loki-tocp4s-querier-88c686cbc-2svzt
pod/loki-tocp4s-querier-88c686cbc-kvhcw
pod/loki-tocp4s-querier-88c686cbc-wzs8c
pod/loki-tocp4s-query-frontend-77db9468dc-z7mzh
pod/loki-tocp4s-ruler-5fc9c9fd4d-52k5l

6. Persistence

Zatím nepočítáme s žádnou persistencí přímo na Openshiftu, toto rozhodnutí muže to mít drobné dopady ale z testů se je nepodařilo ohalit.
Z pohledu ztráty dat je nejcitlivější Ingestor, indexy které generuje nejsou okamžitě posílány na do S3 přez BoltDB shipper ale jsou po dobu 15 minut drženy na Ingestoru.
Pro Ingestor ale používáme Replication factor = 3 tzn stejná data jsou z Distributoru odeslána právě 3 Ingestorům a minimálně 2 potvrzení jsou vyžádány. Data jsou tedy replikována, jejich zápis do S3 je ale proveden pouze jednou jelikož mají stejný hash. Vícero Ingestorů tak nebude zapisovat stejná data do S3 vícekát. Zároveň se ale rozhodnutím nepoužívat persistence omezujeme pro použití WAL(write ahead log) pro recovery scénář během rolloutu a restartu.

7. Retence dat

O odmazávání logů (chunků i indexů) se stará komponenta Compactor

    compactor:
      shared_store: s3
      retention_enabled: true
      retention_delete_delay: 2h
      retention_delete_worker_count: 150

    limits_config:
      retention_period: 240h # 10 dnů

Retence může být nastavena i selektivně s různými retenčními politikami pro různé labely. Zatím tohoto konceptu nevyužíváme.

8. Migrace Schema

Od verze Loki 2.8 je podporováno TSDB místo BoltDB

#both schemas running at once
schemaConfig:
  configs:
  - from: 2023-01-01 # <----schema validity
    store: boltdb-shipper
    object_store: s3
    schema: v12
    index:
      prefix: loki_index_
      period: 24h
  - from: "2023-08-08" # <---- switch to tsdb
    object_store: s3
    schema: v12
    store: tsdb
    index:
      period: 24h
      prefix: loki_index_

# -- Check https://grafana.com/docs/loki/latest/configuration/#storage_config for more info on how to configure storages
storageConfig:
  boltdb_shipper:
    shared_store: s3
    active_index_directory: /var/loki/index
    cache_location: /var/loki/cache
    cache_ttl: 168h
    index_gateway_client:
      # only applicable if using microservices where index-gateways are independently deployed.
      server_address: dns:///loki-iocp4s-index-gateway.loki-iocp4s.svc.cluster.local:9095
  # New tsdb-shipper configuration
  tsdb_shipper:
    shared_store: s3
    active_index_directory: /var/loki/tsdb-index
    cache_location: /var/loki/tsdb-cache
    index_gateway_client:
      # only applicable if using microservices where index-gateways are independently deployed.
      server_address: dns:///loki-iocp4s-index-gateway.loki-iocp4s.svc.cluster.local:9095
  filesystem:
    directory: /var/loki/chunks
query_scheduler:
  # the TSDB index dispatches many more, but each individually smaller, requests.
  # We increase the pending request queue sizes to compensate.
  max_outstanding_requests_per_tenant: 32768

querier:
  # Each `querier` component process runs a number of parallel workers to process queries simultaneously.
  # You may want to adjust this up or down depending on your resource usage
  # (more available cpu and memory can tolerate higher values and vice versa),
  # but we find the most success running at around `16` with tsdb
  max_concurrent: 16

9. DOC

komponenty loki detailně
consistent hash ring - explanation, zajimal me tech pozadi
consistent hashing
loki deep dive
from BoltDB to TSDB
TSDB explained
medium popis performence optimalizace

*file: 03loki-clusterloggingoperator.md *

LOKI stack instead EFK