Alle Rezepte
Red Hat OpenShift Logging 6.6 · Installation

Logging-Stack installieren:
der komplette Fahrplan

Drei Operatoren, zwei Speicherarten, eine goldene Regel: erst planen, dann installieren. Die häufigsten Ausfälle sind stille Fehler – LokiStack meldet Ready, aber es kommen keine Logs an. Dieser Fahrplan zeigt, wie du sie vermeidest.

0Überblick3 Operatoren, Workflow 1Voraussetzungen2 Speicherarten prüfen 2Object StorageBackend, S3-Rechte, TLS-CA 3Sizing1x.demo bis 1x.medium 4Loki OperatorLog-Store + LokiStack CR 5Logging OperatorCollector + Forwarder 6COO & ZugriffKonsole, RBAC, Debugging 7Schritt für SchrittChronologische Anleitung
0

Überblick: Drei Operatoren, drei Schichten

Bild: eine Poststelle. Der Collector ist der Briefträger (sammelt ein), LokiStack das Archiv (lagert), die Konsole das Lesezimmer (anschauen). Jede Schicht hat ihren eigenen Operator.

Wer macht was – und wo er wohnt

OperatorNamespaceAufgabeSteuernde CR
Loki Operatoropenshift-operators-redhatLog-Store: empfängt, indiziert, speichert in S3-kompatiblem Object StorageLokiStack
Red Hat OpenShift Logging Operatoropenshift-loggingSammeln & Weiterleiten: Vector-Collector tailt Container-LogsClusterLogForwarder
Cluster Observability Operator (COO)openshift-operatorsVisualisierung: Logs-Tab unter Observe → Logs in der Web-KonsoleUIPlugin
L-L-C wie „Lagern, Liefern, Checken“ – Loki lagert, Logging liefert, COO checkt (zeigt an). Installationsreihenfolge: Loki → Logging → COO.

Welche Operatoren brauchst du?

  • Nur weiterleiten (externes Log-Ziel): nur der Logging Operator. Kein Cluster-Storage nötig.
  • Speichern im Cluster (Abfrage per Grafana/logcli): Loki Operator + Logging Operator.
  • Voller Stack mit Konsolen-Ansicht: alle drei Operatoren.
  • Kombinierbar: z. B. im Cluster speichern und parallel extern archivieren (Compliance).

Der Installations-Workflow

  1. Planen & vorbereitenStorageClass prüfen, Object Storage + TLS einrichten, Initialgröße wählen, Cluster-Kapazität checken.
  2. Operatoren installierenLoki Operator → Logging Operator → COO (falls Konsole gewünscht).
  3. Konfigurieren & deployenLokiStack CR, dann ClusterLogForwarder CR, dann verifizieren.
  4. Nach 24h optimierenEchte Ingestion-Rate messen, Größe anpassen, Ressourcen beobachten.
Versionskopplung: Loki Operator und Logging Operator müssen dieselbe Major.Minor-Version fahren – beide auf stable-6.6. Und: Loki Operator vor dem Logging Operator konfigurieren. Hinweis: Die 6.6-Doku zeigt in den Beispielen noch stable-6.5 – offensichtlich ein Doku-Überbleibsel. Verfügbare Kanäle prüfen: oc get packagemanifest loki-operator -n openshift-marketplace.
Multi-Cluster: Eine LokiStack-Instanz speichert nur Logs des eigenen Clusters. Cluster-übergreifende Aggregation in eine LokiStack ist nicht unterstützt – pro Cluster eine LokiStack deployen oder an ein zentrales externes System forwarden.
1

Voraussetzungen: Zwei Speicherarten – beide Pflicht

Der wichtigste Punkt der ganzen Doku. LokiStack braucht Blockspeicher (StorageClass, für interne PVCs) und Object Storage (S3-kompatibel, für die Log-Daten). Fehlt eins, scheitert das Deployment – oft still.

Blockspeicher = Werkbank

PVCs für WAL (Write-Ahead-Log), Index-Cache und Compactor-Arbeitsfläche. Das ist die Werkbank, auf der aktiv gearbeitet wird.

  • Dynamisches Provisioning, ReadWriteOnce
  • Muss nicht die Default-StorageClass sein – aber genug Kapazität haben
  • Block statt Filesystem (volumeMode: Block) – Filesystem bremst Loki spürbar, nicht produktionsempfohlen
  • Das Feld storageClassName in der LokiStack-CR meint diesen Speicher, nicht das S3
oc get storageclass

Object Storage = Lagerhalle

Hier landen die eigentlichen Log-Chunks und Indizes – die Lagerhalle für alles Fertige.

  • S3-kompatibel: AWS S3, GCS, Azure Blob, StorageGRID & Co., Ceph RGW/ODF, Swift
  • Konfiguriert über das Secret in spec.storage.secret.name
  • Kapazität vorab nicht seriös schätzbar – mit z. B. 1 TB starten und Verbrauch beobachten
  • Erreichbarkeit von allen Nodes testen (gerade air-gapped)
Werkbank & Lagerhalle: StorageClass = Werkbank (schnell, klein, lokal), Object Storage = Lagerhalle (groß, dauerhaft). Loki braucht immer beides – wer nur die Lagerhalle baut, hat nichts zum Arbeiten; wer nur die Werkbank hat, nichts zum Ablegen.

Die stillen Fehler – warum vorher prüfen

