DB Containers: Deploying Oracle Databases on RedHat OpenShift was a breeze
Success is subject to availability, please read fine print to complete details

I work with software but it does not define me and my constant is change and I live a life of evolution. Learning, adapting, forgetting, re-learning, repeating I am not a Developer, I simply use software tools to solve interesting challenges and implement different use cases.
Just of out curiosity I reached out to the RedHat team in Switzerland to test how well the Oracle Database Operator for Kubernetes (DB Operator or OraOperator) functions on a Non-Oracle environment like OpenShift.
The main objectives to achieve were the installation and Single Instance Database deployment. In general the process on Oracle Cloud Infrastructure is simple and mostly pain free and after my initial tests, I can confirm the same on OpenShift.
About this Post
This post will focus on the high level steps used to deploy single database instance using the Oracle DB Operator, what to look out for and any major challenges that were faced.
The DB Operator lists the following Kubernetes variants that have been tested:
Oracle Container Engine for Kubernetes (OKE) with Kubernetes 1.30 or later
Redhat Openshift with version v4.16 or later
Oracle Linux Cloud Native Environment(OLCNE) 1.9 or later
Minikube with version v1.29.0
My colleagues and I have cut our teeth on OKE but for someone working at Oracle using Oracle Cloud, it should work … Right?!
The Objectives are Simple
Install the DB Operator on OpenShift
Deploy a Database with it
Make some observations
How easy was it to install?
Any points to note, work-arounds or gotchas?
Note any issues & solutions (if available)
Keeping this one very basic and simple. I’m no kubectl expert and feeling pretty good that I can even check the status of the containers, so nothing fancy here.
About the Environment
I’d like to thank the RedHat Marketing team Switzerland (Romy Lienhard) and partner [TD SYNNEX], Artem Zwahlen and Shaun Wetli, for making this possible and my partner in crime Victor Vendo who has been supporting me on this journey.
The OpenShit cluster was hosted by the Solution Center with enough resources to deploy a personal data center.
Techie Details that Matter
| Infrastructure Provider | VSphere |
| OpenShift version | 4.19.16 |
| DB Operator version | 2.0.0 |
| Storage Class: Provisioner | csi.vsphere.vmware.com |
| Storage Class: Class | thin-csi |
Getting the DB Operator
The Oracle Database Operatorwas not listed in the RedHat OpenShift OperatorHub in the Cluster, but in a recent announcement it can be found their Software Catalog.

So for now, manual install using the provided YAML from the GitHub repo or using one of the options on the OperatorHub.io
Check the Prerequisites and follow the child sections for the lifecycle operations that you will perform on the cluster. (Single Instance Database Prerequisites)
With this details, lets get to it.
To Install the DB Operator - follow the Repo Instructions
Before we get into it there are very few OpenShift specific prerequisites or steps, which is good for us.
Secondly, I recommend cloning the repository vs. copy pasting YAML from the repo one by one.
As I mentioned above, follow the instructions in the GitHub repo, they are fairly straight forward but apply some common sense.
For example: A Certificate Manager is required as the operator uses WebHooks. If your environment already as one deployed, do not install another one.

