Ü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
| Operator | Namespace | Aufgabe | Steuernde CR |
|---|---|---|---|
| Loki Operator | openshift-operators-redhat | Log-Store: empfängt, indiziert, speichert in S3-kompatiblem Object Storage | LokiStack |
| Red Hat OpenShift Logging Operator | openshift-logging | Sammeln & Weiterleiten: Vector-Collector tailt Container-Logs | ClusterLogForwarder |
| Cluster Observability Operator (COO) | openshift-operators | Visualisierung: Logs-Tab unter Observe → Logs in der Web-Konsole | UIPlugin |
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
- Planen & vorbereitenStorageClass prüfen, Object Storage + TLS einrichten, Initialgröße wählen, Cluster-Kapazität checken.
- Operatoren installierenLoki Operator → Logging Operator → COO (falls Konsole gewünscht).
- Konfigurieren & deployenLokiStack CR, dann ClusterLogForwarder CR, dann verifizieren.
- Nach 24h optimierenEchte Ingestion-Rate messen, Größe anpassen, Ressourcen beobachten.
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.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
storageClassNamein 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)
Die stillen Fehler – warum vorher prüfen
| Fehlt… | Was du siehst | Was wirklich passiert |
|---|---|---|
| StorageClass | Operatoren installieren sauber, LokiStack Ready | PVCs bleiben Pending, Pods starten nie, keine Logs |
| Object Storage / CA-Bundle | Operatoren installieren sauber, LokiStack Ready | Logs werden still verworfen – kein Fehler in der Konsole |
s3:DeleteObject-Recht | LokiStack Ready, Retention konfiguriert | Compactor kann nicht löschen – Bucket wächst unbegrenzt |
Ready heißt nur: die Konfiguration ist formal gültig – nicht, dass Logs fließen.Checkliste vor der Installation (nur bei LokiStack nötig)
- StorageClass verfügbarMit ausreichender Kapazität für die gewählte Größe.
- Object Storage angelegtBucket erstellt, Zugangsdaten mit allen sechs S3-Rechten.
- TLS-CA-Bundle konfiguriertBei Self-Signed / interner CA – sonst stiller Log-Verlust.
- Initialgröße gewählt1x.demo / pico / extra-small / small / medium – nach Clustergröße, nicht nach geratenem Log-Volumen.
- Cluster-Kapazität geprüftBeispiel: 1x.medium mit Ruler braucht 70 vCPUs und 171 GiB RAM.
- 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.
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
| Umgebung | Empfohlenes Backend | Secret-type | CA-Bundle? |
|---|---|---|---|
| AWS / GCP / Azure | S3 / GCS / Azure Blob | s3 / gcs / azure | Nur bei Custom-/VPC-Endpoints mit eigenen Zertifikaten |
| On-Prem | ODF Ceph RGW oder S3-kompatibel (StorageGRID, Cloudian, HCP …) | s3 | Bei Self-Signed / interner CA: ja |
| OpenStack | Swift | swift | Bei Self-Signed / interner CA: ja |
| Edge / SNO | Forwarding an zentralen Hub | – | – |
Namenskonvention für das Secret: logging-loki-<provider>. Ceph RGW heißt in Rook-Deployments auch NooBaa.
Die sechs S3-Rechte
- List/Get: Abfragen und Compaction
- Put: Ingestion (Chunks + Index schreiben)
- Delete: Compactor löscht abgelaufene Logs
- Tagging (Get/Put): Retention & Lifecycle
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-Namenforcepathstyle="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
- CA extrahieren
openssl s_client -connect <endpoint>:<port> -showcerts </dev/null | openssl x509 -out storage-ca.crt - ConfigMap anlegen
oc create configmap loki-s3-ca-bundle -n openshift-logging --from-file=ca-bundle.crt=./storage-ca.crt - In der LokiStack-CR referenzierenUnter
spec.storage.tls.caName: loki-s3-ca-bundle. - Verifizieren
oc logs <ingester_pod> -n openshift-logging | grep -i "x509\|certificate"– muss leer bleiben.
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.
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.demo | 1x.pico | 1x.extra-small | 1x.small | 1x.medium | |
|---|---|---|---|---|---|
| Ingestion | nur Demo | 50 GB/Tag | 100 GB/Tag | 500 GB/Tag | 2 TB/Tag |
| QPS (200 ms) | nur Demo | 1–25 | 1–25 | 25–50 | 25–75 |
| Replikation | keine | 2 | 2 | 2 | 2 |
| 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
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.
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.
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
- Namespace
openshift-operators-redhatMit Labelopenshift.io/cluster-monitoring: "true". Nichtopenshift-operators– dort lauern Community-Operatoren mit Metrik-Namenskonflikten. - OperatorGroup
loki-operatorIm selben Namespace,upgradeStrategy: Default. - Subscription
channel: stable-6.6,source: redhat-operators,installPlanApproval: Automatic(oder Manual). Disconnected: Name der eigenen CatalogSource. - Prüfen
oc get csv -n openshift-operators-redhat→loki-operator.v6.6.0 … Succeeded. - Namespace
openshift-logginganlegenEbenfalls mit Cluster-Monitoring-Label – hier laufen LokiStack und alle Logging-Workloads.
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.
secret.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
- Operator installierenOperatorGroup + Subscription
cluster-logginginopenshift-logging, Kanalstable-6.6(gleich wie Loki!), Quelleredhat-operators. Check:oc get csv -n openshift-logging. - ServiceAccount anlegen
oc create sa logging-collector -n openshift-logging - ClusterRoles binden – VOR der CLF-CR
logging-collector-logs-writer(in LokiStack schreiben),collect-application-logs,collect-infrastructure-logs; für Audit zusätzlichcollect-audit-logs. - ClusterLogForwarder-CR anlegenName
instance, Output-TyplokiStack, Pipelines mitinputRefs. - Status prüfen
oc get clusterlogforwarder instance -n openshift-logging -o yaml→ ConditionsAuthorized,Valid,Ready.
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]
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 Nodeoc 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.
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-operatorinopenshift-operators(bestehende OperatorGroup, nichts extra anlegen) - Kanal:
development· Quelle:redhat-operators - Check:
oc get csv -n openshift-operators | grep cluster-observability→Succeeded
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:
- 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.adminGroupsin der LokiStack-CR (nur Modusopenshift-logging); überschreibt die Defaultssystem: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 anlegen (oc adm groups new cluster-admin), Nutzer hinzufügen, Rolle an die Gruppe binden.Troubleshooting-Spickzettel
| Symptom | Ursache / Lösung |
|---|---|
certificate verify failed im Collector | tls.ca-Block im CLF-Output ergänzen (openshift-service-ca.crt / service-ca.crt) |
x509: unknown authority in Loki-Pods | CA-Bundle für den Object Storage fehlt → ConfigMap + spec.storage.tls.caName |
429 Too Many Requests | Normal beim Erst-Ingest (Backlog-Flush), löst sich in Minuten |
| Kein Logs-Tab unter Observe | COO und UIPlugin nötig – beides prüfen |
CLF Ready: True, aber keine Logs | Collector-Pod-Logs lesen; Validation prüft die Verbindung nicht. Häufigste Ursache: fehlende TLS-CA |
ResolutionFailed bei Subscription | Kanal/Quelle prüfen: redhat-operators, nicht Community-Katalog |
PVCs Pending | Keine passende StorageClass – nachrüsten (ggf. Local Storage Operator) |
| Bucket wächst trotz Retention | s3:DeleteObject-Recht fehlt dem Storage-Account |
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
- Phase A · VorbereitenSchritte 1–4: StorageClass, Bucket + Rechte, Größe, Kapazität. Noch kein Operator!
- Phase B · Log-StoreSchritte 5–9: Loki Operator, Namespaces, Secret, CA-Bundle, LokiStack-CR.
- Phase C · CollectorSchritte 10–13: Logging Operator, ServiceAccount + RBAC, ClusterLogForwarder, Verifikation.
- 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.