Fehlt…Was du siehstWas wirklich passiert
StorageClassOperatoren installieren sauber, LokiStack ReadyPVCs bleiben Pending, Pods starten nie, keine Logs
Object Storage / CA-BundleOperatoren installieren sauber, LokiStack ReadyLogs werden still verworfen – kein Fehler in der Konsole
s3:DeleteObject-RechtLokiStack Ready, Retention konfiguriertCompactor kann nicht löschen – Bucket wächst unbegrenzt
„Ready“ ist keine Erfolgsmeldung. Die häufigsten Support-Fälle entstehen, weil Operatoren vor den Prüfungen installiert wurden. Ready heißt nur: die Konfiguration ist formal gültig – nicht, dass Logs fließen.

Checkliste vor der Installation (nur bei LokiStack nötig)

  1. StorageClass verfügbarMit ausreichender Kapazität für die gewählte Größe.
  2. Object Storage angelegtBucket erstellt, Zugangsdaten mit allen sechs S3-Rechten.
  3. TLS-CA-Bundle konfiguriertBei Self-Signed / interner CA – sonst stiller Log-Verlust.
  4. Initialgröße gewählt1x.demo / pico / extra-small / small / medium – nach Clustergröße, nicht nach geratenem Log-Volumen.
  5. Cluster-Kapazität geprüftBeispiel: 1x.medium mit Ruler braucht 70 vCPUs und 171 GiB RAM.
  6. Netzwerk getestetCluster ↔ Storage-Endpoint, IAM-Rollen/Service-Accounts korrekt.

Bei reinem Forwarding ohne LokiStack entfällt die Checkliste – stattdessen Auth, Verschlüsselung und CA-Zertifikate des Ziels prüfen.

Single-Node / Edge ohne StorageClass: Local Storage Operator

SNO- und Edge-Cluster haben oft keine StorageClass. Lösung: Local Storage Operator (oder LVM Storage) macht aus rohen Block-Devices eine StorageClass.

oc adm new-project openshift-local-storage
apiVersion: local.storage.openshift.io/v1
kind: LocalVolume
metadata:
  name: local-block
  namespace: openshift-local-storage
spec:
  nodeSelector:
    nodeSelectorTerms:
    - matchExpressions:
      - key: kubernetes.io/hostname
        operator: In
        values:
        - <node_name>
  storageClassDevices:
  - storageClassName: local-block   # wird deine neue StorageClass
    volumeMode: Block               # Block empfohlen für Loki
    devicePaths:
    - /dev/disk/by-id/<device_id>   # stabile by-id-Pfade nutzen
    fsType: ""

Danach: oc get storageclass local-block und nach LokiStack-Erstellung oc get pvc -n openshift-logging – PVCs müssen binden.

2

Object Storage konfigurieren

Backend wählen, S3-Rechte sicherstellen, Secret anlegen – und bei Self-Signed-Zertifikaten zwingend das CA-Bundle. Alles vor der LokiStack-CR.

Backend-Wahl nach Umgebung

UmgebungEmpfohlenes BackendSecret-typeCA-Bundle?
AWS / GCP / AzureS3 / GCS / Azure Blobs3 / gcs / azureNur bei Custom-/VPC-Endpoints mit eigenen Zertifikaten
On-PremODF Ceph RGW oder S3-kompatibel (StorageGRID, Cloudian, HCP …)s3Bei Self-Signed / interner CA: ja
OpenStackSwiftswiftBei Self-Signed / interner CA: ja
Edge / SNOForwarding an zentralen Hub

Namenskonvention für das Secret: logging-loki-<provider>. Ceph RGW heißt in Rook-Deployments auch NooBaa.

Die sechs S3-Rechte

s3:ListBucket s3:PutObject s3:GetObject s3:DeleteObject s3:GetObjectTagging s3:PutObjectTagging
  • List/Get: Abfragen und Compaction
  • Put: Ingestion (Chunks + Index schreiben)
  • Delete: Compactor löscht abgelaufene Logs
  • Tagging (Get/Put): Retention & Lifecycle
Ohne s3:DeleteObject greift keine Retention: der Bucket wächst endlos, obwohl alles Ready meldet.

Beispiel: Secret für S3-kompatiblen Storage

oc create secret generic logging-loki-s3 \
  -n openshift-logging \
  --from-literal=bucketnames="<bucket>" \
  --from-literal=endpoint="https://s3.example.com:9000" \
  --from-literal=access_key_id="<key>" \
  --from-literal=access_key_secret="<secret>" \
  --from-literal=forcepathstyle="true"
  • endpoint: volle URL mit Protokoll und Port – ohne Bucket-Namen
  • forcepathstyle="true": Pflicht für S3-kompatible Anbieter, nicht für AWS
  • Kein region-Parameter bei S3-kompatiblem Storage – das ist AWS-spezifisch
  • Feldnamen (access_key_id …) sind Loki-Operator-eigen, nicht die AWS-SDK-Namen

TLS-CA-Bundle – der Klassiker unter den stillen Fehlern

Self-Signed oder interne CA am Storage-Endpoint, aber kein CA-Bundle konfiguriert? Dann: LokiStack Ready, Logs weg, kein Fehler in der UI. In den Pod-Logs steht dafür:

