Skip to main content
Version: Next

Oracle Database Operator for Kubernetes

The Oracle Database Operator for Kubernetes (OraOperator, or simply the operator) extends the Kubernetes API with custom resources and controllers to automate Oracle Database lifecycle management.

Full Documentation.

Learn about using the OraOperator in the Livelab Microservices and Kubernetes for an Oracle DBA

Installing the Oracle Database Operator for Kubernetes

Oracle Database Operator for Kubernetes will be installed if the oracle-database-operator.enabled is set to true in the values.yaml file. The default namespace for Oracle Database Operator is oracle-database-operator-system.

Deploy ORDS with the Oracle Database Operator

Use the OrdsSrvs custom resource to deploy Oracle REST Data Services (ORDS) into an OBaaS namespace.

Prerequisites

Before you create the ORDS resource, confirm that:

  • Oracle Database Operator is installed.
  • The ordssrvs.database.oracle.com custom resource exists.
  • The OBaaS namespace exists.
  • The database administrator Secret exists.
  • The database connection details are known.
kubectl get crd ordssrvs.database.oracle.com
kubectl get secret <db-admin-secret> -n <application-namespace>

Create a Secret for the ORDS runtime database user password:

read -r -s ORDS_RUNTIME_PASSWORD
printf '%s' "${ORDS_RUNTIME_PASSWORD}" | kubectl -n <application-namespace> create secret generic <ords-runtime-secret> \
--from-file=password=/dev/stdin
unset ORDS_RUNTIME_PASSWORD

Database connection settings

Use the connection settings that match the OBaaS database type.

OBaaS database typeORDS connection typeRequired connection details
ADB-StnsADB wallet Secret and TNS alias
SIDB-FREEbasicIn-cluster database service, port 1521, service FREEPDB1
OTHERbasic or customurlExternal host, port, service name, or JDBC URL

Create the ORDS resource

Create a file named ords.yaml.

apiVersion: database.oracle.com/v4
kind: OrdsSrvs
metadata:
name: <ords-resource-name>
namespace: <application-namespace>
spec:
image: container-registry.oracle.com/database/ords:25.1.0
imagePullPolicy: IfNotPresent
workloadType: Deployment
replicas: 1
globalSettings:
standalone.context.path: /ords
standalone.http.port: 8080
standalone.https.port: 8443
security.forceHTTPS: true
database.api.enabled: true
poolSettings:
- poolName: <pool-name>

# Add the database connection settings for ADB-S, SIDB-FREE, or OTHER here.

db.username: ORDS_PUBLIC_USER_OPER
db.secret:
secretName: <ords-runtime-secret>
passwordKey: password
db.adminUser: <ADMIN-or-SYSTEM>
db.adminUser.secret:
secretName: <db-admin-secret>
passwordKey: password

restEnabledSql.active: true
feature.sdw: true
plsql.gateway.mode: proxied
jdbc.InitialLimit: 2
jdbc.MinLimit: 2
jdbc.MaxLimit: 10

For ADB-S, add:

db.connectionType: tns
db.tnsAliasName: <tns-alias>
tnsAdminSecret:
secretName: <adb-wallet-secret>

For SIDB-FREE, add:

db.connectionType: basic
db.hostname: <db-service-name>
db.port: 1521
db.servicename: FREEPDB1

You can find the in-cluster database service with:

kubectl get svc -n <application-namespace> -l app.kubernetes.io/component=database

For OTHER, add:

db.connectionType: basic
db.hostname: <db-host>
db.port: <db-port>
db.servicename: <db-service-name>

If the database requires a JDBC URL, use:

db.connectionType: customurl
db.customURL: <jdbc-url>

Apply and verify

Validate the resource before applying it:

kubectl apply --dry-run=server -f ords.yaml
kubectl apply -f ords.yaml

Check the ORDS resource, pods, and service:

kubectl get ordssrvs <ords-resource-name> -n <application-namespace>
kubectl get pods,svc -n <application-namespace> -l app=<ords-resource-name>

Test the ORDS endpoint locally:

