Im Umfeld zahlreicher Neuerungen der Oracle Database 23c erschien Anfang Juli 2023 das erste Production Release 1.0.0 des Oracle Database Operator for Kubernetes. Dieser bietet viele Erweiterungen für den umfassenden Betrieb einer Oracle Database unter gängigen Kubernetes Distributionen. Ich versuche zu beschreiben, was der OraOperator 1.0 für “Single Instance Databases” zu bieten hat und wie einfach eine neue Datenbank aufgesetzt werden kann. Inklusive separat erhältlichem, Container-nativem Monitoring mittels Prometheus und Grafana.
OraOperator verwaltet Datenbank-Container und Datenbank-nahe
Container unter Kubernetes – umfassend und Kubernetes-nativ
Wie bereits in einem früheren Blog Artikel (Oracle Database – fit für Kubernetes) beschrieben, verwaltet der OraOperator genannte Container unter Kubernetes verschiedene Datenbank-Konfigurationen wie Autonomous Database, Sharded Database, Database Cloud Service, Container Database und Pluggable Database. Er vermag Oracle Databases außerhalb seines Kubernetes Clusters als native, Kubernetes-eigene Ressourcen einzubinden. Er kann aber auch Oracle Databases innerhalb des Clusters noch wesentlich umfassender verwalten. Datenbank-nahe Container wie Oracle REST Data Services (ORDS) und ganz neu eine Data Guard Konfiguration werden implizit und explizit mitbetreut.
Gerade bei der Verwaltung der Oracle Database im lokalen Kubernetes Cluster kamen im Laufe der Zeit weitere Features hinzu, so daß man von einem umfassenden automatisierten Betrieb von Datenbank-Containern sprechen kann. Teilweise sind diese Features recht tief in dessen Dokumentation vergraben, und so möchte ich sie zunächst auflisten und beschreiben. Wohl gemerkt, nur bezogen auf die Verwaltung der Oracle Database im lokalen Kubernetes Cluster, “SingleInstanceDatabase” genannt in der Nomenklatur des OraOperator:
Lifecycle Management
Oracle Database (CDB + 1 PDB) neu “from scratch” erzeugen, eine vorbereitete Datenbank erzeugen oder durch Cloning einer der beiden vorhergehenden Varianten erzeugen. Beim Anlegen der Datenbank darf man Version und Edition der Datenbank wählen, z.B. auch Express Edition, 23c Free, Standard Edition 2 und Enterprise Edition. Eine “vorbereitete Datenbank” ist ein Container Image mit darin entaltenen Data Files, welche bei Einrichtung des Containers umkopiert werden auf ein Persistent Volume. Alle drei Varianten sind gut geeignet für die Einbindung in agile Entwicklungs-Prozesse, bei denen neben Anwendungscontainern auch Datenbank-Container eingerichtet werden sollen um damit z.B. separat zu testen und zu entwickeln.
Oracle Database löschen – durch Löschen der Kubernetes Ressource werden auch mitverwaltete Container gelöscht. Abhängig von der gewählten Strategie wieder freigegebener Persistent Volumes (“reclaimPolicy”) können auch diese mitgelöscht oder geleert werden – oder bleiben gar erhalten.
Pluggable Database erzeugen/clonen/löschen – wurde eine Oracle Database (Container Database, CDB) lokal erzeugt oder remote eingebunden, so können darüber weitere Pluggable Databases angelegt, gecloned oder gelöscht werden.
Oracle Database patchen – ist einmal ein neues Container Image mit neuerer Version der Oracle Database Software erzeugt worden, z.B. durch Einspielen eines aktuellen Release Updates in ein bestehendes Container Image, so ist nur in der Datenbank-Ressource (verwaltet vom OraOperator) das neue Image namentlich einzutragen. Der OraOperator startet den Datenbank-Container mit der neuen Software-Version durch, die zugehörigen Datafiles werden beim Start des neuen Containers ebenfalls auf aktuellen Stand gebracht.
(Hoch-)Verfügbarkeit
Aktuell nicht vom OraOperator unterstützt wird eine Real Application Cluster (RAC) Database, obwohl RAC durchaus als Docker/Podman Konfiguration vom Oracle Support zertifiziert ist.
OraOperator Konfigurationen für Hochverfügbarkeit: Container-Replica mit
wechselnder Zuständigkeit oder Spiegelung und Failover mit Data Guard
Eine automatisierte Cold Failover Konfiguration ist per Definition möglich: Der OraOperator kann mehrere Container einer Oracle Database (eigentlich: Replica eines Kubernetes Pods) starten, wobei nur einer der Pods die Datafiles tatsächlich angebunden und geöffnet hat. Die restlichen gestarteten Container warten auf ein Signal des Kubernetes Clusters, das bei Ausfall bzw. Löschung dieses Pods gesendet wird. Der von Kubernetes signalisierte überlebende Pod bindet die Datafiles an sich und öffnet die Datenbank. Dieses Verhalten kann z.B. die Ausfallzeit beim Patchen der Datenbank reduzieren oder hilft bei ungeplantem Ausfall, so daß die Datenbank schneller wieder zur Verfügung steht.
Eine Data Guard Konfiguration ist seit Version 1.0 des OraOperator als Preview Funktionalität verfügbar. Der OraOperator verwaltet nun eine Data Guard Broker Konfiguration mit Namen der Quell- und Zieldatenbank sowie Wahl des Data Guard Protection Mode (“MaxAvailability” oder “MaxPerformance”) und erzeugt aus einer lokal verwalteten Datenbank eine Spiegel-Datenbank als eigene Kubernetes Ressource. Diese wird mittels Data Guard synchronisiert und im Bedarfsfall aktiviert.
Jede verwaltete Datenbank ist innerhalb des Kubernetes-Clusters zugänglich über Standard-Ports (1521 für Datenbank, 5500 für Enterprise Manager) oder selbst definierbare Ports. Ein vom OraOperator erzeugter Service vom Typ ClusterIP ist für den internen Zugang zuständig.
Jede verwaltete Datenbank ist außerhalb des Kubernetes-Clusters zugänglich über Standard-Ports (1521 für Datenbank, 5500 für Enterprise Manager) oder selbst definierbare Ports. Ein weiterer vom OraOperator erzeugter Service ist für den Zugang von außerhalb zuständig. Dieser Service ist wahlweise vom Typ NodePort oder, vorausgesetzt der Kubernetes Cluster ist mit dem Modul metalLB ausgestattet oder läuft in einer Cloud-Umgebung, vom Typ LoadBalancer.
Jede verwaltete Datenbank kann wahlweise einen Zugang per SSL erhalten. Die vorzuinstallierende Komponente cert-manager erzeugt und verwaltet (d.h. erneuert bei Ablauf) SSL Zertifikate für die Datenbank-Listener, der OraOperator verwendet diese Zertifikate und weist sie einem Oracle Wallet im jeweiligen Datenbank-Container zu. Per Standard handelt es sich um Zertifikate einer Self-Signed Certificate Authority, deren Zertifikat wiederum dem OraOperator angehört. Denkbar wäre es, dieses Self-Signed (Root)-Zertifikat durch ein offizielles Zertifikat auszutauschen. Meist jedoch genügt eine Verschlüsselung, bei der dieses Root-Zertifikat im Oracle Wallet vorliegt.
Der OraOperator verwaltet auf Wunsch Container vom Typ OracleRestDataServices (ORDS) mit ebenso verschlüsselter Netzwerkanbindung von innen und außen. Es ist lediglich zu spezifizieren, wieviele Container zu starten sind und welcher Datenbank sie angehören sollen. Die benötigten Zertifikate, Benutzer und Kennwörter können den gleichen Kubernetes Secrets entnommen werden wie die für das Anlegen und Verwalten der Datenbanken selbst. Damit stehen Application Express (APEX), REST enabled schemas und Database Actions (ehemals SQL*Developer Web) für die angebundene Datenbank zur Verfügung und sind ebenfalls aktualisierbar durch einfachen Tausch der Container-Versionsnummer.
Möchte man einzelne Pluggable Databases durch den OraOperator verwalten, so ist zunächst eine Verbindung zu einer Container Database (CDB) herzustellen. Dies geschieht durch automatisches Anlegen und Verwalten eines speziell konfigurierten ORDS Containers, der die REST Management API zur Verwaltung der verknüpften Datenbank aktiviert und konfiguriert hat.
Monitoring
In jedem vom OraOperator verwalteten Datenbank Container ist per Standard der Oracle Enterprise Manager (OEM) enthalten und wird in dem Container gestartet.
Oracle Database (und Transactional Event Queues) Metric Exporter –
für Docker, aber auch für Kubernetes
Ein separat erhältlicher, nicht vom OraOperator verwalteter Container kann aufgesetzt werden, um von einer damit verknüpften Datenbank Laufzeit-Metriken abzugreifen. In kurzen, regelmäßigen Zeitabständen werden sie in eine Prometheus Datenbank eingelesen, um sie durch Werkzeuge wie Grafana auszuwerten. Vorgefertigte Oracle Datenbank-Dashboards für Grafana zeigen Metriken an wie Speicher-,CPU-,SGA- Größen, Top Wait Classes, Top Sessions, Netzwerkverkehr uvm. Separate Dashboards und Metriken für die Überwachung von Transactional Event Queues sind ebenfalls vorhanden. Somit können Metriken aus allen verwalteten Datenbanken in zentralen, konfigurierbaren Dashboards dargestellt werden.
Weitere Monitoring-Möglichkeiten existieren mit Kubernetes-Mitteln: weitere Grafana Dashboards zeigen Metriken auf Container-Ebene wie z.B. Volume-Größen, I/O, Netzwerkverkehr, CPU- und Speicher Auslastung pro Container und vieles mehr. Eine detailliertere Überwachung des Netzverkehrs, z.B. zwischen einzelnen Containern und nach außen hin, ist mit den Netzwerktools istio und kiali größtenteils möglich: Leichte Einschränkungen gibt es beim Net8 Protokoll der Datenbank, welches von istio eben nicht automatisch (per mTLS) verschlüsselt werden sollte, sonst können sich Clients nicht mehr mit der Datenbank verbinden. Dagegen kann eine explizite Net8 TLS-Verschlüsselung mit dem OraOperator besonders leicht aufgesetzt werden.
Beispiel-Setup: Oracle Database, APEX und Grafana Monitoring einrichten
1. OraOperator unter Kubernetes installieren
In ein bestehendes Kubernetes Cluster läßt sich die Software des OraOperator mit zwei kurzen Kommandos installieren. Für die Verwaltung von SSL Zertifikaten für die interne Kommunikation des OraOperator sollte zunächst die Komponente “cert-manager” installiert werden. Ist bereits eine Container Management Plattform wie Oracle Verrazzano installiert, so ist der cert-manager bereits vorhanden und muß nicht mehr berücksichtigt werden.
Nach erfolgter Installation müßte im Kubernetes Cluster ein neuer Namespace oracle-database-operator-system angelegt sein, darin mehrere Container bzw. Pods desselben Software-Deployments oracle-database-operator-controller-manager. Dies kann wie folgt geprüft werden:
$ kubectl get pods -n oracle-database-operator-system
NAME READY STATUS RESTARTS AGE
oracle-database-operator-controller-manager-775bb46fd-6smq7 1/1 Running 5 (24h ago) 33d
oracle-database-operator-controller-manager-775bb46fd-mkhxw 1/1 Running 6 (24h ago) 33d
oracle-database-operator-controller-manager-775bb46fd-wjxdn 1/1 Running 4 (24h ago) 33d
2. Oracle Database erzeugen
Es gibt zahlreiche Beispiele für den Umgang mit SingleInstanceDatabase-Ressourcen auf github.com. Betrachten wir hier einen möglichst einfachen Fall: Anlegen einer neuen Oracle Database mit Angabe eines vorgefertigten Container Images auf container-registry.oracle.com. Zunächst legen Sie bitte einen neuen Kubernetes Namespace zum Test an:
> kubectl create namespace oracledb
Dann erzeugen Sie ein Kubernetes “Secret”, in dem das gewünschte Admin-Kennwort Ihrer zukünftigen Datenbank abgelegt wird. Hier im Beispiel “db-admin-secret.yaml” wird ein Klartext-Kennwort angegeben. Alternativ wäre ein base64-encoding des Wertes möglich (das Feld stringData müßte umbenannt werden nach data, dann darf ein base64 Wert eingetragen werden).
apiVersion: v1
kind: Secret
metadata:
name: db-admin-secret
type: Opaque
stringData:
## Specify your DB password here
oracle_pwd: "MyComplexPwd123##"
Legen Sie das Secret in Kubernetes mit folgendem Kommando an (im eben angelegten Namespace):
kubectl apply -f db-admin-secret.yaml -n oracledb
Jetzt benötigen wir noch ein Kubernetes Secret, in dem Ihre Login-Daten für den vom OraOperator herunterzuladenden Container mit Oracle Software darin auf container-registry.oracle.com eingetragen sind. Das ist beispielsweise möglich durch folgendes Kommando (der Name des Secrets lautet auf oracle-container-registry-secret):
Bitte melden Sie sich auch mit dem Browser auf container-registry.oracle.com an, klicken auf den Bereich “database” und akzeptieren Sie dort die Lizenzbestimmungen.
Ist dies erledigt, können wir jetzt eine neue Datenbank erzeugen. Die nachfolgende Beispiel-Datei oracle21c.yaml enthält Angaben zur Datenbank-Größe, dem zu verwendenden Image und Admin Kennwörtern mit den eben angelegten Secrets:
apiVersion: database.oracle.com/v1alpha1
kind: SingleInstanceDatabase
metadata:
name: db21c
spec:
## Use only alphanumeric characters for sid
sid: ORCL1
## DB edition.
edition: enterprise
## Secret containing SIDB password mapped to secretKey
adminPassword:
secretName: db-admin-secret
## DB character set
charset: AL32UTF8
## PDB name
pdbName: orclpdb1
## Enable/Disable ArchiveLog. Should be true to allow DB cloning
archiveLog: true
## Database image details
image:
pullFrom: container-registry.oracle.com/database/enterprise:latest
pullSecrets: oracle-container-registry-secret
## size is the required minimum size of the persistent volume
## storageClass is specified for automatic volume provisioning
## accessMode can only accept one of ReadWriteOnce, ReadWriteMany
persistence:
size: 100Gi
## oci-bv applies to OCI block volumes. Use "standard" storageClass for dynamic provisioning in Minikube. Update as appropriate for other cloud service providers
storageClass: "oci-bv"
accessMode: "ReadWriteOnce"
## Count of Database Pods.
replicas: 1
Eine Besonderheit ist, daß die Datafiles der neuen Datenbank in einem Persistent Volume angelegt werden, das von Kubernetes erst noch zuzuweisen ist. Läuft Ihre Kubernetes Umgebung in der Oracle Cloud, so ist eine Storage Klasse Namens “oci-bv” bereits vorinstalliert, welche Ihre benötigten Volumes auf Anfrage frisch erzeugt. Unter Azure/AKS wäre wahrscheinlich eine Storage Klasse namens “managed-csi” denkbar oder “azurefile-csi”, unter AWS/EKS wohl am häufigsten “gp2”. Ein weiterer Weg wäre das Anlegen einer “dummy” Storage Klasse die keine neuen Volumes erzeugt, und ihr ein paar manuell angelegte Persistent Volumes (z.B. per NFS) in ausreichender Größe zuzuordnen.
Erzeugen Sie nun die neue Kubernetes Ressource per kubectl, so daß der OraOperator sein Werk tun kann um die neue Datenbank anzulegen:
kubectl apply -f oracle21c.yaml -n oracledb
Die Ressource ist schnell angelegt, doch das Herunterladen der Container und Starten des Installationsprozesses darin dauert einige Minuten. Sie können den Verlauf beobachten, indem Sie den Status der Ressource beobachten und hin und wieder in die Log Daten des Containers hineinschauen:
> kubectl get pods -n oracledb
NAME READY STATUS RESTARTS AGE
db21c-h2kpr 1/1 Running 0 10m
> kubectl logs db21c-h2kpr -n oracledb --since=0
[2023:06:21 12:29:41]: Acquiring lock .ORCL1.create_lck with heartbeat 30 secs
[2023:06:21 12:29:41]: Lock acquired
[2023:06:21 12:29:41]: Starting heartbeat
[2023:06:21 12:29:41]: Lock held .ORCL1.create_lck
ORACLE EDITION: ENTERPRISE
LSNRCTL for Linux: Version 21.0.0.0.0 - Production on 21-JUN-2023 12:29:41
Copyright (c) 1991, 2021, Oracle. All rights reserved.
Starting /opt/oracle/product/21c/dbhome_1/bin/tnslsnr: please wait...
TNSLSNR for Linux: Version 21.0.0.0.0 - Production
System parameter file is /opt/oracle/homes/OraDB21Home1/network/admin/listener.ora
Log messages written to /opt/oracle/diag/tnslsnr/chronin-db-h2kpr/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 21.0.0.0.0 - Production
Start Date 21-JUN-2023 12:29:42
Uptime 0 days 0 hr. 0 min. 0 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /opt/oracle/homes/OraDB21Home1/network/admin/listener.ora
Listener Log File /opt/oracle/diag/tnslsnr/chronin-db-h2kpr/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))
The listener supports no services
The command completed successfully
Prepare for db operation
8% complete
Copying database files
31% complete
Creating and starting Oracle instance
32% complete
36% complete
Ist die Installation fertiggestellt, zeigt auch die zugehörige Kubernetes Ressource neben Versionsnummern und Connect Strings einen “Healthy” Status:
> kubectl get singleinstancedatabase -n oracledb
NAME EDITION STATUS VERSION CONNECT STR TCPS CONNECT STR OEM EXPRESS URL
db21c Enterprise Healthy 21.3.0.0.0 10.0.10.77:32113/ORCL1 Unavailable https://10.0.10.77:31895/em
Bei Schwierigkeiten können die Kubernetes Events oder auch die Logs der OraOperator Pods (im Namespace oracle-database-operator-system) hilfreich sein. Vielleicht läßt sich das Container Image nicht herunterladen, oder der neue Container wartet unbestimmt und vergeblich auf Persistent Volumes vom angeforderten Typ, Zugriffsart (ReadWriteOnce ?) oder Größe…
Ist die neue Ressource nun Healthy, so wurden auch Netzwerk-Ressourcen vom OraOperator angelegt, um von innerhalb und außerhalb des Kubernetes Clusters zuzugreifen:
> kubectl get services -n coracledb
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
db21c-db ClusterIP 10.96.32.21 <none> 1521/TCP 21d
db21c-db-ext NodePort 10.96.84.181 <none> 5500:31895/TCP,1521:32113/TCP 21d
Der Standard-Typ “NodePort” für den Datenbank-Dienst ist aber oft nicht sehr sinnvoll, muß man so direkt die Adresse des Worker Nodes ansprechen, auf dem der Datenbank-Container läuft. Besser wäre, wenn möglich, die Umstellung (oder gleich die richtige Angabe vorab) auf einen Dienst vom Typ “LoadBalancer”. Kubernetes weist dem Dienst eine separate, neue und von außen zugängliche IP Adresse zu. Das funktioniert aber nur, wenn eine LoadBalancer-Implementation installiert wurde wie z.B. metalLB, oder mit angeschlossenem LBaaS (load balancer as a service) eines Cloud Providers:
Oftmals ist ein direkter Datenbank-Zugriff von außerhalb des Kubernetes Clusters gar nicht erwünscht. Ein Container wie ORDS bzw. Application Express könnte intern auf die Datenbank zugreifen und seinerseits die Pforten für den Zugriff von außen über HTTP(S) ermöglichen. Und genau dies wird nun getan – richten wir einen ORDS Container mit APEX ein.
3. ORDS bzw. Application Express Container mit der Oracle Database verknüpfen
Um einen Container für REST Data Services und / oder Application Express zu erzeugen benötigen wir zunächst zwei weitere Kubernetes Secrets, um einen neuen ORDS Datenbank-Benutzer anzulegen sowie ein vorläufiges Kennwort für den admin-Benutzer für Application Express. Diesmal begnügen wir uns mit zwei Kommandozeilen-Aufrufen, statt eine YAML Datei mit Einträgen zu verwenden.
Die Ressourcenbeschreibung “db21c-ords.yaml” enthält nun Angaben zur Verknüpfung des neuen ORDS Containers an die eben erstellte SingleInstanceDatabase, d.h. deren Kubernetes-Namen und das Secret mit dem Datenbank-Kennwort. Dazu kommen Angaben zum Container-Image mit dem im vorigen Schritt angelegten Docker Registry-Secret und die beiden neuen Kennwörter für den ORDS Datenbank Benutzer (“ORDS_PUBLIC_USER”) und für Application Express:
apiVersion: database.oracle.com/v1alpha1
kind: OracleRestDataService
metadata:
name: db21c-ords
spec:
## Database ref. This can be of kind SingleInstanceDatabase.
## Make sure the source database has been created by applying singeinstancedatabase_express.yaml
databaseRef: "db21c"
## Secret containing databaseRef password
adminPassword:
secretName: db-admin-secret
secretKey: oracle_pwd
keepSecret: true
## Secret containing ORDS_PUBLIC_USER password
ordsPassword:
secretName: ords-secret
secretKey: oracle_pwd
keepSecret: true
## To configure APEX with ORDS, specfiy the apexPassword secret details. Leave empty if Apex is not needed.
## This is a secret containing a common password for APEX_PUBLIC_USER, APEX_REST_PUBLIC_USER, APEX_LISTENER and Apex administrator (username: ADMIN)
apexPassword:
secretName: apex-secret
secretKey: oracle_pwd
keepSecret: true
loadBalancer: true
## ORDS image details
image:
pullFrom: container-registry.oracle.com/database/ords:21.4.2-gh
pullSecrets: oracle-container-registry-secret
## PDB Schemas to be ORDS Enabled.
## Schema will be created (if not exists) with password as .spec.ordsPassword.
restEnableSchemas:
- schemaName: restme
enable: true
urlMapping: restme
Hier könnten sie bereits im Vorfeld wählen, ob der vom OraOperator angelegte Netzwerk-Service vom Typ “LoadBalancer” sein soll oder nicht. Bei “loadbalancer: false” würde ein NodePort-Service erzeugt. Das SSL Zertifikat kommt wieder vom OraOperator (eigentlich von cert-manager) bzw. dessen konfiguriertem Root-Zertifikat. Bitte beachten Sie, daß ORDS bzw APEX sich auf diese Weise immer in die Container Database installiert, nicht in die “erstbeste” Pluggable Database hinein. Legen Sie nun die neue Ressource an mit folgendem Kommando:
> kubectl apply -f db21c-ords.yaml -n oracledb
Ist alles richtig eingetragen, so steht Ihnen nach wenigen Minuten ein neuer Container und Netzwerk-Dienst zur Verfügung. Der neue Container richtet beim ersten Aufruf alle ORDS bzw Application Express Schemas in der Datenbank ein, das dauert ein klein wenig. Fehler und Probleme sehen Sie in den Events des “oracledb” Namespaces und im Log des OraOperator Containers.
> kubectl get pods -n oracledb
NAME READY STATUS RESTARTS AGE
db21c-h2kpr 1/1 Running 0 22d
dbc21c-ords-umlrt 1/1 Running 0 41m
> kubectl get services -n oracledb
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
db21c ClusterIP 10.96.32.21 <none> 1521/TCP 22d
db21c-db-ext LoadBalancer 10.96.84.181 158.101.217.247 5500:31895/TCP,1521:32113/TCP 22d
db21c-ords LoadBalancer 10.96.75.108 158.101.201.244 8443:32309/TCP 44m
> kubectl get oraclerestdataservice -n oracledb
NAME STATUS DATABASE DATABASE API URL
DATABASE ACTIONS URL APEX URL
db21c-ords Healthy db21c https://158.101.201.244:8443/ords/orclpdb1/_/db-api/stable/
https://158.101.201.244:8443/ords/sql-developer https://158.101.201.244:8443/ords/orclpdb1/apex
Das war es auch schon, Sie können nun versuchen mit Ihrem Browser die eben erhaltene APEX URL einmal aufzurufen und das admin-Kennwort gleich zu ändern. Die ORDS REST API, Database Management API und Database Actions stehen auch gleich zur Verfügung, müssen aber noch innerhalb der Datenbank weiter konfiguriert werden. Zum Beispiel mit APEX, dann müssen Sie sich nicht direkt mit der Datenbank verbinden.
Nehmen sie für den Admin-Login nicht die Standard-Seite “/ords/orclpdb1/apex”,
sonden die Administrations-Seite über die URI “/ords/orclpdb1/f?p=4550:10”
Herzlichen Glückwunsch! Datenbank und Entwicklungs-Werkzeuge sind gestartet, nun fügen wir neben dem klassischen Enterprise Manager “Database Express” noch Monitoring mittels Grafana Dashboards hinzu.
4. Datenbank Metriken für Prometheus und Grafana bereitstellen
Das recht neue, noch in Entwicklung befindliche Projekt trägt den offiziellen Namen “Unified Observability Exporter“. Dieses Projekt ist neu in Java erstellt worden auf Basis der Go-Implementierung eines database metric exporters für Oracle (auch verfügbar für MySQL und Postgres) von Seth Miller (https://github.com/iamseth/oracledb_exporter). Metriken können dort frei definiert werden auf Basis von SQL Abfragen an System-Views der Datenbank. Es gibt vorbereitete Metriken in einbindbaren .toml Dateien voller SQL Abfragen und Attribut-Mappings, z.B. für einen allgemeinen Datenbank-Überblick wie SGA, Top Sessions, Top Wait Classes, aber auch Metriken wie Trace Events, ASM Storage, Alert Logs, Advanced Queuing und Transactional Event Queues. So verhält es sich auch für das Monitoring Werkzeug Grafana: einige vorbereitete Dashboards können heruntergeladen und eingebunden werden für einen allgemeinen Überblick, für das I/O Verhalten der Datenbank und für Advanced Queuing bzw. Transactional Event Queues.
Viel (Betriebs-) Komfort
mit Oracle Verrazzano
Prinzipiell ist lediglich ein Container mit einem entsprechend leseberechtigten Datenbank-Benutzer mit der Datenbank zu verbinden. Dieser Container führt die in den .toml Dateien aufgeführten SQL Abfragen immer dann aus, wenn ein Prometheus Container (die Metrik-Datenbank unterhalb von Grafana) seinen als “scraping” bezeichneten Job ausführt. Das vorbereitete Container-Image des “Unified Observability Exporter” liegt ebenso auf container-registry.oracle.com zum Download bereit wie die bereits verwendeten Datenbank-Images und ORDS/APEX Images. Eine Erläuterung der Installation von Prometheus und Grafana möchte ich hier nicht aufführen, wird aber im github-Projekt am Beispiel einer docker-compose Konfiguration ohne Kubernetes erläutert. Aus Komfort-Gründen möchte ich Sie hier an die Installation der Oracle Container Management Plattform “Verrazzano” verweisen. Diese enthält diverse aufeinander abgestimmte Komponenten wie die ohnehin benötigten cert-manager, Grafana, Prometheus aber auch OpenSearch, ArgoCD (für continuous deployment nach Kubernetes), velero backup, istio/Kiali Netzwerk Überwachung, Keycloak Identity Broker, Rancher Kubernetes UI und einige mehr.
Das github-Projekt besteht aus mehreren Code-Branches mit altem Go Code, neuem Java Code mit Anweisungen für die Einrichtung unter Kubernetes und mit neuem Java Code, Grafana Dashboards und Anweisungen für die Einrichtung unter docker-compose. Ich werde mich daher für die vollständige Einrichtung aus mehreren Unter-Töpfen im Projekt bedienen.
Beginnen wir mit der Erzeugung eines Kubernetes Secrets, das einen Datenbank Connect String enthält für den Zugang zur weiter oben angelegten Datenbank , genauer zur Container Database / CDB. Statt des Benutzers “system” könnten Sie einen separaten Benutzer anlegen, z.B. mit “SELECT ANY DICTIONARY” Recht, wenn Ihnen das nicht zu viel erscheint, oder SELECT Rechte auf alle in den .toml Dateien angefragten “sys.gv$*” und “sys.dba_*”-Views. Um die Datenbnk innerhalb des Kubernetes Clusters anzusprechen, dürfen wir den internen DNS Dienst verwenden statt die aktuelle IP Adresse des Containers anzugeben. Der interne DNS Name wäre <Name des Dienstes>.<Namespace>, in unserem Beisiel also db21c.oracledb
Dann laden Sie sich bitte eine der .toml – Dateien aus dem Projekt herunter und binden Sie als Kubernetes ConfigMap ein. So können Sie jederzeit Änderungen daran vornehmen, die nach Neustart des Containers greifen. Ohne gleich einen neuen Container bauen zu müssen. Am besten, Sie verwenden die Datei “default-metrics.toml” aus dem main Branch im Unterverzeichnis exporter:
Im Branch “java-impl-branch” des github Projektes finden Sie auch Kubernetes YAML Dateien für die Installation des Containers als Deployment, einen Kubernetes Service für den internen Netzwerkzugriff sowie eine Prometheus-Konfiguration, als Kubernetes Ressource ServiceMonitor genannt. Die Dateien liegen dort im Unterverzeichnis examples und wären noch auf unsere Belange anzupassen. Sie können nachfolgende, bereits angepaßte Deployment-Konfiguration z.B. als metric-deployment.yaml abspeichern und mit “kubectl apply -f metric-deployment.yaml -n oracledb” in Ihrem Kubernetes Cluster anlegen:
Und, hat das Deployment bei Ihnen funktioniert ? Die im Deployment definierte Umgebungsvariable DEFAULT_METRICS zeigt auf unsere per ConfigMap eingebundene .toml-Datei. Die Variable DATA_SOURCE_NAME enthält Benutzername, Kennwort und Connect String aus dem vorher angelegten Secret. Die TNS_ADMIN Variable ist aktuell nur ein “dummy”, sie könnte auf ein Secret zeigen mit enthaltenem Oracle Wallet und tnsnames.ora Datei für den verschlüsselten Zugang zu einer Oracle Datenbank. Der Container sollte nach kurzer Zet laufen und auch im Log keine Fehler zeigen:
> kubectl get pod -n oracledb
NAME READY STATUS RESTARTS AGE
db21c-h2kpr 1/1 Running 0 22d
db21c-ords-umlrt 1/1 Running 0 20h
unified-observability-exporter-db21c-bbc9d99b7-wqsc4 1/1 Running 0 28s
> kubectl logs unified-observability-exporter-db21c-bbc9d99b7-wqsc4 -n oracledb
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.0)
2023-07-14 11:21:14.173 INFO 1 --- [ main] o.o.ObservabilityExporterApplication : Starting ObservabilityExporterApplication v0.1.0 using Java 11.0.15 on unified-observability-exporter-db21c-bbc9d99b7-wqsc4 with PID 1 (/usr/share/observability-exporter.jar started by root in /)
2023-07-14 11:21:14.177 INFO 1 --- [ main] o.o.ObservabilityExporterApplication : No active profile set, falling back to 1 default profile: "default"
2023-07-14 11:21:15.758 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 9161 (http)
2023-07-14 11:21:15.776 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-07-14 11:21:15.776 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.63]
2023-07-14 11:21:15.909 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-07-14 11:21:15.909 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1636 ms
...
...
2023-07-14 11:21:19.226 INFO 1 --- [ Thread-4] oracle.observability.logs.LogsExporter : No logs records configured
2023-07-14 11:21:19.230 INFO 1 --- [ Thread-3] o.observability.tracing.TracingExporter : No trace records configured
2023-07-14 11:21:19.751 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9161 (http) with context path ''
2023-07-14 11:21:19.762 INFO 1 --- [ main] o.o.ObservabilityExporterApplication : Started ObservabilityExporterApplication in 6.265 seconds (JVM running for 7.278)
Ein paar SQL Konvertierungsfehler bzw. Fehler wegen zu großer Datentypen können aktuell auftreten, aber das wird sicher bald behoben sein. Legen Sie nun einen Kubernetes Service an, daß wir testen können ob Metriken überhaupt entstehen. Auch hier können Sie die überarbeitete Datei “metric-service.yaml” abspeichern und mit “kubectl apply -f metric-service.yaml -n oracledb” an Ihr Cluster senden:
Der Service ist nur Kubernetes-intern erreichbar, d.h. um ihn zu testen können Sie nun in einem anderen Container einen “wget” Aufruf starten und schauen, ob ansprechende Metriken erzeugt werden:
> kubectl run busybox --image=busybox --dry-run=client -o yaml --command -- /bin/sh -c "wget -O - http://unified-observability-exporter-service-db21c.oracledb:9161/metrics" | kubectl apply -f -
> kubectl logs busybox
...
...
oracledb_concurrency_background_wait_event_average_wait_bg{inst_id="1",con_id="0",event_name="PGA memory operation"} 0.0
oracledb_concurrency_background_wait_event_average_wait_bg{inst_id="1",con_id="0",event_name="Log archive I/O"} 0.0
oracledb_concurrency_background_wait_event_average_wait_bg{inst_id="1",con_id="0",event_name="latch: shared pool"} 2.0
# HELP oracledb_io_filetype_write_data_s Number of megabytes written via single block write requests
# TYPE oracledb_io_filetype_write_data_s gauge
oracledb_io_filetype_write_data_s{inst_id="1",con_id="1",filetype_name="Temp File"} 200.0
oracledb_io_filetype_write_data_s{inst_id="1",con_id="1",filetype_name="Log File"} 3229.0
oracledb_io_filetype_write_data_s{inst_id="1",con_id="1",filetype_name="Archive Log"} 0.0
oracledb_io_filetype_write_data_s{inst_id="1",con_id="1",filetype_name="Data File"} 6924.0
oracledb_io_filetype_write_data_s{inst_id="1",con_id="1",filetype_name="Control File"} 14642.0
...
...
> kubectl delete pod busybox
Sehen Sie viele, viele Zeilen Text und beginnen die meisten davon mit “oracledb_*”, dann sieht das sehr gut aus. Der Metrik Export funktioniert.
Legen Sie nun eine ServiceMonitor-Ressource an, die einer bereits bestehenden Prometheus Installation mitteilt, wie sie an die Metriken des Exporters herankommt. Die angepaßte Datei trägt den Namen “metric-monitor.yaml” , Sie können den nachfolgenden Inhalt abermals kopieren und mit “kubectl apply -f metric-monitor.yaml -n oracledb” in Ihr Cluster eintragen:
Nach etwa 20 Sekunden sollten Sie in Ihrer Prometheus Installation per Browser sehen können, ob die Metriken auch dort angekommen sind. Klicken Sie dort auf “graph” und geben Sie den Anfangs-Text “oracledb” ein, denn so beginnen alle Metriken, die vom “Unified Observability Exporter” erzeugt werden:
Sieht die Liste nicht wie gewünscht aus, so wurden vielleicht noch keine Metriken erfaßt. Prüfen Sie sicherheitshalber, ob die Scraping-Konfiguration über den ServiceMonitor in Ihre Umgebung als sogenanntes Target übernommen wurde. In meiner Verrazzano-basierten Umgebung sieht das in etwa wie nachfolgend aus – ich habe zwar einen anderen Namespace und Datenbank-Namen gewählt, aber das Prinzip ist gleich:
Falls nicht, so müßte ein Berechtigungs-Problem in Ihrer Prometheus-Installation vorliegen. Bitte suchen Sie in den Logs Ihres Prometheus Containers nach entsprechenden Fehlermeldungen, vielleicht müssen Sie den ServiceAccount des Prometheus Pods noch um Rechte erweitern, in anderen Namespaces nach Daten zu suchen als dem eigenen…
Der letzte Schritt liegt nun noch darin, die vorbereiteten Dashboards in Grafana zu importieren und sich die gesammelten Werte sinnvoll darstellen zu lassen. Laden Sie am besten aus dem github-Projekt im main Branch aus dem Unterverzeichnis “grafana/dashboards” die Datei dashboard.json herunter:
Wechseln Sie nun mit Ihrem Browser in die Grafana Oberfläche und importieren Sie das Dashboard – entweder per Datei Upload oder per Copy&Paste:
Nun sollte ein neues Dashboard zum Anschauen zur Verfügung stehen – und auch gleich mit Werten aus Prometheus befüllt sein:
In dem github Projekt liegen im java-impl-branch genannten Branch noch weitere Dashboards und Metriken (.toml Dateien) zu TEQ und Advanced Queuing, z.B. im Unterverzeichnis oracle-teq/dashboards und oracle-teq/metrics. Im main Branch befinden sich im Verzeichnis docker_vol/graf_app_vol noch weitere Datenbank-Dashboards mit Einzelteilen aus dem Haupt-Dashboard für das I/O Verhalten, SQL Cache, Concurrency. Diese benötigen eventuell weitere Metriken aus dem Unterverzeichnis oracle-db-monitoring-exporter.
Herzlichen Glückwunsch und Dank für Ihre Aufmerksamkeit bis hierhin ! Auch weiterhin viel Spaß beim Testen und Ausprobieren.
Fazit:
Wir dürfen noch einige verfeinerte und verbesserte Features erwarten, bis Oracle Database 23c offiziell verfügbar ist und den Developer Preview-Status überwunden hat. Alles in allem ist bereits heute eine recht umfassende Unterstützung für typische Container-Umgebungen gegeben. Der aktuelle, durch Datenbank-Lizenzen unter vollem Support stehende Database Operator für Kubernetes funktioniert auch mit Oracle 19c und 21c Datenbank Versionen, auch wenn er vorrangig im Umfeld einer umfassenden Microservices-Unterstützung von Oracle 23c gesehen wird. Das gleiche Prinzip gilt auch für den Unified Observability Exporter für Grafana.
Doing System Integration, Data Integration, System Integration Frameworks and Data Integration Frameworks since so many years and moved from Transaction Monitors to Application Servers to Cloud Infrastructure, Kubernetes and AI - all in the name of Oracle.