x509: certificate signed by unknown authority
  1. CA extrahierenopenssl s_client -connect <endpoint>:<port> -showcerts </dev/null | openssl x509 -out storage-ca.crt
  2. ConfigMap anlegenoc create configmap loki-s3-ca-bundle -n openshift-logging --from-file=ca-bundle.crt=./storage-ca.crt
  3. In der LokiStack-CR referenzierenUnter spec.storage.tls.caName: loki-s3-ca-bundle.
  4. Verifizierenoc logs <ingester_pod> -n openshift-logging | grep -i "x509\|certificate" – muss leer bleiben.
ODF/NooBaa: Beim Default-Ceph-RGW-Endpoint ggf. das service-ca.crt aus der ConfigMap openshift-service-ca.crt verwenden.
Provider-Details: AWS, GCS, Azure, Ceph RGW (ODF), Swift

AWS S3: Secret mit bucketnames, endpoint (https://s3.<region>.amazonaws.com), access_key_id, access_key_secret, region. Bei STS stattdessen bucketnames, region, audience.

GCS: Service-Account-Key als Datei: --from-literal=bucketname=… --from-file=key.json=./key.json.

Azure Blob: container, environment (AzureGlobal, AzureChinaCloud, AzureGermanCloud, AzureUSGovernment), account_name, account_key; bei Entra Workload ID ohne account_key.

Ceph RGW (ODF): Erst ObjectBucketClaim im Namespace openshift-logging mit storageClassName: openshift-storage.ceph.rbd, dann Credentials aus zugehöriger ConfigMap/Secret ins logging-loki-s3-Secret übernehmen (forcepathstyle="true").

Swift: Secret logging-loki-swift mit auth_url, Benutzer-/Domain-Feldern, password, container_name; optional Projekt-/Region-Parameter. In der LokiStack-CR dann type: swift.

3

Sizing: erst schätzen, nach 24 Stunden messen

Log-Volumen ist vor der Installation nicht vorhersagbar: ein einzelner Pod kann 100 GB/Tag produzieren, journald- und Audit-Logs kommen obendrauf. Deshalb: Baseline nach Clustergröße wählen, später anhand echter Metriken nachjustieren.

Größenübersicht (1x.<size> – die „1x“ ist fix)

1x.demo1x.pico1x.extra-small1x.small1x.medium
Ingestionnur Demo50 GB/Tag100 GB/Tag500 GB/Tag2 TB/Tag
QPS (200 ms)nur Demo1–251–2525–5025–75
Replikationkeine2222
vCPU (mit Ruler)7 (8)14 (16)34 (42)54 (70)
RAM (mit Ruler)17 Gi (18)31 Gi (35)67 Gi (83)139 Gi (171)
Disk (mit Ruler)40 Gi (60)590 Gi (910)430 Gi (750)430 Gi (750)590 Gi (910)

Disk-Requests sind über die Größen ähnlich – verschiedene Größen lassen sich so gefahrlos testen. Produktionsgrößen laut CR-Doku: extra-small, small, medium; 1x.pico gibt es ab Logging 6.1. 1x.pico: HA für alle Komponenten, für Deployments ohne Single-Replication/Auto-Compaction.

Startgrößen-Faustregel

  • ≤ 10 Nodes: 1x.extra-small
  • > 10 Nodes: 1x.medium
  • SNO/Edge: 1x.pico (minimal lauffähig); Edge alternativ 1x.extra-small mit kurzer Retention (7–14 Tage)
  • Edge mit knapper Kapazität: statt lokaler LokiStack an zentralen Hub forwarden
Kleider kauft man nach Anprobe: erst die Konfektionsgröße nach Statur (Clustergröße), nach 24 h Tragen (Metriken) wird umgetauscht (resized).

Nach 24 h: echte Rate messen

sum by (component_name) (
  rate(vector_component_sent_bytes_total{
    component_type="loki",
    component_kind="sink"}[5m])
)

Bytes/s × 86400 ÷ 1073741824 = GB/Tag. Beispiel: 5 242 880 B/s ≈ 421 GB/Tag → 1x.small (500 GB/Tag). Dann in der CR spec.size anpassen.

Resize = Rolling Restart aller Komponenten. In ein Wartungsfenster legen.
Was treibt die Größe? QPS, Volumen, Retention, Ruler
  • QPS: Konsolen-Abfragen, Dashboard-Refreshes, Alert-Evaluierungen, API-Abfragen. Ein einzelner Nutzer mit mehreren Dashboards erzeugt schon 10–20 QPS.
  • Ingestion (GB/Tag): treibt Ingester-CPU/RAM.
  • Retention: treibt Object-Storage-Bedarf (100 GB/Tag × 30 Tage = 3 TB).
  • Abfrage-Zeitraum: treibt Querier-Ressourcen.
  • Ruler (optional): wertet Alerting-/Retention-Regeln aus, skaliert mit Tenants × Regeln × Datenvolumen. Laut Tabelle 1x.medium: +16 vCPU, +32 Gi RAM, +Disk. (Der Fließtext der 6.6-Doku nennt für 1x.medium 34→42 vCPU – das sind laut Tabelle die Werte von 1x.small; die Tabelle gilt.) Nur einplanen, wenn Alerting/Recording Rules genutzt werden.
  • Requests sind garantierte Minima – reale Last kann darüber liegen.
4

Loki Operator installieren & LokiStack anlegen

Der Lagerverwalter zieht ein: Namespace openshift-operators-redhat, Kanal stable-6.6, Quelle redhat-operators. Danach Namespace openshift-logging, Storage-Secret, LokiStack-CR.

CLI-Installation in 5 Schritten

  1. Namespace openshift-operators-redhatMit Label openshift.io/cluster-monitoring: "true". Nicht openshift-operators – dort lauern Community-Operatoren mit Metrik-Namenskonflikten.
  2. OperatorGroup loki-operatorIm selben Namespace, upgradeStrategy: Default.
  3. Subscriptionchannel: stable-6.6, source: redhat-operators, installPlanApproval: Automatic (oder Manual). Disconnected: Name der eigenen CatalogSource.
  4. Prüfenoc get csv -n openshift-operators-redhatloki-operator.v6.6.0 … Succeeded.
  5. Namespace openshift-logging anlegenEbenfalls mit Cluster-Monitoring-Label – hier laufen LokiStack und alle Logging-Workloads.
Community-Falle: Es gibt einen loki-operator auch im Community-Katalog – anderer Kanalname, kein Support. Immer source: redhat-operators. Bei ResolutionFailed: oc get packagemanifest loki-operator -n openshift-marketplace und Kanal/Quelle prüfen.

LokiStack-CR – das Herzstück

apiVersion: loki.grafana.com/v1
kind: LokiStack
metadata:
  name: logging-loki                # fester Name
  namespace: openshift-logging
spec:
  size: 1x.small                    # Initialgröße
  storage:
    schemas:
    - effectiveDate: '2023-10-15'
      version: v13
    secret:
      name: logging-loki-s3         # dein Storage-Secret
      type: s3                      # s3 | gcs | azure | swift
    tls:
      caName: loki-s3-ca-bundle     # bei Self-Signed-Storage
  storageClassName: <storage_class> # BLOCKspeicher, nicht S3!
  tenants:
    mode: openshift-logging
  • credentialMode (optional): static (Default, Secret-Credentials), token (kurzlebige Tokens), token-cco (Default bei STS/WIF mit CCO)
  • Loki ist hier als Kurzzeit-Store ausgelegt: getestet/supportet bis max. 30 Tage Retention. Langzeit-Archiv → externes System.
„storageClassName ≠ S3“: das Feld klingt nach Speicher-Backend, meint aber die Werkbank (Block-PVCs). Die Lagerhalle (S3) steckt im secret.
5

Logging Operator, RBAC & ClusterLogForwarder

Der Briefträger braucht drei Dinge: einen Dienstausweis (ServiceAccount), Zutrittsrechte (ClusterRoles) und eine Routenkarte (ClusterLogForwarder). Reihenfolge ist hier sicherheitskritisch.

Installation & Collector-Setup

  1. Operator installierenOperatorGroup + Subscription cluster-logging in openshift-logging, Kanal stable-6.6 (gleich wie Loki!), Quelle redhat-operators. Check: oc get csv -n openshift-logging.
  2. ServiceAccount anlegenoc create sa logging-collector -n openshift-logging
  3. ClusterRoles binden – VOR der CLF-CRlogging-collector-logs-writer (in LokiStack schreiben), collect-application-logs, collect-infrastructure-logs; für Audit zusätzlich collect-audit-logs.
  4. ClusterLogForwarder-CR anlegenName instance, Output-Typ lokiStack, Pipelines mit inputRefs.
  5. Status prüfenoc get clusterlogforwarder instance -n openshift-logging -o yaml → Conditions Authorized, Valid, Ready.
RBAC zuerst! Fügst du einen Input-Typ in die CLF-CR ein, ohne dass das passende ClusterRoleBinding existiert, wird das gesamte Collector-DaemonSet zerstört – die komplette Log-Sammlung fällt aus.

ClusterLogForwarder – Minimalbeispiel

apiVersion: observability.openshift.io/v1
kind: ClusterLogForwarder
metadata:
  name: instance
  namespace: openshift-logging
spec:
  serviceAccount:
    name: logging-collector
  outputs:
  - name: lokistack-out
    type: lokiStack
    lokiStack:
      target:
        name: logging-loki
        namespace: openshift-logging
      authentication:
        token:
          from: serviceAccount
    tls:                              # PFLICHT!
      ca:
        key: service-ca.crt
        configMapName: openshift-service-ca.crt
  pipelines:
  - name: infra-app-logs
    inputRefs: [application, infrastructure]
    outputRefs: [lokistack-out]
Ohne den tls.ca-Block scheitern die Collector-Pods mit certificate verify failed – der CLF-Status kann trotzdem Ready: True zeigen.

Verifikation & LogFileMetricExporter

  • oc get pods -n openshift-logging -l app.kubernetes.io/component=collector → ein Pod pro Node
  • oc logs … --tail=20 → gesund sind nur WARN-Meldungen über kleine Dateien
  • Konsole: Observe → Logs, Query {log_type="infrastructure"}

LogFileMetricExporter (optional, aber sonst zeigt „Produced Logs“ im Dashboard No datapoints found): Singleton-CR openshift-logging/instance, Kind LogFileMetricExporter (logging.openshift.io/v1alpha1) mit optionalen nodeSelector/resources/tolerations. Läuft danach als Pod parallel zum Collector auf jedem Node.

6

COO, UIPlugin, Log-Zugriff & Troubleshooting

Das Lesezimmer ist optional: sammeln, speichern und forwarden geht ohne COO. Wer den Logs-Tab in der Konsole will, braucht beides – COO und UIPlugin-CR.

COO installieren

  • Subscription cluster-observability-operator in openshift-operators (bestehende OperatorGroup, nichts extra anlegen)
  • Kanal: development · Quelle: redhat-operators
  • Check: oc get csv -n openshift-operators | grep cluster-observabilitySucceeded

UIPlugin – schaltet den Logs-Tab frei

apiVersion: observability.openshift.io/v1alpha1
kind: UIPlugin
metadata:
  name: logging            # muss "logging" heißen
spec:
  type: Logging
  logging:
    lokiStack:
      name: logging-loki   # = LokiStack-Name
    logsLimit: 50
    timeout: 30s
    schema: otel           # otel | viaq | select

Bekannte Einschränkungen (OU-587): Schema-Feature erst ab OCP 4.15; Nicht-Admins können mit Logging 5.8–6.2 nicht per otel-Attribut abfragen (LOG-6589). Default-Schema ist viaq.

Fein granularer Log-Zugriff (Loki)

Der Logging Operator gibt keinem Nutzer automatisch Log-Zugriff. Drei ClusterRoles stehen bereit:

cluster-logging-application-view cluster-logging-infrastructure-view cluster-logging-audit-view
  • Clusterweit: ClusterRoleBinding auf die View-Rolle (z. B. für system:authenticated).
  • Pro Namespace: RoleBinding + ClusterRole im Ziel-Namespace; Nutzer müssen beim Abfragen den Namespace angeben. ServiceAccounts brauchen zusätzlich Projekt-List-Rechte (z. B. self-provisioner).
  • Admin-Gruppen: spec.tenants.openshift.adminGroups in der LokiStack-CR (nur Modus openshift-logging); überschreibt die Defaults system:cluster-admins, cluster-admin, dedicated-admin; [] deaktiviert. SA-Gruppen: system:serviceaccount:<ns>:<name>.
  • Nach Upgrades sorgt logging-application-logs-reader + Binding für Abwärtskompatibilität (jeder authentifizierte Nutzer liest die eigenen Namespaces).
cluster-admin & viele Namespaces: Übersteigt die Zeichensumme aller Namespaces 5120, gibt es Parse error: input size too long. Abhilfe: Gruppe cluster-admin anlegen (oc adm groups new cluster-admin), Nutzer hinzufügen, Rolle an die Gruppe binden.

Troubleshooting-Spickzettel

SymptomUrsache / Lösung
certificate verify failed im Collectortls.ca-Block im CLF-Output ergänzen (openshift-service-ca.crt / service-ca.crt)
x509: unknown authority in Loki-PodsCA-Bundle für den Object Storage fehlt → ConfigMap + spec.storage.tls.caName
429 Too Many RequestsNormal beim Erst-Ingest (Backlog-Flush), löst sich in Minuten
Kein Logs-Tab unter ObserveCOO und UIPlugin nötig – beides prüfen
CLF Ready: True, aber keine LogsCollector-Pod-Logs lesen; Validation prüft die Verbindung nicht. Häufigste Ursache: fehlende TLS-CA
ResolutionFailed bei SubscriptionKanal/Quelle prüfen: redhat-operators, nicht Community-Katalog
PVCs PendingKeine passende StorageClass – nachrüsten (ggf. Local Storage Operator)
Bucket wächst trotz Retentions3:DeleteObject-Recht fehlt dem Storage-Account
7

Die komplette Anleitung: chronologisch, Schritt für Schritt

Ziel: voller Stack (LokiStack + Collector + Konsolen-Ansicht) mit S3-kompatiblem On-Prem-Storage. Jeder Schritt: erst was und warum, Code zum Aufklappen. Reihenfolge einhalten – sie ist der halbe Erfolg.

Die vier Phasen auf einen Blick

  1. Phase A · VorbereitenSchritte 1–4: StorageClass, Bucket + Rechte, Größe, Kapazität. Noch kein Operator!
  2. Phase B · Log-StoreSchritte 5–9: Loki Operator, Namespaces, Secret, CA-Bundle, LokiStack-CR.
  3. Phase C · CollectorSchritte 10–13: Logging Operator, ServiceAccount + RBAC, ClusterLogForwarder, Verifikation.
  4. Phase D · Konsole & FeinschliffSchritte 14–17: COO, UIPlugin, Nutzer-Zugriff, Nachmessen & Resize.

Phase A · Vorbereiten (kein Operator anfassen!)

Schritt 1 · StorageClass prüfen (Blockspeicher für interne PVCs)

LokiStack braucht dynamisch provisionierten ReadWriteOnce-Blockspeicher für WAL, Index-Cache und Compactor. Ohne StorageClass bleiben PVCs Pending und kein Pod startet – bei trotzdem grünem LokiStack-Status.

# Alle StorageClasses auflisten
oc get storageclass

# Default-StorageClass ermitteln
oc get storageclass -o=jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}'