kubectl -n <application-namespace> port-forward service/<ords-resource-name> 18443:8443
curl -k -i https://localhost:18443/ords/<pool-name>/_/db-api/stable/

Optional: Route ORDS through APISIX

You can keep ORDS internal and access it with kubectl port-forward, as shown above. Only create an APISIX route when you want ORDS reachable through the OBaaS APISIX gateway.

If your APISIX gateway is exposed outside the cluster, this route can make ORDS reachable from that same network path. Review your gateway, hostname, TLS, and access-control configuration before using this option in a shared or production environment.

The examples below use these service name patterns:

ServiceName
APISIX admin API<app-release>-apisix-admin
APISIX gateway<app-release>-apisix-gateway
ORDS<ords-resource-name>
SigNoz OpenTelemetry collector aliassignoz-otel-collector

Confirm the services exist:

kubectl get svc -n <application-namespace> \
<app-release>-apisix-admin \
<app-release>-apisix-gateway \
<ords-resource-name> \
signoz-otel-collector

Confirm that APISIX has the OpenTelemetry plugin enabled:

kubectl -n <application-namespace> get configmap <app-release>-apisix -o yaml \
| yq '.data."config.yaml"' \
| yq '.plugins[]' \
| grep opentelemetry

Open a local tunnel to the APISIX admin API:

kubectl -n <application-namespace> port-forward service/<app-release>-apisix-admin 9180:9180

In another terminal, retrieve the APISIX admin key:

admin_key=$(
kubectl -n <application-namespace> get configmap <app-release>-apisix -o yaml \
| yq '.data."config.yaml"' \
| yq '.deployment.admin.admin_key[] | select(.name == "admin") | .key'
)

Configure or verify APISIX OpenTelemetry plugin metadata:

The OBaaS chart enables the APISIX opentelemetry plugin and configures the SigNoz collector service. APISIX also requires runtime plugin metadata before route-level traces are emitted. If plugin_metadata/opentelemetry is already configured, you can skip this command.

curl -i http://127.0.0.1:9180/apisix/admin/plugin_metadata/opentelemetry \
-H "X-API-KEY: ${admin_key}" \
-X PUT \
-d '{
"trace_id_source": "random",
"resource": {
"service.name": "APISIX"
},
"collector": {
"address": "http://signoz-otel-collector:4318",
"request_timeout": 3
},
"batch_span_processor": {
"drop_on_queue_full": false,
"max_queue_size": 1024,
"batch_timeout": 2,
"inactive_timeout": 1,
"max_export_batch_size": 16
},
"set_ngx_var": false
}'

Create the ORDS route:

curl -i http://127.0.0.1:9180/apisix/admin/routes/<ords-resource-name> \
-H "X-API-KEY: ${admin_key}" \
-X PUT \
-d '{
"name": "<ords-resource-name>",
"uri": "/ords/*",
"methods": ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
"plugins": {
"opentelemetry": {
"sampler": {
"name": "always_on"
}
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "rewrite",
"upstream_host": "localhost",
"tls": {
"verify": false
},
"nodes": {
"<ords-resource-name>.<application-namespace>.svc.cluster.local:8443": 1
}
}
}'

The route uses the ORDS HTTPS port, 8443. The generated ORDS certificate uses localhost, so the APISIX upstream sets upstream_host to localhost and disables upstream certificate verification.

For a local test of the optional APISIX route, open a tunnel to the APISIX gateway:

kubectl -n <application-namespace> port-forward service/<app-release>-apisix-gateway 18080:80

Test the ORDS endpoint through APISIX:

curl -i \
-H "x-request-id: ords-apisix-test-001" \
http://localhost:18080/ords/<pool-name>/_/db-api/stable/

Check the APISIX route:

curl -s http://127.0.0.1:9180/apisix/admin/routes/<ords-resource-name> \
-H "X-API-KEY: ${admin_key}"

In SigNoz, look for traces with service name APISIX. The APISIX span should include http.route=/ords/*, apisix.route_id=<ords-resource-name>, and apisix.route_name=<ords-resource-name>.