Certificate Manager Installed - Check ✅
Applying YAML - kubectl or oc
OpenShift provides a version of the kubectl cli tool called OpenShift CLI or oc for short. The 3.11 documentation clarifies the difference best but in a nutsheell oc offers the same capabilities as the kubectl, but it is extended to natively support OpenShift Container Platform features.
I would use oc when possible and the main syntax for basic commands are the same:
# Kubectl samples
kubectl get all -n sidb-ns
kubectl get singleinstancedatabases -n sidb-ns
kubectl get services -n sidb-ns
kubectl apply -f sidb_create_dbfree26ai.yaml
# oc samples = save on keyboard strokes
oc get all -n sidb-ns
oc get singleinstancedatabases -n sidb-ns
oc get services -n sidb-ns
oc apply -f sidb_create_dbfree26ai.yaml
Role Bindings
We selected the Cluster Scoped deployment option, but I am sure as a best practice, limiting the operators deployment and monitoring scope is better.
Single Instance Database Prerequisites
You may opt to proceed with the Single Instance Database Prerequisites now to conclude all of these steps together.
The optional response role bindings are recommended for database deployments for node access, storage and volume management.
This is also one of those few OpenShift specific perquisites as OpenShift requires additional Security Context Constraints (SCC) for deploying and managing the SingleInstanceDatabase resource.
Review the openshift_rbac.yaml and make note of the objects and resources that are created.
Install the DB Operator itself
Apply the oracle-database-operator.yaml to deploy the operator and check that the pods are up and running.
# Use oc to install the operator
oc apply -f oracle-database-operator.yaml
# Check the pods in the oracle-database-operator-system namespace
oc get pods -n oracle-database-operator-system
NAME READY STATUS RESTARTS AGE
oracle-database-operator-controller-manager-59f6bd9b64-65zq2 1/1 Running 0 2m
oracle-database-operator-controller-manager-59f6bd9b64-dvxnf 1/1 Running 0 2m
oracle-database-operator-controller-manager-59f6bd9b64-x7ljk 1/1 Running 0 2m
Creating an Oracle Single Instance Database
The Operator does provide lifecycle management for different database infrastructure options:
Following the Containerized Oracle Single Instance Database and Data Guard, completing the prerequisites, it is simple to Create a Database
Copy the Create Template
Create a copy of the config/samples/sidb/singleinstancedatabase_create.yaml, edit it for the type of database container to deploy.
Samples are provided for (not a complete list):
| Sample | Database Version |
| Complete Template | singleinstancedatabase.yaml |
| Enterprise Edition v19c | singleinstancedatabase_create.yaml |
| Free Edition v236ai | singleinstancedatabase_free.yaml |
| Free Edition Lite v236ai | singleinstancedatabase_free-lite.yaml |
| Free Edition True Cache v236ai | singleinstancedatabase_free-truecache.yaml |
| Oracle Rest Data Service | oraclerestdataservice.yaml |
Edit the Template
Update the template appropriately
Name of the resource
Ensure the Namespace is correct
Specify the resources setting and configuration for deployment
Update the Storage Class to match the available Storage Classes available in your cluster
Add / verify the service account name to run the deployment as. This goes in the spec section
Sample DB Free
#
# Copyright (c) 2023, Oracle and/or its affiliates.
# Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
#
apiVersion: database.oracle.com/v4
kind: SingleInstanceDatabase
metadata:
name: db001
namespace: sidb-ns
spec:
## DB edition
edition: free
## Secret containing SIDB password mapped to secretKey
adminPassword:
secretName: db-admin-secret
## Database image details
image:
## Oracle Database Free is only supported from DB version 23.2 onwards
pullFrom: container-registry.oracle.com/database/free:23.7.0.0
pullSecrets: ocr-snurse-cred
prebuiltDB: true
## 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: 50Gi
## Update as appropriate for other cloud service providers
storageClass: "thin-csi"
accessMode: "ReadWriteOnce"
## Count of Database Pods. Should be 1 for free edition.
replicas: 1
## Service Account
serviceAccountName: "sidb-sa"
The file is saved as create_sidb_23ai_db001.yaml
Create Your Secrets
The YAML file to create the single instance database references two secrets. The database admin password and the pull secret.
spec.adminPassword.secretName: db-admin-secret
image.pullSecrets: ocr-snurse-cred
Create each of these in your project / namespace
# Create the Admin Password Secret
oc create secret generic db-admin-secret \
--from-literal=oracle_pwd=<specify password here> \
-n sidb-ns
# response
secret/db-admin-secret created
# Create the Pull Secret used to connect to the Container REgistry
$ oc create secret docker-registry oracle-container-registry-secret \
--docker-server=container-registry.oracle.com \
--docker-username='<oracle-sso-email-address>' \
--docker-password='<container-registry-auth-token>' \
--docker-email='<oracle-sso-email-address>' \
-n sidb-ns
# reponse
secret/oracle-container-registry-secret created
Deploy the Image
The deployment is the simplest of steps, requiring a single kubectl / oc command.
# Apply the template to deploy the image as a pod
oc apply -f create_sidb_23ai_db001.yaml
# response
singleinstancedatabase.database.oracle.com/sidb-sample created
This message sounds great but to be sure verify that the new pod is created and starts the initialisation process. This will include downloading the container image and applying the setup scripts to stand up the database.
This may take some time, usually 5 minutes from Init to Running and the database services to be Ready.
Monitor the Image Deployment
Use the OpenShift UI to monitor the progress or standard kubectl options such as describe or logs.
Using cli is easy and standard across Kubernetes platforms. First use the get to list all pods or all resources in the namespace.
# Get All Pods in the namespace
oc get pods -n sidb-ns
# response
Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+
NAME READY STATUS RESTARTS AGE
pod/db001-r3qq4 0/1 Init:0/1 0 7s
# Get All Resources in the namespace
oc get all -n sidb-ns
# response once the Pod is running with Get All
Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+
NAME READY STATUS RESTARTS AGE
pod/db001-r3qq4 0/1 Running 0 3m9s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
db001 ClusterIP 172.30.211.151 <none> 1521/TCP 3m9s
db001-ext NodePort 172.30.145.198 <none> 5500:32652/TCP,1521:32193/TCP 3m9s
othing is shown - Time to Troubleshoot!
If nothing is returned, no pods are listed or the status shows Init:CrashLoopBackOff, check the Operator System logs.
If the default YAML was used to install the Operator, then 3 Operator Pods will have been deployed.
# Tail the Operator logs from the Pods oc logs -f -n oracle-database-operator-system \ $(oc get pod -o name -n oracle-database-operator-system|tail -1) # Full output is not shown .... 2025-12-02T10:29:37Z INFO singleinstancedatabase-resource validate create {"name": "db001"} 2025-12-02T10:29:37Z INFO controllers.database.SingleInstanceDatabase Reconcile requested 2025-12-02T10:29:37Z INFO singleinstancedatabase-resource validate update {"name": "db001"} 2025-12-02T10:29:37Z INFO singleinstancedatabase-resource validate create {"name": "db001"} 2025-12-02T10:29:37Z INFO controllers.database.SingleInstanceDatabase Entering reconcile validation 2025-12-02T10:29:37Z INFO controllers.database.SingleInstanceDatabase Completed reconcile validation 2025-12-02T10:29:37Z INFO controllers.database.SingleInstanceDatabase Creating a new PVC {"createPVC Datafiles-Vol": {"name":"db001","namespace":"sidb-ns"}, "PVC.Namespace": "sidb-ns", "PVC.Name": "db001"} 2025-12-02T10:29:37Z INFO No db001 Pod is Ready {"controller": "singleinstancedatabase", "controllerGroup": "database.oracle.com", "controllerKind": "SingleInstanceDatabase", "SingleInstanceDatabase": {"name":"db001","namespace":"sidb-ns"}, "namespace": "sidb-ns", "name": "db001", "reconcileID": "ac6a76bb-31e7-4e70-9ef5-feae6370378b", "FindPods": {"name":"db001","namespace":"sidb-ns"}} 2025-12-02T10:29:37Z INFO db001 Pods Available ( Other Than Ready Pod ) {"controller": "singleinstancedatabase", "controllerGroup": "database.oracle.com", "controllerKind": "SingleInstanceDatabase", "SingleInstanceDatabase": {"name":"db001","namespace":"sidb-ns"}, "namespace": "sidb-ns", "name": "db001", "reconcileID": "ac6a76bb-31e7-4e70-9ef5-feae6370378b", "FindPods": {"name":"db001","namespace":"sidb-ns"}, " Names :": []} 2025-12-02T10:29:37Z INFO Total No Of db001 PODS {"controller": "singleinstancedatabase", "controllerGroup": "database.oracle.com", "controllerKind": "SingleInstanceDatabase", "SingleInstanceDatabase": {"name":"db001","namespace":"sidb-ns"}, "namespace": "sidb-ns", "name": "db001", "reconcileID": "ac6a76bb-31e7-4e70-9ef5-feae6370378b", "FindPods": {"name":"db001","namespace":"sidb-ns"}, "Count": 0} 2025-12-02T10:29:37Z INFO controllers.database.SingleInstanceDatabase Replica Info {"createPods": {"name":"db001","namespace":"sidb-ns"}, "Found": 0, "Required": 1} 2025-12-02T10:29:37Z INFO controllers.database.SingleInstanceDatabase Creating a new db001 POD {"createPods": {"name":"db001","namespace":"sidb-ns"}, "POD.Namespace": "sidb-ns", "POD.Name": "db001-r3qq4"} 2025-12-02T10:29:37Z ERROR controllers.database.SingleInstanceDatabase Failed to create new db001 POD {"createPods": {"name":"db001","namespace":"sidb-ns"}, "pod.Namespace": ....
Hopefully an indication of the root cause will help identify the problem. At this stage, we’ve only completed a few prerequisite tasks, so re-check them before proceeding.
IF(All is Good)
To continue monitoring the pods progress using the describe or viewing the logs. The describe should return even if the pod is initialising but the logs will only return when the pod is Running.
# Using Describe to get Pod details
oc describe -n sidb-ns pod/db001-r3qq4
# response
Name: db001-iyge6
Namespace: sidb-ns
Priority: 0
Service Account: sidb-sa
Node: ocp-oracle-xbvj4-worker-0-kq5g9/192.168.230.202
Start Time: Thu, 04 Dec 2025 10:17:03 +0000
Labels: app=db003
version=
Annotations: k8s.ovn.org/pod-networks:
{"default":{"ip_addresses":["10.128.2.28/23"],"mac_address":"0a:58:0a:80:02:1c","gateway_ips":["10.128.2.1"],"routes":[{"dest":"10.128.0.0...
k8s.v1.cni.cncf.io/network-status:
[{
"name": "ovn-kubernetes",
"interface": "eth0",
"ips": [
"10.128.2.28"
],
"mac": "0a:58:0a:80:02:1c",
"default": true,
"dns": {}
}]
openshift.io/scc: sidb-oracle-user-scc
Status: Running
IP: 10.128.2.28
IPs:
IP: 10.128.2.28
Controlled By: SingleInstanceDatabase/db001
Init Containers:
init-prebuiltdb:
Container ID: cri-o://1f8b03f21098142b3bf12ea331656e046c10ca7d7fae9762dbd246b8043739d4
Image: container-registry.oracle.com/database/free:23.7.0.0
Image ID: container-registry.oracle.com/database/free@sha256:229c2015c60b4ee996bd1643576d189810a4e8d1fde772f80fdc057a2d5deb96
Port: <none>
Host Port: <none>
Command:
/bin/sh
-c
if [ ! -d /mnt/oradata/${ORACLE_SID} -a -d $ORACLE_BASE/oradata/${ORACLE_SID} ]; then cp -v $ORACLE_BASE/oradata/.${ORACLE_SID}$CHECKPOINT_FILE_EXTN /mnt/oradata && cp -vr $ORACLE_BASE/oradata/${ORACLE_SID} /mnt/oradata && cp -vr $ORACLE_BASE/oradata/dbconfig /mnt/oradata; fi
State: Terminated
Reason: Completed
Exit Code: 0
Started: Thu, 04 Dec 2025 10:20:28 +0000
Finished: Thu, 04 Dec 2025 10:20:34 +0000
Ready: True
Restart Count: 0
Environment:
ORACLE_SID: FREE
Mounts:
/mnt/oradata from datafiles-vol (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-frj8w (ro)
Containers:
db001:
Container ID: cri-o://af137efc46e563e49474ee85ba850d863281f1d03f70b683964c654c93808677
Image: container-registry.oracle.com/database/free:23.7.0.0
Image ID: container-registry.oracle.com/database/free@sha256:229c2015c60b4ee996bd1643576d189810a4e8d1fde772f80fdc057a2d5deb96
Ports: 1521/TCP, 5500/TCP
Host Ports: 0/TCP, 0/TCP
State: Running
Started: Thu, 04 Dec 2025 10:20:35 +0000
Ready: True
Restart Count: 0
Readiness: exec [/bin/sh -c if [ -f $ORACLE_BASE/checkDBLockStatus.sh ]; then $ORACLE_BASE/checkDBLockStatus.sh ; else $ORACLE_BASE/checkDBStatus.sh; fi ] delay=20s timeout=20s period=60s #success=1 #failure=3
Environment:
SVC_HOST: db003
SVC_PORT: 1521
ORACLE_CHARACTERSET:
ORACLE_EDITION: free
Mounts:
/opt/oracle/oradata from datafiles-vol (rw)
/run/secrets/oracle_pwd from oracle-pwd-vol (ro,path="oracle_pwd")
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-frj8w (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
datafiles-vol:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: db001
ReadOnly: false
oracle-pwd-vol:
Type: Secret (a volume populated by a Secret)
SecretName: db-admin-secret
Optional: false
tls-secret-vol:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium:
SizeLimit: <unset>
custom-scripts-vol:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium:
SizeLimit: <unset>
kube-api-access-frj8w:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
ConfigMapName: openshift-service-ca.crt
ConfigMapOptional: <nil>
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events: <none>
This shows the deployment details of the pod but not the database state. The operator provides the custom resource definition singleinstancedatabase, along with other definitions, that can be managed.
Viewing the Single Instance Database status
# Get the Status of the single instance database
oc get singleinstancedatabase db001 -n sidb-ns
# response
NAME EDITION STATUS ROLE VERSION CONNECT STR TCPS CONNECT STR OEM EXPRESS URL
db001 Free Healthy PRIMARY 23.7.0.25.01 192.168.230.198:32193/FREE Unavailable Unavailable
The Status progresses during the provisioning, startup, ready or failure states. Healthy is up and Running but to be sure, we can view the pods logs
# View the pod logs
oc logs -f pod/db001-r3qq4
# Snippets of the Response is shown
Starting Oracle Net Listener.
Oracle Net Listener started.
Starting Oracle Database instance FREE.
Oracle Database instance FREE started.
The Oracle base remains unchanged with value /opt/oracle
SQL*Plus: Release 23.0.0.0.0 - Production on Thu Dec 4 10:20:39 2025
Version 23.7.0.25.01
Copyright (c) 1982, 2025, Oracle. All rights reserved.
Connected to:
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.7.0.25.01
SQL>
User altered.
SQL>
User altered.
SQL>
Session altered.
SQL>
User altered.
SQL> Disconnected from Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.7.0.25.01
The Oracle base remains unchanged with value /opt/oracle
#########################
DATABASE IS READY TO USE!
#########################
The following output is now a tail of the alert.log:
...
The log will update as the database is initialised and configured. When the “DATABASE IS READY TO USE!” appears, then it is ready to be connected to by applications and SQL clients.
Of course this is much simpler in the OpenShift Console.
Navigate to Home → Projects
Search for the Project / Namespace Name

Select the project
Navigate to Pods in the Inventory Section


Select the POD
Navigate to the Logs tab

You can also use this to access the pods terminal.
Connecting to the Database Instance
Connecting to a pods running in a Kubernetes cluster are not covered in this post. The pods can be accessed directly, via port forwarding on a jump host or load balancer.
For connectivity using port forwarding or a load balancer, the Cluster IPs and Ports for the services are obtained
# Get Services Info for connections outside of the cluster
oc get services -n sidb-ns
# response
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
db001 ClusterIP 172.30.211.151 <none> 1521/TCP 15m
db001-ext NodePort 172.30.145.198 <none> 5500:32652/TCP,1521:32193/TCP 15m

Connectivity from the same subnet or that has routing to the cluster resources can use a direct connection.
# Get Single Instance Database Info for Direct connections with the same subnet as the POD
oc get singleinstancedatabase db001 -n sidb-ns
# response
NAME EDITION STATUS ROLE VERSION CONNECT STR TCPS CONNECT STR OEM EXPRESS URL
db001 Free Healthy PRIMARY 23.7.0.25.01 192.168.230.198:32193/FREE Unavailable Unavailable
The client I use to connect is in the same subnet, so I opt for the direct connection. Using the Oracle SQL Developer extension in VS Code, I create a connection to the CDB$ROOT and PDB containers (FREE & FREEPDB1 respectively).

You are all set to start you DB & Application Development on Oracle Databases.
Removing an Oracle Single Database Instance
Luckily for those who’ve worked in a Kubernetes or OpenShift environment this step is no different that removing or deleting other deployed resources.
# Using normal oc (kubectl) to delete a resource
## Listing existing resources
oc get all -n sidb-ns
#response
Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+
NAME READY STATUS RESTARTS AGE
pod/db001-37gsz 1/1 Running 0 3d15h
pod/db002-lhwg6 1/1 Running 0 3d15h
pod/db003-2m0jl 1/1 Running 0 3d15h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/db001 ClusterIP 172.30.211.151 <none> 1521/TCP 3d21h
service/db001-ext NodePort 172.30.145.198 <none> 5500:32652/TCP,1521:32193/TCP 3d21h
service/db002 ClusterIP 172.30.190.26 <none> 1521/TCP 7d2h
service/db002-ext NodePort 172.30.24.17 <none> 5500:31356/TCP,1521:30281/TCP 7d2h
service/db003 ClusterIP 172.30.33.212 <none> 1521/TCP 5d2h
service/db003-ext NodePort 172.30.179.29 <none> 5500:32660/TCP,1521:31614/TCP 5d2h
## Listing the single instance databases
oc get singleinstancedatabase -n sidb-ns
# reponse
NAME EDITION STATUS ROLE VERSION CONNECT STR TCPS CONNECT STR OEM EXPRESS URL
db001 Free Healthy PRIMARY 23.7.0.25.01 192.168.230.199:32193/FREE Unavailable Unavailable
db002 Enterprise Healthy PRIMARY 19.26.0.0.0 192.168.230.200:30281/ORCL Unavailable https://192.168.230.199:32652/em
db003 Free Healthy PRIMARY 23.7.0.25.01 192.168.230.199:31614/FREE Unavailable Unavailable
## Deleting the single database instance "db003"
oc delete -f sidb-db003.yaml
# response
singleinstancedatabase.database.oracle.com "db003" deleted
## Listing existing resources
oc get all -n sidb-ns
#response
Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+
NAME READY STATUS RESTARTS AGE
pod/db001-37gsz 1/1 Running 0 3d15h
pod/db002-lhwg6 1/1 Running 0 3d15h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/db001 ClusterIP 172.30.211.151 <none> 1521/TCP 3d21h
service/db001-ext NodePort 172.30.145.198 <none> 5500:32652/TCP,1521:32193/TCP 3d21h
service/db002 ClusterIP 172.30.190.26 <none> 1521/TCP 7d2h
service/db002-ext NodePort 172.30.24.17 <none> 5500:31356/TCP,1521:30281/TCP 7d2h
## Listing the single instance databases
oc get singleinstancedatabase -n sidb-ns
# reponse
NAME EDITION STATUS ROLE VERSION CONNECT STR TCPS CONNECT STR OEM EXPRESS URL
db001 Free Healthy PRIMARY 23.7.0.25.01 192.168.230.199:32193/FREE Unavailable Unavailable
db002 Enterprise Healthy PRIMARY 19.26.0.0.0 192.168.230.200:30281/ORCL Unavailable https://192.168.230.199:32652/em
The Single Instance Database, its services and pod are all removed.
The operator does provide an additional option to clean up instances and associated resources like the pod or services.
# Using the Operator Signle Instance Database CRD operations
## Listing existing resources
oc get all -n sidb-ns
#response
Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+
NAME READY STATUS RESTARTS AGE
pod/db001-37gsz 1/1 Running 0 3d15h
pod/db002-lhwg6 1/1 Running 0 3d15h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/db001 ClusterIP 172.30.211.151 <none> 1521/TCP 3d21h
service/db001-ext NodePort 172.30.145.198 <none> 5500:32652/TCP,1521:32193/TCP 3d21h
service/db002 ClusterIP 172.30.190.26 <none> 1521/TCP 7d2h
service/db002-ext NodePort 172.30.24.17 <none> 5500:31356/TCP,1521:30281/TCP 7d2h
## Listing the single instance databases
oc get singleinstancedatabase -n sidb-ns
# reponse
NAME EDITION STATUS ROLE VERSION CONNECT STR TCPS CONNECT STR OEM EXPRESS URL
db001 Free Healthy PRIMARY 23.7.0.25.01 192.168.230.199:32193/FREE Unavailable Unavailable
db002 Enterprise Healthy PRIMARY 19.26.0.0.0 192.168.230.200:30281/ORCL Unavailable https://192.168.230.199:32652/em
## Deleting the single instance database "db002"
oc delete singleinstancedatabase db002 -n sidb-ns
# response
singleinstancedatabase.database.oracle.com "db002" deleted
## Listing the single instance databases
oc get all -n sidb-ns
# reponse
Warning: apps.openshift.io/v1 DeploymentConfig is deprecated in v4.14+, unavailable in v4.10000+
NAME READY STATUS RESTARTS AGE
pod/db001-37gsz 1/1 Running 0 3d15h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/db001 ClusterIP 172.30.211.151 <none> 1521/TCP 3d21h
service/db001-ext NodePort 172.30.145.198 <none> 5500:32652/TCP,1521:32193/TCP 3d21h
## Listing the single instance databases
oc get singleinstancedatabase -n sidb-ns
# reponse
NAME EDITION STATUS ROLE VERSION CONNECT STR TCPS CONNECT STR OEM EXPRESS URL
db001 Free Healthy PRIMARY 23.7.0.25.01 192.168.230.199:32193/FREE Unavailable Unavailable
Each command option provides the same results and of course this can be completed via the console.

Removing Autonomous Databases
Although not a focus of this post, I just wanted to note that the deletion of Autonomous Databases (ADBs) that bounded to or created in Oracle Cloud Infrastructure (OCI) supports two deletion operations.
Unbind
In this case the ADB remains deployed in OCI
Delete
The hardLink property which defines the behavior when the resource is deleted from the cluster. If the hardLink is set to true, the Operator terminates the Autonomous Database in OCI when the resource is removed; otherwise, the database remains unchanged (same as UNBIND).
Removing the resource can be performed using the oc/kubectl delete and referencing the resource YAM file or the autonomousdatabase.database.oracle.com or for short adb CRD
Samples
# Listing the Bounded Autonomous Databases
## Option 1
kubectl get adbs
NAME DISPLAY NAME DB NAME STATE DEDICATED OCPUS STORAGE (TB) WORKLOAD TYPE CREATED
snapexdb23ai snapexdb23ai snapexdb23ai AVAILABLE false 0 1 OLTP 2024-09-19 08:21:43 UTC
snodbodb23ai snodbodb23ai snodbodb23ai STOPPED false 0 1 OLTP 2025-07-11 08:06:47 UTC
## Option 2
kubectl get autonomousdatabase.database.oracle.com
NAME DISPLAY NAME DB NAME STATE DEDICATED OCPUS STORAGE (TB) WORKLOAD TYPE CREATED
snapexdb23ai snapexdb23ai snapexdb23ai AVAILABLE false 0 1 OLTP 2024-09-19 08:21:43 UTC
snodbodb23ai snodbodb23ai snodbodb23ai STOPPED false 0 1 OLTP 2025-07-11 08:06:47 UTC
## Delete or Unbind the resource fromt he cluster
kubectl delete adb/snodbodb23ai
# response
autonomousdatabase.database.oracle.com/snodbodb23ai deleted
To clean up the ADB instance in OCI please refer to the Delete the resource from the cluster section of the Operator documentation.
Conclusion
As expected the process was straight forward and simple. It did not differ much from other Kubernetes environment with only a few OpenShift caveats.
Using oc vs kubectl was an easy switch and OpenShift provides developer and user enhancements that simply context switching.
I look forward to the day when this operator is available in the cluster’s Operator Hub, which would simplify the deployment even more.
If you are familiar with Kubernetes and/or OpenShift, then this will only be a high level intro to using the Operator to deploy different database options. In future testing, I hope to explore the OCI Database deployments such as Autonomous provisioning.
All of the Operator operations are supported but if any issues arise issues can be posted to the GitHub repository. So far, so good, nothing to report except for a minor typo in the documentation.
Are you thinking about deploying containerised Oracle Databases for Development or Testing on OpenShift?
If so, what has your experience been like?