Auf den Provisioner achten (z. B. ebs.csi.aws.com, csi.vsphere.vmware.com, openshift-storage.ceph.rbd) – Blockspeicher bevorzugen, Filesystem bremst Loki. Kapazität gegen die Sizing-Tabelle prüfen (1x.medium mit Ruler: 910 Gi über alle PVCs).

SNO/Edge ohne StorageClass: Local Storage Operator installieren und aus rohen Devices eine StorageClass bauen:

oc adm new-project openshift-local-storage
# Local Storage Operator via OperatorHub oder Subscription (stable) installieren, dann:
cat <<'EOF' | oc apply -f -
apiVersion: local.storage.openshift.io/v1
kind: LocalVolume
metadata:
  name: local-block
  namespace: openshift-local-storage
spec:
  nodeSelector:
    nodeSelectorTerms:
    - matchExpressions:
      - key: kubernetes.io/hostname
        operator: In
        values:
        - <your_node_name>
  storageClassDevices:
  - storageClassName: local-block
    volumeMode: Block
    devicePaths:
    - /dev/disk/by-id/<device_id>
    fsType: ""
EOF
oc get storageclass local-block
Schritt 2 · Object Storage anlegen: Bucket + Credentials mit den sechs S3-Rechten

Bucket auf dem S3-kompatiblen Storage anlegen (StorageGRID, Cloudian, Ceph RGW, MinIO-artige …) und einen Account mit genau diesen Rechten ausstatten: ListBucket, PutObject, GetObject, DeleteObject, GetObjectTagging, PutObjectTagging. Ohne DeleteObject läuft der Bucket trotz Retention voll.

# Referenz-IAM-Policy (AWS-Syntax, sinngemäß auf den Provider übertragen)
{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::<bucket_name>" },
    { "Effect": "Allow",
      "Action": ["s3:PutObject","s3:GetObject","s3:DeleteObject",
                 "s3:GetObjectTagging","s3:PutObjectTagging"],
      "Resource": "arn:aws:s3:::<bucket_name>/*" }
  ]
}

Kapazität nicht überplanen – vorab nicht schätzbar. Mit ~1 TB starten, nach Deployment beobachten. Erreichbarkeit des Endpoints von den Cluster-Nodes testen (gerade air-gapped).

Schritt 3 · Initialgröße wählen

Log-Volumen ist vor der Installation nicht vorhersagbar – deshalb nach Clustergröße wählen, nicht raten:

≤ 10 Nodes                → 1x.extra-small
> 10 Nodes                → 1x.medium
SNO/Edge                  → 1x.pico (minimal lauffähig)
Edge, knappe Kapazität    → Forwarding an zentralen Hub

Größe notieren – sie kommt in Schritt 9 in die LokiStack-CR und wird in Schritt 17 gegen echte Messwerte geprüft.

Schritt 4 · Cluster-Kapazität gegenchecken

Die gewählte Größe muss ins Cluster passen (siehe Sizing-Tabelle in Etappe 3). Beispiele der Gesamt-Requests:

1x.extra-small : 14 vCPU / 31 Gi RAM / 430 Gi Disk   (mit Ruler: 16 / 35 Gi / 750 Gi)
1x.small       : 34 vCPU / 67 Gi RAM / 430 Gi        (mit Ruler: 42 / 83 Gi / 750 Gi)
1x.medium      : 54 vCPU / 139 Gi RAM / 590 Gi         (mit Ruler: 70 / 171 Gi / 910 Gi)

Ruler nur einrechnen, wenn Alerting-/Recording-Rules geplant sind.

Phase B · Log-Store aufbauen

Schritt 5 · Loki Operator installieren (Namespace → OperatorGroup → Subscription)

Der Loki Operator gehört nach openshift-operators-redhat – nicht nach openshift-operators (Community-Metrik-Konflikte). Quelle zwingend redhat-operators: im Community-Katalog liegt ein gleichnamiger, nicht supporteter Operator mit anderen Kanälen.

cat <<'EOF' | oc apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: openshift-operators-redhat
  labels:
    openshift.io/cluster-monitoring: "true"
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: loki-operator
  namespace: openshift-operators-redhat
spec:
  upgradeStrategy: Default
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: loki-operator
  namespace: openshift-operators-redhat
spec:
  channel: stable-6.6
  installPlanApproval: Automatic
  name: loki-operator
  source: redhat-operators        # disconnected: eigene CatalogSource
  sourceNamespace: openshift-marketplace
EOF
# Verifizieren – muss Succeeded zeigen
oc get csv -n openshift-operators-redhat
# NAME                   DISPLAY         VERSION   PHASE
# loki-operator.v6.6.0   Loki Operator   6.6.0     Succeeded
Schritt 6 · Namespace openshift-logging anlegen

Hier laufen LokiStack, Collector und alle Logging-Workloads. Das Monitoring-Label sorgt dafür, dass Cluster-Monitoring die Metriken scrapt.

cat <<'EOF' | oc apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: openshift-logging
  labels:
    openshift.io/cluster-monitoring: "true"
EOF
Schritt 7 · Object-Storage-Secret erstellen

Das Secret verbindet LokiStack mit der Lagerhalle. Name nach Konvention logging-loki-s3, im Namespace openshift-logging. S3-kompatibel: forcepathstyle="true" Pflicht, kein region, Endpoint ohne Bucket-Namen.

# S3-kompatibler On-Prem-Storage
oc create secret generic logging-loki-s3 \
  -n openshift-logging \
  --from-literal=bucketnames="<bucket_name>" \
  --from-literal=endpoint="https://s3.example.com:9000" \
  --from-literal=access_key_id="<access_key>" \
  --from-literal=access_key_secret="<secret_key>" \
  --from-literal=forcepathstyle="true"

# Kontrolle
oc get secret logging-loki-s3 -n openshift-logging
# Alternative AWS S3 (Standard-Auth)
oc create secret generic logging-loki-s3 \
  -n openshift-logging \
  --from-literal=bucketnames="<bucket_name>" \
  --from-literal=endpoint="https://s3.<region>.amazonaws.com" \
  --from-literal=access_key_id="<aws_access_key_id>" \
  --from-literal=access_key_secret="<aws_access_key_secret>" \
  --from-literal=region="<aws_region>"

GCS/Azure/Swift/ODF: siehe Provider-Aufklapper in Etappe 2.

Schritt 8 · Nur bei Self-Signed/interner CA: TLS-CA-Bundle konfigurieren

Pflicht bei On-Prem-Storage mit eigener CA – sonst werden Logs still verworfen, obwohl alles Ready meldet.

# 1. CA-Zertifikat vom Storage-Endpoint ziehen
openssl s_client -connect <storage_endpoint>:<port> -showcerts </dev/null 2>/dev/null \
  | openssl x509 -out storage-ca.crt

# 2. ConfigMap im Logging-Namespace anlegen
oc create configmap loki-s3-ca-bundle \
  -n openshift-logging \
  --from-file=ca-bundle.crt=./storage-ca.crt

Die Referenz (spec.storage.tls.caName) kommt im nächsten Schritt in die LokiStack-CR. ODF/NooBaa: ggf. service-ca.crt aus der ConfigMap openshift-service-ca.crt nutzen.

Schritt 9 · LokiStack-CR anlegen und Start prüfen

Jetzt kommt alles zusammen: Größe (Schritt 3), Secret (Schritt 7), CA-Bundle (Schritt 8), StorageClass (Schritt 1). Merken: storageClassName = Blockspeicher, das S3 steckt im Secret.

cat <<'EOF' | oc apply -f -
apiVersion: loki.grafana.com/v1
kind: LokiStack
metadata:
  name: logging-loki
  namespace: openshift-logging
spec:
  size: 1x.small                     # aus Schritt 3
  storage:
    schemas:
    - effectiveDate: '2023-10-15'
      version: v13
    secret:
      name: logging-loki-s3          # aus Schritt 7
      type: s3
    tls:
      caName: loki-s3-ca-bundle      # aus Schritt 8, sonst Block weglassen
  storageClassName: <storage_class>  # aus Schritt 1
  tenants:
    mode: openshift-logging
EOF
# PVCs müssen binden, Pods laufen
oc get pvc -n openshift-logging
oc get pods -n openshift-logging | grep lokistack

# Keine Zertifikatsfehler? Muss leer bleiben:
oc logs -n openshift-logging <lokistack_ingester_pod> | grep -i "x509\|certificate"

Phase C · Collector aufsetzen

Schritt 10 · Logging Operator installieren

Gleicher Kanal wie der Loki Operator (stable-6.6) – die Versionen müssen zusammenpassen. Namespace ist hier openshift-logging.

cat <<'EOF' | oc apply -f -
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: cluster-logging
  namespace: openshift-logging
spec:
  upgradeStrategy: Default
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: cluster-logging
  namespace: openshift-logging
spec:
  channel: stable-6.6
  installPlanApproval: Automatic
  name: cluster-logging
  source: redhat-operators
  sourceNamespace: openshift-marketplace
EOF

oc get csv -n openshift-logging
# cluster-logging.v6.6.0   Red Hat OpenShift Logging   6.6.0   Succeeded
Schritt 11 · ServiceAccount anlegen und RBAC binden – zwingend VOR der CLF-CR

Kritischste Reihenfolge im ganzen Ablauf: fehlt beim Anlegen der ClusterLogForwarder-CR ein Binding für einen genutzten Input-Typ, wird das komplette Collector-DaemonSet zerstört.

oc create sa logging-collector -n openshift-logging

oc adm policy add-cluster-role-to-user logging-collector-logs-writer \
  -z logging-collector -n openshift-logging
oc adm policy add-cluster-role-to-user collect-application-logs \
  -z logging-collector -n openshift-logging
oc adm policy add-cluster-role-to-user collect-infrastructure-logs \
  -z logging-collector -n openshift-logging

# Nur wenn Audit-Logs gesammelt werden sollen:
oc adm policy add-cluster-role-to-user collect-audit-logs \
  -z logging-collector -n openshift-logging

Rollen: logging-collector-logs-writer schreibt in die LokiStack, collect-application-logs / collect-infrastructure-logs lesen die jeweiligen Container-Logs.

Schritt 12 · ClusterLogForwarder-CR anlegen (mit Pflicht-tls.ca-Block!)

Die Routenkarte des Briefträgers: welche Inputs in welchen Output. Der tls.ca-Block ist Pflicht – ohne ihn scheitern die Collector-Pods mit certificate verify failed, während der CLF-Status trotzdem Ready: True zeigen kann.

cat <<'EOF' | oc apply -f -
apiVersion: observability.openshift.io/v1
kind: ClusterLogForwarder
metadata:
  name: instance
  namespace: openshift-logging
spec:
  serviceAccount:
    name: logging-collector          # aus Schritt 11
  outputs:
  - name: lokistack-out
    type: lokiStack
    lokiStack:
      target:
        name: logging-loki           # aus Schritt 9
        namespace: openshift-logging
      authentication:
        token:
          from: serviceAccount
    tls:                             # PFLICHT
      ca:
        key: service-ca.crt
        configMapName: openshift-service-ca.crt
  pipelines:
  - name: infra-app-logs
    inputRefs:
    - application
    - infrastructure                 # audit nur mit RBAC aus Schritt 11!
    outputRefs:
    - lokistack-out
EOF
oc get clusterlogforwarder instance -n openshift-logging -o yaml
# Erwartete Conditions: observability.openshift.io/Authorized,
# observability.openshift.io/Valid, Ready
Schritt 13 · Pipeline verifizieren + optional LogFileMetricExporter
# Ein Collector-Pod pro Node
oc get pods -n openshift-logging -l app.kubernetes.io/component=collector

# Logs prüfen: gesund = nur WARN über kleine Dateien.
# "certificate verify failed" → tls.ca-Block in Schritt 12 prüfen.
# "429 Too Many Requests" → normal beim Erst-Ingest, legt sich in Minuten.
oc logs -n openshift-logging -l app.kubernetes.io/component=collector --tail=20

Optional, damit das Konsolen-Dashboard „Produced Logs“ Daten zeigt (Singleton – Operator akzeptiert nur openshift-logging/instance):

cat <<'EOF' | oc apply -f -
apiVersion: logging.openshift.io/v1alpha1
kind: LogFileMetricExporter
metadata:
  name: instance
  namespace: openshift-logging
spec:
  nodeSelector: {}
  resources:
    limits:
      cpu: 500m
      memory: 256Mi
    requests:
      cpu: 200m
      memory: 128Mi
  tolerations: []
EOF

oc get pods -l app.kubernetes.io/component=logfilesmetricexporter -n openshift-logging

Phase D · Konsole, Zugriff & Feinschliff

Schritt 14 · COO installieren (nur für den Logs-Tab in der Konsole)

Optional: Sammeln, Speichern und Forwarden funktionieren ohne COO. Der COO wandert nach openshift-operators (bestehende OperatorGroup, nichts extra anlegen), Kanal development.

cat <<'EOF' | oc apply -f -
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: cluster-observability-operator
  namespace: openshift-operators
spec:
  channel: development
  installPlanApproval: Automatic
  name: cluster-observability-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace
EOF

oc get csv -n openshift-operators | grep cluster-observability
# cluster-observability-operator.v0.4.2 … Succeeded
Schritt 15 · UIPlugin-CR anlegen → Logs-Tab erscheint

COO allein reicht nicht – erst die UIPlugin-CR schaltet Observe → Logs frei. Name muss logging sein, lokiStack.name muss zur LokiStack passen.

cat <<'EOF' | oc apply -f -
apiVersion: observability.openshift.io/v1alpha1
kind: UIPlugin
metadata:
  name: logging
spec:
  type: Logging
  logging:
    lokiStack:
      name: logging-loki             # aus Schritt 9
    logsLimit: 50
    timeout: 30s
    schema: otel                     # otel | viaq | select (Default: viaq)
EOF

Danach Web-Konsole neu laden, Observe → Logs öffnen und testen:

{log_type="infrastructure"}
Schritt 16 · Nutzern Log-Zugriff geben (Loki-RBAC)

Ohne explizite Bindings sieht kein normaler Nutzer Logs. Rollen: cluster-logging-application-view, cluster-logging-infrastructure-view, cluster-logging-audit-view.

# Variante A: App-Logs clusterweit für alle authentifizierten Nutzer
cat <<'EOF' | oc apply -f -
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
subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.authorization.k8s.io
EOF
# Variante B: nur ein Namespace für einen Nutzer
cat <<'EOF' | oc apply -f -
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: allow-read-logs
  namespace: log-test-0
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-logging-application-view
subjects:
- kind: User
  apiGroup: rbac.authorization.k8s.io
  name: testuser-0
EOF

ServiceAccounts brauchen bei Namespace-Zugriff zusätzlich Projekt-List-Rechte (z. B. self-provisioner). Admin-Gruppen: spec.tenants.openshift.adminGroups in der LokiStack-CR. cluster-admin mit vielen Namespaces (Parse error > 5120 Zeichen):

oc adm groups new cluster-admin
oc adm groups add-users cluster-admin <username>
oc adm policy add-cluster-role-to-group cluster-admin cluster-admin
Schritt 17 · Nach 24 Stunden: messen, vergleichen, ggf. resizen

Erst jetzt ist das echte Log-Volumen sichtbar. Ingestion-Rate per Prometheus abfragen, in GB/Tag umrechnen, gegen die Sizing-Tabelle halten:

sum by (component_name) (
  rate(vector_component_sent_bytes_total{
    component_type="loki",
    component_kind="sink"}[5m])
)

# Bytes/s × 86400 ÷ 1073741824 = GB/Tag
# Beispiel: 5 242 880 B/s ≈ 421 GB/Tag → 1x.small (500 GB/Tag)
# Größe in der LokiStack-CR anpassen (Wartungsfenster! Rolling Restart)
oc patch lokistack logging-loki -n openshift-logging \
  --type=merge -p '{"spec":{"size":"1x.small"}}'

Danach CPU-/RAM-Auslastung weiter beobachten – Requests sind Minima, reale Last kann darüber liegen.

A-B-C-D wie „Ausmessen, Bauen, Collector, Dashboard“: erst die Umgebung ausmessen (Phase A), dann den Store bauen (B), den Collector anschließen (C), zuletzt Dashboard und Zugriff (D). Wer bei B anfängt, landet beim stillen Fehler.