<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Kuassi Mensah on Medium]]></title>
        <description><![CDATA[Stories by Kuassi Mensah on Medium]]></description>
        <link>https://medium.com/@kuassimensah?source=rss-66c52e475e23------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*79EdabZGCY89az5A.</url>
            <title>Stories by Kuassi Mensah on Medium</title>
            <link>https://medium.com/@kuassimensah?source=rss-66c52e475e23------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 18:13:55 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@kuassimensah/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Oracle Database Operator for Kubernetes v2.0.0]]></title>
            <link>https://kuassimensah.medium.com/oracle-database-operator-for-kubernetes-v2-0-0-99481155b5f5?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/99481155b5f5</guid>
            <category><![CDATA[oracle-database]]></category>
            <category><![CDATA[openshift]]></category>
            <category><![CDATA[kubernetes-operator]]></category>
            <category><![CDATA[oraclecloudinfrastructure]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Fri, 14 Nov 2025 16:43:16 GMT</pubDate>
            <atom:updated>2025-11-14T16:43:16.583Z</atom:updated>
            <content:encoded><![CDATA[<h4>Making the Oracle Database Truly Kubernetes-Native</h4><p>Authors: <a href="https://medium.com/u/66c52e475e23?source=post_page---user_mention--b1f4e7eeb667---------------------------------------">Kuassi Mensah</a> — <a href="https://medium.com/u/04aa52d2bd9e?source=post_page---user_mention--b1f4e7eeb667---------------------------------------">Paramdeep Saini</a>— Sanjay.Singh</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O24F8375H9qPpwiSD_bUtQ.png" /></figure><p>The journey to making enterprise databases truly Kubernetes-native just took a significant leap forward. Oracle has released version 2.0.0 of the Oracle Database Operator for Kubernetes (a.k.a. OraOperator), bringing enterprise-grade database management into the cloud-native era with enhanced automation, expanded platform support, and powerful new features.</p><h3>Lifecycle Automation at Scale</h3><p>OraOperator v2.0.0 automates complex database operations that traditionally required manual intervention:</p><ul><li><strong>Provisioning and cloning</strong> across multiple database types</li><li><strong>In-place and out-of-place patching</strong> for seamless updates</li><li><strong>Backup and restore operations</strong> with long-term backup support</li><li><strong>Scaling operations</strong> for both compute and storage resources</li><li><strong>Data Guard configuration</strong> and switchover operations</li></ul><h3>What Makes This Release Special?</h3><p>Version 2.0.0 represents a major milestone in Oracle’s commitment to Kubernetes-native database operations.</p><h4>Red Hat OpenShift Partner Validation: Enterprise Ready</h4><p>One of the most significant additions is full validation of Red Hat OpenShift. OraOperator and its controllers have been validated and included in the <a href="https://catalog.redhat.com/en/software/container-stacks/detail/68c4502d45d3fc6d301a9980">Red Hat Operators Catalog</a>, making it easier than ever for enterprises running OpenShift to deploy and manage Oracle databases with confidence.</p><p>The <a href="https://container-registry.oracle.com/ords/ocr/ba/database">Oracle Container Images (OCR)</a> are available for deployment on Red Hat OpenShift, including: <a href="https://container-registry.oracle.com/ords/ocr/ba/database/free">Oracle AI Database 26ai Free</a>, <a href="https://container-registry.oracle.com/ords/ocr/ba/database/enterprise_ru">SIDB 19.28</a>, GDD(GSM) 26ai Free, and <a href="https://container-registry.oracle.com/ords/ocr/ba/database/rac_ru">Oracle Restart Database 19.28</a>.</p><h4>Oracle Restart Controller: Enhanced Infrastructure Management</h4><p>The new Restart Controller enables dynamic infrastructure management, such as provisioning, adding, and deleting ASM disks, bringing advanced storage automation to Kubernetes-managed databases and supporting deployments with GI and ASM. <br>When storage is added or removed using Kubernetes Persistent Volume Claims (PVCs), Oracle Restart and ASM automatically handle these changes.</p><h4>Broader Integration with Private Cloud Appliance (PCA)</h4><p>The Database Operator for Kubernetes add-on on the Oracle Kubernetes Engine (OKE) now supports Oracle Private Cloud Appliance (PCA) with platform release 3.12 and is available through the OKE console with Database Operator V1.2. Additionally, Database Operator V2.0 offers on-demand updates, with planned integration in the next platform release 3.13, enhancing deployment flexibility and supporting a wider range of Oracle environments.</p><h4>ORDS Services Enhancements</h4><p>The enhanced Oracle REST Data Services (ORDS) support now includes:</p><ul><li>Service Account integration with OpenShift support</li><li>Compatibility with ORDS image 25.1 and above</li><li>Flexible APEX installation: provide files via download URL or persistent volume, addressing the need for missing installation files</li></ul><h4>True Cache Support</h4><p>Preview support for True Cache with Free SIDB databases brings Oracle’s high-performance caching to Kubernetes deployments.</p><h4>Expanded Database and Platform Support</h4><p>Version 2.0.0 supports an impressive range of Oracle database configurations:</p><ul><li>Autonomous Database (ADB-S and ADB-D): Includes manual failover and switchover</li><li>Oracle Database 26ai: Full support, including Free and Free-lite editions</li><li>Globally Distributed Databases 26ai: Manage sharded topologies and Raft replication</li><li>Multitenant: Improved PDB management via a new LRES-based controller, enhanced config map support, and deletion policy control</li></ul><h4>Broad Kubernetes Platform Support</h4><p>This production release has been thoroughly tested across the Kubernetes ecosystem:</p><ul><li>Oracle Container Engine for Kubernetes (OKE)</li><li>RedHat OpenShift (v4.16+)</li><li>Oracle Linux Cloud Native Environment (OLCNE)</li><li>Google Kubernetes Engine (GKE)</li><li>Azure Kubernetes Service (AKS)</li><li>Amazon Elastic Kubernetes Service (EKS)</li><li>Minikube (for development)</li></ul><p>Also:</p><ul><li>Operator Lifecycle Manager (OLM) support</li><li>Upgraded Kubernetes API (v4) for enhanced compatibility</li></ul><h3>High Availability, Observability, and Integrations</h3><h4><strong>Data Guard Enhancements</strong></h4><p>Includes an Observer for FastStartFailover and Snapshot Standby, raising high availability for databases in containers.</p><h4><strong>Database Observability</strong></h4><p>Native support for database logs and metrics through the latest exporter container images enables seamless integration with Kubernetes monitoring stacks such as Prometheus and Grafana.</p><h4>Enterprise Cloud Integrations</h4><p>Added deployment support for Database Operator on OKE console for Private Cloud Appliance (PCA) and Compute Cloud@Customer (C3) for true hybrid cloud operations.</p><h3>Getting Started</h3><p><em>Ready to make your Oracle databases Kubernetes-native?</em></p><p>The OraOperator v2.0.0 is available via:</p><ul><li><a href="https://github.com/oracle/oracle-database-operator">GitHub</a></li><li><a href="https://container-registry.oracle.com/ords/f?p=113:10::::::">Oracle Container Registry</a></li><li><a href="https://operatorhub.io/">Operatorhub.io</a></li><li>Red Hat Operators Catalog (upon final approval)</li></ul><h3>The Bottom Line</h3><p>Oracle Database Operator for Kubernetes v2.0.0 represents a mature, production-ready solution for running Oracle databases in Kubernetes. Whether you’re managing a single containerized database or orchestrating a globally distributed database topology, OraOperator brings the power of declarative configuration and Kubernetes automation to Oracle Database operations.</p><p>For organizations committed to Kubernetes as their application platform, v2.0.0 removes the traditional barriers between stateful database workloads and cloud-native infrastructure. The result is faster deployments, simplified operations, and the ability to manage databases using the same tools and patterns as your applications.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=99481155b5f5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Database CI/CD with the Oracle Database Operator for Kubernetes, GitHub Actions, and Liquibase —…]]></title>
            <link>https://kuassimensah.medium.com/database-ci-cd-with-the-oracle-database-operator-for-kubernetes-github-actions-and-liquibase-cb42ec5f8697?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/cb42ec5f8697</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[oracle-cloud]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[oracle-database]]></category>
            <category><![CDATA[github-actions]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Wed, 29 Oct 2025 11:01:54 GMT</pubDate>
            <atom:updated>2025-10-29T12:23:58.711Z</atom:updated>
            <content:encoded><![CDATA[<h3>Database CI/CD with the Oracle Database Operator for Kubernetes, GitHub Actions, and Liquibase — Take 2</h3><h4>How We Automated Database Provisioning from Days to Minutes (And the Problems We Solved Along the Way)</h4><p><a href="https://medium.com/@kuassimensah?source=post_page---byline--e0227ca7b7c3---------------------------------------">Kuassi Mensah</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*OZaUrTT9hu_GIBisku_LPA.png" /></figure><p>“Can you provision a database for my feature branch?”</p><p>This simple request used to trigger a 2–3 day process: create a ticket, wait for the DBA team to pick it up, manual database creation, configuration, connection details sent back, inevitably something is misconfigured, back to the DBA team…</p><p>By the time the database was ready, the developer had moved on to something else, context was lost, and momentum was dead.</p><p>We decided to fix this. What started as a simple automation project became a deep dive into Kubernetes internals, authentication patterns, and the challenges of managing stateful applications in cloud-native environments.</p><p>This is the story of that implementation — the problems we faced, the solutions we found, and the lessons we learned. <br>I presented this with a live workflow at the recent Oracle AI World in Las Vegas. See <a href="https://reg.rf.oracle.com/flow/oracle/ocw25/catalog/page/catalog/session/1748631907900001E115">my slides</a>.</p><h3>The Problem: Development Database Bottleneck</h3><p>Our development workflow was broken. We had three teams working on different features of our application, all needing their own database environments for testing. But our infrastructure couldn’t keep up:</p><p><strong>For Developers:</strong></p><ul><li>Shared development database meant constant conflicts — your schema change broke someone else’s work</li><li>Manual provisioning took days, killing momentum</li><li>No two development environments were configured the same way</li><li>“Works on my machine” problems were constant</li></ul><p><strong>For DBAs:</strong></p><ul><li>Managing 15+ manual database requests per week</li><li>Tracking which database belongs to which feature in spreadsheets</li><li>Forgotten test databases are consuming cloud resources and budget</li><li>No standardization — every database was a snowflake</li></ul><p><strong>For the Business:</strong></p><ul><li>Features are taking 20–30% longer due to infrastructure delays</li><li>Monthly cloud bills included $5,000 in orphaned test databases</li><li>Production issues from schema changes that weren’t properly tested</li><li>Developer frustration leading to retention concerns</li></ul><p>We needed a better way.</p><h3>The Vision: Database-as-Code</h3><p>The initial implementation was performed by <a href="https://medium.com/@npaberin/database-ci-cd-with-the-oracle-db-operator-for-kubernetes-github-actions-and-liquibase-6dd161940a68">Norman Aberin’s work</a>; we envisioned a simple workflow:</p><ol><li>The developer creates a feature branch: feature/user-authentication</li><li>Developer pushes code</li><li><strong>Magic happens</strong></li><li>15 minutes later, they have a fully configured Oracle database with schemas deployed</li><li>A developer works on their feature with an isolated database</li><li>The developer deletes the branch</li><li>The database automatically cleans up</li></ol><p>No tickets. No waiting. No manual intervention.</p><p>Infrastructure-as-Code, but for databases.</p><h3>The Architecture</h3><p>Here’s what you can achieve (I’ve only implemented a test-db feature branch)</p><figure><img alt="Architecture diagram showing GitHub → GitHub Actions → OKE Cluster with namespaces" src="https://cdn-images-1.medium.com/proxy/1*d9LhkQ9DXM_PKG_F7DpC0g.png" /><figcaption><strong><em>Architecture diagram showing GitHub → GitHub Actions → OKE Cluster with namespaces</em></strong></figcaption></figure><p><strong>Key Components:</strong></p><ul><li><strong>Oracle Kubernetes Engine (OKE)</strong>: Our container orchestration platform</li><li><strong>Oracle Database Operator</strong>: Manages the database lifecycle as a Kubernetes resource</li><li><strong>GitHub Actions</strong>: Orchestrates the entire workflow</li><li><strong>Kustomize</strong>: Handles configuration management</li><li><strong>Liquibase</strong>: Manages schema versioning and deployment</li></ul><p>Each feature branch gets its own namespace in the Kubernetes cluster, complete with an isolated Oracle database instance.</p><p>The flow looks like this:</p><pre>GitHub Repository (feature branches)<br>           ↓<br>    GitHub Actions (triggered on push)<br>           ↓<br>    OKE Cluster<br>      ├─ Namespace: feature-user-auth<br>      │    ├─ Oracle Database Pod<br>      │    ├─ LoadBalancer Service<br>      │    └─ Persistent Volume<br>      └─ Namespace: feature-payment-system<br>           ├─ Oracle Database Pod<br>           ├─ LoadBalancer Service<br>           └─ Persistent Volume</pre><h3>The Journey: Four Major Challenges</h3><p>What seemed straightforward in theory hit reality hard. Here are the four major technical challenges we faced and how we solved them.</p><h4>Challenge 1: Authentication Hell</h4><p><em>The Problem</em></p><p>We needed GitHub Actions to authenticate with our OKE cluster. Oracle provides a GitHub Action (oracle-actions/configure-kubectl-oke) that&#39;s supposed to handle this. We followed the documentation, configured our secrets, ran the workflow, and...</p><pre>Error: Authentication failed<br>The required information to complete authentication <br>was not provided or was incorrect.</pre><p>We spent three days trying different combinations of credentials, regions, and configuration options. The error messages were generic and unhelpful.</p><p><em>The Investigation</em></p><p>OCI authentication uses a private key and a fingerprint of that key’s public component. The Oracle action expected us to provide the fingerprint as a GitHub secret. But we kept getting mismatches — the fingerprint we stored didn’t match what the actual key generated.</p><p>Then the breakthrough: <strong>What if we don’t store the fingerprint at all? What if we generate it from the private key at runtime?</strong></p><p><em>The Solution</em></p><pre>- name: Setup OCI CLI and Configure kubectl<br>  run: |<br>    # Install OCI CLI<br>    bash -c &quot;$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)&quot; -- --accept-all-defaults<br>    export PATH=&quot;$HOME/bin:$PATH&quot;<br>    <br>    # Create private key from GitHub secret<br>    mkdir -p ~/.oci<br>    echo &quot;${{ secrets.OCI_KEY_FILE }}&quot; &gt; ~/.oci/key.pem<br>    chmod 600 ~/.oci/key.pem<br>    <br>    # Generate fingerprint from actual key (not from secret!)<br>    FINGERPRINT=$(openssl rsa -pubout -outform DER \<br>      -in ~/.oci/key.pem 2&gt;/dev/null | \<br>      openssl md5 -c | awk -F&#39;= &#39; &#39;{print $2}&#39;)<br>    <br>    # Create OCI config with generated fingerprint<br>    cat &gt; ~/.oci/config &lt;&lt; EOF<br>    [DEFAULT]<br>    user=${{ secrets.OCI_USER_OCID }}<br>    fingerprint=${FINGERPRINT}<br>    tenancy=${{ secrets.OCI_TENANCY_OCID }}<br>    region=${{ secrets.OCI_REGION }}<br>    key_file=$HOME/.oci/key.pem<br>    EOF<br>    <br>    # Configure kubectl<br>    $HOME/bin/oci ce cluster create-kubeconfig \<br>      --cluster-id ${{ secrets.OKE_CLUSTER_OCID }} \<br>      --file ~/.kube/config \<br>      --region &#39;${{ secrets.OCI_REGION }}&#39; \<br>      --token-version 2.0.0</pre><p><em>Key Insight</em></p><p><strong>Store only what you must. Generate what you can.</strong></p><p>The fingerprint is derived from the key, so derive it at runtime. This guarantees they match because they come from the same source.</p><p><strong>Impact:</strong> Authentication went from 0% success rate to 100%.</p><h4>Challenge 2: The Kustomize Naming Nightmare</h4><p><em>The Problem</em></p><p>We had a base database configuration named freedb-lite-sample. We wanted to add the branch name as a suffix, so for the branchtest-db, we&#39;d get db-test-db. Simple, right?</p><p>We used Kustomize’s namesuffix feature:</p><pre>kustomize edit set namesuffix test-db</pre><p><strong>The result?</strong> freedb-lite-sampletest-db</p><p>Kustomize appended the suffix directly to the existing name. Our monitoring scripts were looking for db-test-db, but the database was actually named freedb-lite-sampletest-db.</p><p>We spent hours debugging “database not found” errors when the database was right there — just with the wrong name.</p><p><em>The Solution</em></p><p>We switched namesuffix to <strong>JSON patches</strong>, which give complete control:</p><pre>cat &gt; kustomization.yaml &lt;&lt; EOF<br>apiVersion: kustomize.config.k8s.io/v1beta1<br>kind: Kustomization</pre><pre>namespace: feature-test-db</pre><pre>resources:<br>  - base/sidb-free-lite</pre><pre>patches:<br>  - patch: |-<br>      - op: replace<br>        path: /metadata/name<br>        value: db-test-db<br>    target:<br>      kind: SingleInstanceDatabase<br>EOF</pre><p>The patch says: “Find the SingleInstanceDatabase resource and replace its metadata name with <strong>exactly</strong> this value.&quot; No ambiguity, full control.</p><p><em>Lesson Learned</em></p><p>Kustomize’s convenience features are great for simple cases, but for precise control, JSON patches are worth the extra verbosity.</p><h4>Challenge 3: Namespaces That Won’t Die</h4><p><em>The Problem</em></p><p>This was perhaps the most frustrating issue. We’d run our delete workflow to clean up an old database. The workflow completed successfully. But when we tried to create a new database with the same name:</p><pre>Error from server (AlreadyExists): object is being deleted: <br>namespaces &quot;feature-test-db&quot; already exists</pre><p>The namespace was stuck in the “Terminating” state. For hours. <strong>In one case, over 6 hours.</strong></p><p>Kubernetes was trying to delete the namespace, but couldn’t because resources inside it had <strong>“finalizers”</strong> — cleanup handlers that must complete before deletion. The SingleInstanceDatabase custom resource had a finalizer for proper database shutdown. Something was preventing that finalizer from completing, so the namespace was stuck in limbo forever.</p><p>Developers couldn’t create new databases because the namespace name was technically “taken” even though nothing was actually running.</p><p><em>The Investigation</em></p><p>When I examined the namespace status, I found:</p><pre>&quot;message&quot;: &quot;Some content in the namespace has finalizers remaining: <br>database.oracle.com/singleinstancedatabasefinalizer in 1 resource instances&quot;</pre><p>The database resource was blocking namespace deletion. But the database pod was long gone. The finalizer was waiting for something that would never happen.</p><h3>The Solution</h3><p>We had to force the issue by removing finalizers:</p><pre>- name: Force delete stuck namespace and resources<br>  run: |<br>    NAMESPACE=&quot;feature-${{ steps.getname.outputs.idname }}&quot;<br>    <br>    if kubectl get namespace $NAMESPACE 2&gt;/dev/null | grep -q Terminating; then<br>      echo &quot;Namespace stuck, removing resources...&quot;<br>      <br>      # Remove finalizers from database resources first<br>      for db in $(kubectl get singleinstancedatabase -n $NAMESPACE -o name); do<br>        kubectl patch $db -n $NAMESPACE \<br>          -p &#39;{&quot;metadata&quot;:{&quot;finalizers&quot;:[]}}&#39; --type=merge<br>      done<br>      <br>      # Remove finalizers from namespace<br>      kubectl patch namespace $NAMESPACE \<br>        -p &#39;{&quot;metadata&quot;:{&quot;finalizers&quot;:[]}}&#39; --type=merge<br>      <br>      # Force delete if still exists<br>      sleep 15<br>      kubectl delete namespace $NAMESPACE --force --grace-period=0<br>    fi</pre><p>We run this check before creating a new namespace. If an old one is stuck, we forcibly remove the finalizers and delete it.</p><p><em>Lessons Learned</em></p><p><strong>Kubernetes finalizers are powerful for ensuring proper cleanup, but they can create deadlocks.</strong></p><p>Always have a force-cleanup mechanism for production workflows. Custom Resource Definitions are especially prone to this issue.</p><p><strong>Impact:</strong> Workflow success rate went from ~60% (blocked by stuck namespaces) to 95%+.</p><h4>Challenge 4: The Connectivity Conundrum</h4><p><em>The Problem</em></p><p>Database created successfully. Pod running. Everything looked perfect in the Kubernetes dashboard. But when Liquibase tried to connect from GitHub Actions:</p><pre>ORA-12541: Cannot connect. No listener at host 10.0.10.10 port 30328<br>nc: connect to 10.0.10.10 port 30328 (tcp) failed: Connection timed out</pre><p>We verified credentials. Checked firewall rules. Tested from different networks. Nothing worked.</p><p>Then I realized: <strong>10.0.10.10 is an internal Kubernetes IP (ClusterIP)</strong>. It&#39;s only accessible from inside the cluster. GitHub Actions runs on GitHub&#39;s infrastructure, completely outside our cluster. They&#39;re in different networks with no connectivity.</p><p><em>The Root Cause</em></p><p>The Oracle Database Operator created a ClusterIP service by default:</p><pre>apiVersion: v1<br>kind: Service<br>metadata:<br>  name: db-service<br>spec:<br>  type: ClusterIP  # Internal only!<br>  clusterIP: 10.0.10.10<br>  ports:<br>  - port: 1521</pre><p>ClusterIP is perfect for pod-to-pod communication within the cluster. But it’s invisible to the outside world.</p><p><em>The Solution</em></p><p>We needed to expose the database externally via a <strong>LoadBalancer</strong>:</p><pre>- name: Expose database externally<br>  run: |<br>    kubectl apply -f - &lt;&lt;EOF<br>    apiVersion: v1<br>    kind: Service<br>    metadata:<br>      name: db-external<br>      namespace: feature-test-db<br>    spec:<br>      type: LoadBalancer<br>      selector:<br>        app: db-test-db<br>      ports:<br>      - port: 1521<br>        targetPort: 1521<br>    EOF<br>    <br>    # Wait for external IP<br>    kubectl wait --for=jsonpath=&#39;{.status.loadBalancer.ingress[0].ip}&#39; \<br>      service/db-external --timeout=300s</pre><p>In Oracle Cloud, the LoadBalancer service automatically provisions an OCI Load Balancer with a public IP address. The flow becomes:</p><pre>Liquibase (GitHub Actions) <br>  → External IP (OCI Load Balancer) <br>  → ClusterIP (Kubernetes Service) <br>  → Database Pod</pre><p>We wait for the external IP assignment (takes 2–3 minutes) before proceeding with Liquibase.</p><p><em>Lessons Learned</em></p><p><strong>Kubernetes networking has layers.</strong> ClusterIP is internal-only, NodePort exposes on node IPs, and LoadBalancer gets a cloud provider’s load balancer. Choose based on your access patterns.</p><p><strong>Security Note:</strong> For production, you’d restrict access to this LoadBalancer (IP allowlists, VPN, etc.). For temporary development databases with non-sensitive data, external access is acceptable.</p><p><strong>Alternative Approach:</strong> We’re considering running Liquibase as a Kubernetes Job inside the cluster for future iterations. This would keep the database internal-only and eliminate the need for external exposure.</p><h3>Real World Performance</h3><p>Here’s what a typical execution looks like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/612/1*KmBt8U7DYlY_Th4nLLFhyA.png" /><figcaption><strong><em>Workflow execution timeline or screenshot from GitHub Actions</em></strong></figcaption></figure><h3>What you get:</h3><ul><li>1 Oracle Database instance (19c or 21c)</li><li>1 Kubernetes namespace (isolated)</li><li>3+ application schemas (fully deployed)</li><li>1 external IP for connectivity</li><li>Automatic cleanup on branch deletion</li></ul><p><strong>Compare this to our previous process: a minimum of 2–3 days.</strong></p><h3>The Impact</h3><h4>Quantitative Results</h4><p><strong>Before:</strong></p><ul><li>Average database provisioning time: <strong>2–3 days</strong></li><li>Monthly orphaned database costs: <strong>~$5,000</strong></li><li>Developer satisfaction score (infrastructure): <strong>4.2/10</strong></li><li>Features delayed by database availability: <strong>20–30%</strong></li></ul><p><strong>After:</strong></p><ul><li>Average database provisioning time: <strong>15–20 minutes</strong> (99.5% reduction)</li><li>Monthly orphaned database costs: <strong>~$200</strong> (96% reduction)</li><li>Developer satisfaction score (infrastructure): <strong>8.7/10</strong></li><li>Features delayed by database availability: <strong>&lt;2%</strong></li></ul><h4>Qualitative Benefits</h4><p><strong>Developers:</strong></p><blockquote><em>“I can experiment freely without worrying about breaking someone else’s work”</em></blockquote><blockquote><em>“Testing schema changes is so much easier now”</em></blockquote><blockquote><em>“I love that I can just push code and come back to a ready database”</em></blockquote><p><strong>DBAs:</strong></p><blockquote><em>“I’ve gone from managing 15+ manual requests per week to zero”</em></blockquote><blockquote><em>“Everything is standardized now — I know exactly how every database is configured”</em></blockquote><blockquote><em>“The automatic cleanup is amazing for cost control”</em></blockquote><p><strong>Project Managers:</strong></p><blockquote><em>“Features are shipping faster”</em></blockquote><blockquote><em>“Our cloud bill dropped significantly”</em></blockquote><blockquote><em>“Developers are happier, which helps with retention”</em></blockquote><h3>Lessons Learned</h3><h4>1. Authentication: Store Less, Generate More</h4><p>Don’t store credentials you can derive. We went from storing five pieces of authentication data to storing two (private key and region), generating everything else at runtime. This reduced secret management complexity and eliminated mismatch errors.</p><h4>2. Kubernetes: Plan for Finalizers</h4><p>Custom Resource Definitions often have finalizers. In a perfect world, they clean up gracefully. In reality, they can deadlock. Always have force-cleanup mechanisms for production workflows.</p><h4>3. Networking: Internal vs External Matters</h4><p>ClusterIP vs LoadBalancer isn’t just about exposure — it fundamentally changes who can access your services. Understand your access patterns before choosing service types.</p><h4>4. Debugging: Add Observability Early</h4><p>Every step in our workflow now echoes what it’s doing and the results. When something fails at 2 AM, these logs are invaluable. Don’t wait for production failures to add debugging.</p><h4>5. Automation: Perfect is the Enemy of Done</h4><p>Our first version worked for 60% of cases. We shipped it, learned from failures, and iterated. Waiting for perfection would have meant developers still waiting days for databases.</p><h3>Future Improvements</h3><p>We’re not done. Here’s what we’re planning:</p><p><strong>Security:</strong></p><ul><li>Run Liquibase as a Kubernetes Job (keep databases internal)</li><li>Add network policies (restrict database access to specific pods)</li><li>Migrate from GitHub Secrets to OCI Vault (better secret management)</li><li>Implement TLS/SSL for database connections</li></ul><p><strong>Operations:</strong></p><ul><li>Automated backups before schema changes</li><li>Prometheus metrics for database health</li><li>Cost tracking by feature branch</li><li>Slack notifications for deployment status</li></ul><p><strong>Developer Experience:</strong></p><ul><li>Database seeding with realistic test data</li><li>Schema diff tool (compare feature branch to main)</li><li>Direct kubectl access for troubleshooting</li><li>Rollback capability for schema changes</li></ul><h3>Tools and Resources</h3><p>This implementation wouldn’t have been possible without standing on the shoulders of others:</p><p><strong>Core Technologies:</strong></p><ul><li><a href="https://github.com/oracle/oracle-database-operator">Oracle Database Operator for Kubernetes</a></li><li><a href="https://www.oracle.com/cloud/compute/container-engine-kubernetes.html">Oracle Kubernetes Engine (OKE)</a></li><li><a href="https://docs.github.com/en/actions">GitHub Actions</a></li><li><a href="https://www.liquibase.org/">Liquibase</a></li><li><a href="https://kustomize.io/">Kustomize</a></li></ul><p><strong>Inspiration:</strong></p><ul><li><a href="https://medium.com/@npaberin/database-ci-cd-with-the-oracle-db-operator-for-kubernetes-github-actions-and-liquibase-6dd161940a68">Norman Aberin’s blog post</a> provided the initial architecture and approach</li></ul><p><strong>Documentation &amp; Community:</strong></p><ul><li>Oracle Cloud Infrastructure documentation</li><li>Kubernetes documentation (especially on finalizers and service types)</li><li>Stack Overflow for specific troubleshooting</li><li>Claude AI for debugging strategies and troubleshooting guidance</li></ul><h3>Try It Yourself</h3><p>Want to implement this in your environment? Here’s where to start:</p><p><a href="https://github.com/Kuassim/AiWorld">GitHub - Kuassim/AiWorld: Oracle AI WOrld demo</a></p><ol><li><strong>Set up an OKE cluster</strong> with the Oracle Database Operator installed</li><li><strong>Configure GitHub secrets</strong> for OCI authentication</li><li><strong>Create base database configuration</strong> using Oracle DB Operator manifests</li><li><strong>Implement the create workflow,</strong> starting with authentication</li><li><strong>Add Kustomize</strong> for configuration management</li><li><strong>Integrate Liquibase</strong> for schema deployment</li><li><strong>Build the delete workflow</strong> for cleanup</li></ol><p>Start simple. Get authentication working first. Then add one piece at a time. Each challenge we faced taught us something valuable about the technology stack.</p><h3>Conclusion</h3><p>From 2–3 days to 15–20 minutes. From manual spreadsheet tracking to automated GitOps. From $5,000 in wasted resources to $200. From frustrated developers to delighted ones.</p><p>But more than the metrics, what we built is a <strong>culture shift</strong>. Databases are no longer special snowflakes that require manual care. They’re infrastructure-as-code, just like everything else in our cloud-native stack.</p><p>Every developer on our team can now provision a database with a git push. They can experiment freely, test thoroughly, and ship confidently. The database is no longer a bottleneck — it&#39;s an enabler.</p><p><strong>That’s the real value of automation: not just time saved, but possibilities created.</strong></p><p><strong>Have you implemented similar database automation in your environment? What challenges did you face? I’d love to hear your experiences in the comments.</strong></p><p><strong>Tags:</strong> #Kubernetes #DevOps #Oracle #GitHubActions #DatabaseAutomation #CloudNative #InfrastructureAsCode #OCI #Liquibase #Kustomize</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cb42ec5f8697" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Oracle Database Operator for Kubernetes on Google Cloud]]></title>
            <link>https://medium.com/oracledevs/oracle-database-operator-for-kubernetes-on-google-cloud-b1f4e7eeb667?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/b1f4e7eeb667</guid>
            <category><![CDATA[google-cloud-platform]]></category>
            <category><![CDATA[oracle-database-23ai]]></category>
            <category><![CDATA[oraclecloudinfrastructure]]></category>
            <category><![CDATA[kubernetes-operator]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Tue, 18 Mar 2025 19:22:51 GMT</pubDate>
            <atom:updated>2025-03-18T19:22:51.004Z</atom:updated>
            <content:encoded><![CDATA[<p>Authors: <a href="https://medium.com/u/66c52e475e23">Kuassi Mensah</a>— <a href="https://medium.com/u/b6640383863c">Jyoti Prakash Verma</a> — <a href="https://medium.com/u/04aa52d2bd9e">Paramdeep Saini</a> — <a href="https://medium.com/u/172cf47c325c">Yunus-Qureshi</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/974/1*qA13_ImfSKciBQXntLr5_Q.png" /><figcaption>OraOperator on GKE</figcaption></figure><p>As part of Oracle’s Multi-Cloud partnership with third-party Clouds, including Azure, GCP, and AWS, this blog post describes the steps for installing the Oracle Database Operator for Kubernetes (a.k.a. OraOperator) on the Google Kubernetes Engine (GKE) and provisioning a Single Instance Database (a.k.a. SIDB).</p><h3>Prerequisites — Create a GKE Cluster</h3><p>You first need to create a Google Kubernetes Engine (GKE) cluster. The Google Cloud Platform (GCP) offers two modes for provisioning GKE:</p><ol><li>The Autopilot mode, allows you to focus on your services and applications, while GKE manages your nodes and infrastructure. We did not perform our tests using this mode.</li><li>The standard mode lets you control the configuration of the individual nodes.</li></ol><p>For our validation of OraOperator on GKE, we created a single node cluster in standard mode, using the Google Cloud Console.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*X5xDT4WMCoMJ2D4HacKr5g.png" /></figure><p>Alternatively, you may use t<a href="https://github.com/javiercanadillas/oracle-operator-on-gke/blob/main/oopgke.bash">his script</a> by the Google folks to create the same cluster.</p><pre>./oopgke.bash step1_create_infra</pre><p>Then use the following links to configure your client machine for accessing the GKE cluster using <em>kubectl</em></p><ol><li><a href="https://cloud.google.com/sdk/docs/install#linux">Install <em>gcloud</em> CLI</a></li><li><a href="https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl#install_plugin">Install <em>gcloud</em> plugin to access GKE using kubectl</a></li></ol><p>At this stage, you have a 1-node GKE cluster installed and your client has been configured to access it using <em>kubectl.</em></p><pre>kubectl get nodes -o wide</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/963/1*SBgniAiwMCNrIqXHQVCa6Q.png" /></figure><p>The next steps, which consist of installing OraOperatore and provisioning a Single Instance Database, are business as usual, i.e., similar for all CNCF-compliant Kubernetes engines.</p><h4>Install OraOperator on GKE</h4><ol><li><strong>Install the certificate manager using the following command</strong></li></ol><pre>kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.2/cert-manager.yaml</pre><p><strong>2. Namespace deployment</strong></p><p>To reduce the scope of OraOperator deployment and monitoring to the default namespace, as opposed to a cluster-wide deployment, you need to grant <em>service account with resource access</em> to the default namespace, using the following command</p><pre>kubectl apply -f rbac/default-ns-role-binding.yaml<br></pre><p>3. Edit the <a href="https://github.com/oracle/oracle-database-operator/blob/main/oracle-database-operator.yaml">oracle-database-operator.yaml</a> to add the default namespace under WATCH_NAMESPACE then save it.</p><pre>- name: WATCH_NAMESPACE<br>  value: &quot;default&quot;</pre><p>4. Finally, apply the just saved y<em>aml</em> file using the following command; this will install/deploy OraOperator.</p><pre>kubectl apply -f oracle-database-operator.yaml</pre><p>5. Check that the operator is up and running using the following command</p><p>For a wide view use the following command:</p><pre>$ kubectl get all -n oracle-database-operator-system -o wide</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f0jMKvjBuNhCjzN6GS9Snw.png" /></figure><p>For a narrow view, use the following command:</p><pre>$ kubectl get pods -n oracle-database-operator-system</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/922/1*gQYuZhpqSXDvBkMSKy6TZA.png" /></figure><h3>Provisioning a Single Instance Database (SIDB)</h3><p>A single-instance database has a one-to-one relationship between the database server instance (memory and processes) and the database itself (i.e., the database files). It is the most basic deployment option of the Oracle Database.</p><h4>Ensure Sufficient Disk Space in the Kubernetes Worker Node</h4><p>The SIDB container images are stored on the Kubernetes worker node. These images can be as large as 10 GB therefore, you need to ensure the K8s nodes have enough free space</p><h4>Resource Privileges</h4><p>The SIDB controller needs the following Kubernetes privileges.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fc87d2acb68ede280cd738a31311f84a/href">https://medium.com/media/fc87d2acb68ede280cd738a31311f84a/href</a></iframe><p>The controller automatically acquires these privileges from the cluster, you need not take any action. Additional optional Kubernetes resource privileges may also be specified (see the <a href="https://github.com/oracle/oracle-database-operator/tree/main/docs/sidb">OraOperator SIDB doc</a> for more details).</p><h4>Prepare the Oracle Container Image</h4><p>The supported Oracle Database releases include Enterprise and Standard Editions for Oracle Database 19c and later, Express Edition for Oracle Database 21.3.0 only, Oracle Database Free 23.6.0 and later, and Oracle Database Free lite 23.6 and later.</p><p>You can build a SIDB image from the source by following <a href="https://github.com/oracle/docker-images/tree/main/OracleDatabase/SingleInstance">these instructions</a> or, better, use the pre-built images available <a href="https://container-registry.oracle.com/ords/ocr/ba/database/enterprise_ru">here</a> (for the Enterprise edition) and <a href="https://container-registry.oracle.com/ords/ocr/ba/database/free">here</a> (for the Free edition).<br>You need to sign in and accept the required license agreement if you have not already done so.</p><p>To pull the image from the Oracle Container Registry, you need to create a Kubernetes secret (named <em>oracle-container-registry-secret</em> for example) as follows:</p><pre>$ kubectl create secret docker-registry oracle-container-registry-secret --docker-server=container-registry.oracle.com --docker-username=&#39;&lt;oracle-sso-email-address&gt;&#39; --docker-password=&#39;&lt;container-registry-auth-token&gt;&#39; --docker-email=&#39;&lt;oracle-sso-email-address&gt;&#39;</pre><p>Alternatively, use the docker config.json or podman auth.json (after successfully logging in).</p><pre>$ docker login container-registry.oracle.com<br>$ kubectl create secret generic oracle-container-registry-secret  --from-file=.dockerconfigjson=.docker/config.json --type=kubernetes.io/dockerconfigjson</pre><p>or</p><pre>$ podman login container-registry.oracle.com<br>$ kubectl create secret generic oracle-container-registry-secret  --from-file=.dockerconfigjson=${XDG_RUNTIME_DIR}/containers/auth.json --type=kubernetes.io/dockerconfigjson</pre><p>Edit the <em>## Database image details</em> section of the <a href="https://github.com/oracle/oracle-database-operator/blob/main/config/samples/sidb/singleinstancedatabase_create.yaml"><strong>singleinstancedatabase_create.yaml</strong></a> file as follows:</p><pre>## Database image details<br>image:<br>  pullFrom: container-registry.oracle.com/database/enterprise_ru:21.17.0.0<br>  pullSecrets: oracle-container-registry-secret</pre><h4><strong>Set Up Volumes for Database Persistence</strong></h4><p>Volumes are required for the persistent storage of the database files. There are two options: dynamic persistence or static persistence.</p><ul><li>Dynamic Persistence: in this mode, a persistent volume is provisioned by mentioning a Cloud infrastructure-specific storage class in the <a href="https://github.com/oracle/oracle-database-operator/blob/main/config/samples/sidb/singleinstancedatabase_create.yaml"><strong>singleinstancedatabase_create.yaml</strong></a> file. The supported access mode for this class is ReadWriteOnce.The Reclaim Policy of such dynamically provisioned volumes is Deletei.e., meaning that the volumes are deleted when their corresponding database deployment is deleted.</li><li>Static Persistence: in this mode, you must create a volume manually, and then use the name of this volume with the &lt;.spec.persistence.datafilesVolumeName&gt; field, which corresponds to the datafilesVolumeName field of the persistence section in the <a href="https://github.com/oracle/oracle-database-operator/blob/main/config/samples/sidb/singleinstancedatabase_create.yaml"><strong>singleinstancedatabase_create.yaml</strong></a> file.</li></ul><p>For this validation test, we will use the dynamic persistence option. Let’s get details of the available storage classes in GCP using the following command:</p><pre>$ kubectl get sc</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cxH9_uXZGN1moIQHrUn8qg.png" /></figure><p>We will use “<em>standard-rwo”, </em>the default storage class.</p><h4>Kubernetes Secret</h4><p>The following command creates a Kubernetes secret named “db-admin-secret” (for <em>SYS, SYSTEM, and SYSADMIN</em> users), with the oracle_pwd key mapped to the actual password specified in the command.</p><pre>$ kubectl create secret generic db-admin-secret --from-literal=oracle_pwd=&lt;specify password here&gt;</pre><p>Note: theadminPassword field in the singleinstancedatabase.yaml file refers to that secret.</p><p>Check the successful creation of the secret using the following command:</p><pre>$ kubectl get secret -n default</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/799/1*yW6D5tb5NT61nXtEkGXL8A.png" /></figure><h4>Provision the SIDB</h4><p>Edit the <a href="https://github.com/oracle/oracle-database-operator/blob/main/config/samples/sidb/singleinstancedatabase_create.yaml"><strong>singleinstancedatabase_create.yaml</strong></a><strong> </strong>file and replace: <br><em>storageClass: “oci-bv” </em>by <em>“standard-rwo”</em></p><p>Save then apply the just edited file, using</p><pre>$ kubectl apply -f singleinstancedatabase_create.yaml</pre><p>Wait for the creation notification <em>singleinstancedatabase.database.oracle.com/sidb-sample created</em></p><p>After the creation, the SIDB needs to be deployed, which takes a few minutes. You can monitor the progress of the provisioning in the log file using the following command:</p><pre>$ kubectl logs -f  pod/sidb-sample-8hmw7</pre><p>The verbose output is not displayed here however, the following message will indicate the completion of the deployment.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/450/1*cpTWEA8X4MlAFH_g3zS3Ew.png" /></figure><p>Get the status of the deployment using the following command (the status should be “<em>Running</em>”):</p><pre>$ kubectl get all -o wide</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1016/1*m5vKvc7fW37_Ekd2hDgTKQ.png" /></figure><p>Get a summary of the deployed SIDB as follows:</p><pre>$ kubectl get singleinstancedatabase sidb-sample -n default</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mNnZpM_R1CL78sA4ZMygFQ.png" /></figure><p>Get more details as follows</p><pre>$ kubectl describe singleinstancedatabase sidb-sample -n default</pre><p>Output not shown, too verbose and lengthy!</p><p>Confirm that the database is healthy</p><pre>$ kubectl get singleinstancedatabase sidb-sample -o &quot;jsonpath={.status.status}&quot;</pre><p>Healthy</p><p>Get the CDB connect string</p><pre>$ kubectl get singleinstancedatabase sidb-sample -o &quot;jsonpath={.status.connectString}&quot;</pre><p>34.70.98.61:31625/ORCL1</p><p>Get the PDB connect string</p><pre>$ kubectl get singleinstancedatabase sidb-sample -o &quot;jsonpath={.status.pdbConnectString}&quot;</pre><p>34.70.98.61:31625/ORCLPDB1</p><h4>Configuring a FrontEnd Load Balancer</h4><p>By default, external connections from outside the K8s cluster to the database are performed through the NodePort service (30000-32767 range) however, in Cloud environments, the best practice is to front-end the SIDB with a load balancer. Configuring it is as simple as setting the <em>loadBalancer</em> attribute to <em>true</em> in the <a href="https://github.com/oracle/oracle-database-operator/blob/main/config/samples/sidb/singleinstancedatabase_create.yaml"><strong>singleinstancedatabase_create.</strong>yaml</a> file as follows.</p><pre>loadBalancer: true</pre><p>Alternatively, use the <em>kubectl patch</em> command as follows:</p><pre>$ kubectl --type=merge -p &#39;{&quot;spec&quot;:{&quot;loadBalancer&quot;: true}}&#39; patch singleinstancedatabase sidb-sample</pre><p>After a few minutes, the load balancer will be provisioned, and an external IP will be assigned.</p><pre>$ kubectl get all</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/940/1*oAxohtXYHL2geMH56v3Z7g.png" /></figure><h4>Secure TCPS Connection</h4><p>To increase security, you can configure the <em>tcpsListenerPort</em> service thereby restricting external communications to the SIDB through the TCPs listener (or TCPs endpoint).</p><pre>$ kubectl patch --type=merge singleinstancedatabases.database.oracle.com sidb-sample -p &#39;{&quot;spec&quot;: {&quot;enableTCPS&quot;: true}}&#39;</pre><p>After a few minutes, the service will be enabled and confirmed using the following commands (checking the status)</p><pre>$ kubectl get singleinstancedatabase sidb-sample -o &quot;jsonpath={.status.isTcpsEnabled}&quot;</pre><p>When TCPS is enabled, a self-signed certificate is generated and stored in a wallet under/opt/oracle/oradata/clientWallet/$ORACLE_SID in the pod.</p><h4>Regular Connections</h4><p>At this stage, you can connect to the database using the connect strings returned by the commands above. You may use any supported client or the good old <em>Sqlplus</em> command line interface:</p><pre>$ sqlplus sys/&lt;.spec.adminPassword&gt;@34.70.98.61:316/ORCL1 as sysdba</pre><h4>TCPS Connections</h4><p>Copy the generated wallet directory onto a client machine, under “<em>wallet_dir</em>” (for example), using the following commands (from the client machine)</p><pre>$ mkdir wallet_dir<br>$ kubectl cp $(kubectl get pods -l app=sidb-sample -o=jsonpath=&#39;{.items[0].metadata.name}&#39;):/opt/oracle/oradata/clientWallet/ORCL1 ./wallet_dir</pre><p>The wallet dir includes several files such astnsnames.ora and sqlnet.ora files.</p><pre>$ ls wallet_dir<br>cwallet.sso  cwallet.sso.lck  ewallet.p12  ewallet.p12.lck  sqlnet.ora  tnsnames.ora</pre><p>The <em>tnsnames.ora</em> file has short TNS aliases for connecting to the database (instead of using the lengthy full descriptor). The <em>TNS_ADMIN</em> environment variable refers to the location of the <em>tnsnames.ora</em> file.</p><pre>$ cd wallet_dir<br>$ export TNS_ADMIN=$(pwd)<br>$ sqlplus sys@ORCL1 as sysdba</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/795/1*mqh0NmKr57HVhSlflycukw.png" /></figure><p>This is it!</p><h4>Clean Up</h4><p>Housekeeping!</p><p>Run the following commands to delete all the CRD instances, APIService, RBAC, and deployments in the default namespace.</p><pre>$ kubectl delete singleinstancedatabase.database.oracle.com --all -n default</pre><pre>$ cat rbac/* | kubectl delete -f -</pre><pre>$ kubectl delete -f oracle-database-operator.yaml --ignore-not-found=true</pre><h3>Further Readings</h3><ul><li>The <a href="https://github.com/oracle/oracle-database-operator/tree/main/docs/sidb">SIDB documentation</a>.</li><li>The <a href="https://github.com/oracle/oracle-database-operator/">Oracle Database Operator for Kubernetes</a>.</li><li>Google’s “<a href="https://github.com/javiercanadillas/oracle-operator-on-gke">Deploying the Oracle Operator on GKE</a>” was a source, published prior to this blog post.</li></ul><h3>Thank you!</h3><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b1f4e7eeb667" width="1" height="1" alt=""><hr><p><a href="https://medium.com/oracledevs/oracle-database-operator-for-kubernetes-on-google-cloud-b1f4e7eeb667">Oracle Database Operator for Kubernetes on Google Cloud</a> was originally published in <a href="https://medium.com/oracledevs">Oracle Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[UCP Best Practices for Oracle Database 19c and Spring Boot]]></title>
            <link>https://medium.com/oracledevs/ucp-best-practices-for-oracle-database-19c-and-spring-boot-fb837f8e195b?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/fb837f8e195b</guid>
            <category><![CDATA[jdbc]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[high-availability]]></category>
            <category><![CDATA[oracle-database]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Mon, 17 Jun 2024 18:45:09 GMT</pubDate>
            <atom:updated>2024-06-17T18:45:09.292Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://medium.com/u/4ee7e5343ded?source=post_page-----4d6723621c0b--------------------------------">Irina Granat</a> — <a href="https://medium.com/u/012927bd8266?source=post_page-----4d6723621c0b--------------------------------">Richard Exley</a> — <a href="https://medium.com/u/66c52e475e23?source=post_page-----4d6723621c0b--------------------------------">Kuassi Mensah</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*3T79mHXJ0qwRNTFK" /><figcaption>Photo by <a href="https://unsplash.com/@dhalseth?utm_source=medium&amp;utm_medium=referral">Daniel Halseth</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Learn how to configure the Universal Connection Pool (UCP) to leverage the Oracle Databases’ High Availability (HA) capabilities for continuous service during planned and unplanned downtime.</p><p>All the recommendations have been tested using the latest Long Term Support (LTS) Oracle Database release, i.e., 19c (19.21).</p><h3>About UCP</h3><p>Oracle Database furnishes the Universal Connection Pool (UCP), a feature-rich Java connection pool—one of the Spring Boot choices—that supports all Oracle database configurations and mission-critical capabilities (availability, scalability, and load balancing), out-of-the-box, including Oracle Real Application Cluster (RAC), Data Guard, Oracle Sharding, Asynchronous API, Runtime Load Balancing, XA, and front-end to Database Resident Connection Pool (DRCP).</p><p>UCP is released quarterly and fully supported by Oracle.</p><p>See more details @ <a href="https://www.oracle.com/jdbc/">https://www.oracle.com/jdbc/</a>.</p><h3>The Basics</h3><p>With Spring Boot v2.4.0 and later, configuring UCP is easier and does not require any extra code. Spring identifies UCP as a data source like any other from the <strong><em>application.properties</em> </strong>file. Spring retrieves the configuration from the <strong><em>application.properties</em></strong> file and autowires (injects) the values to the datasource.</p><p>The basic steps for using the UCP pool with the Oracle Database are (1) configuring the Oracle JDBC driver and (2) configuring UCP.</p><h4>Configuring the Oracle JDBC Driver</h4><p>Add Oracle JDBC driver as a dependency in Spring Initializer or manually add it to your project <strong><em>pom.xml</em></strong> file:</p><pre>&lt;properties&gt;<br>    &lt;oracle.jdbc.version&gt;19.21.0.0&lt;/&lt;oracle.jdbc.version&gt;<br>&lt;/properties&gt;<br><br>&lt;dependencies&gt;<br>...<br>&lt;dependency&gt;<br>    &lt;groupId&gt;com.oracle.database.jdbc&lt;/groupId&gt;<br>    &lt;artifactId&gt;ojdbc8&lt;/artifactId&gt;<br>    &lt;version&gt;${oracle.jdbc.version}&lt;/version&gt;<br>&lt;/dependency&gt;<br>...<br>&lt;/dependencies&gt;</pre><p>Check out this <a href="https://www.oracle.com/database/technologies/faq-jdbc.html">page</a> for more information on Oracle RDBMS and JDK Version Compatibility for Oracle JDBC Drivers.</p><h4>Configuring UCP</h4><p>Pull the latest UCP release by adding the following dependency to your project <strong><em>pom.xml</em></strong> file:</p><pre>&lt;dependencies&gt;<br>...<br>&lt;dependency&gt;<br>&lt;groupid&gt;com.oracle.database.jdbc&lt;/groupId&gt;<br>    &lt;artifactId&gt;ucp&lt;/artifactId&gt;<br>&lt;/dependency&gt;<br>...<br>&lt;/dependencies&gt;</pre><p>Then, add the following properties to the <strong><em>application.properties</em></strong> file. Here is an example of the <strong><em>application.properties</em></strong> file with the minimum set of properties required for using the Oracle database:</p><pre>#Oracle Database DataSource Configuration<br>spring.datasource.url=${JDBC_URL}<br>spring.datasource.username=${DB_USER}<br>spring.datasource.password=${DB_PASSWORD}<br><br>#UCP Settings<br>spring.datasource.type=oracle.ucp.jdbc.PoolDataSource<br>spring.datasource.oracleucp.connection-factory-class-name=oracle.jdbc.pool.OracleDataSource<br>spring.datasource.oracleucp.initial-pool-size=4<br>spring.datasource.oracleucp.min-pool-size=4<br>spring.datasource.oracleucp.max-pool-size=4</pre><p>The next sections cover the steps for configuring UCP to leverage Oracle Databases’ high availability capabilities.</p><h3>Oracle Database High Availability</h3><p>With the Oracle Real Application Cluster system (RAC), any Oracle database service is accessible equally from several server nodes. If a node or a subset of the RAC cluster fails or is taken offline for maintenance, the database is still accessible through the remaining active nodes.</p><p>The building blocks for implementing Application High Availability with the Oracle database are: (1) using <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/haovw/configuring-continuous-availability-applicationsconfiguring-continuous-availability-applicati.html#GUID-5EBF37EA-48AB-4508-A14E-86A2583A24BF">a database service</a>, (2) configuring a URL or a connection string for High Availability, (3) enabling Fast Application Notification (FAN), (4) implementing draining and enabling continuous database availability for Java applications.<br>You may choose the HA protection level that suits your requirements. A detailed explanation of HA protection levels can be found in Oracle’s “<a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/haovw/configuring-continuous-availability-applicationsconfiguring-continuous-availability-applicati.html#GUID-5EBF37EA-48AB-4508-A14E-86A2583A24BF">High Availability Overview and Best Practices</a>” under the Application High Availability Levels chapter.</p><p>The following steps allow you to configure the Oracle RAC system, the Oracle JDBC driver, and Oracle UCP to sustain planned and unplanned outages. Oracle’s “High Availability Overview and Best Practices” documentation covers the detailed steps and explanations for maintaining your applications&#39; continuous availability.</p><h3>Configuring for Basic High Availability — Level 1</h3><p>This HA level furnishes fast dead connection detection thereby allowing applications to immediately react to instance, node, or database failures and quickly establish new connections to surviving database instances. With this level, downtime is minimized for both unplanned and planned outages.</p><p>The steps for implementing High Availability Level 1 are:</p><ol><li>Configure High Availability Database Services</li><li>Setup the Connect String for High Availability</li><li>Enable Fast Application Notification</li></ol><h4>Configuring High Availability Database Services</h4><p>Create a dedicated service to support HA features as follows.</p><pre>$ srvctl add service -db mydb -service MYSERVICE -pdb mypdb<br>-notification TRUE</pre><h4>Setting Up the Connection String for High Availability</h4><p>Use the connect string shown here to connect to the dedicated database service, created above.</p><pre>jdbc:oracle:thin:@(DESCRIPTION =<br>  (CONNECT_TIMEOUT= 3)(RETRY_COUNT=4)(RETRY_DELAY=2)<br>  (TRANSPORT_CONNECT_TIMEOUT=3) (ADDRESS_LIST = (LOAD_BALANCE=on)<br>  (ADDRESS = (PROTOCOL = TCP)(HOST=clu_site_scan)(PORT=1521)))<br>  (CONNECT_DATA=(SERVICE_NAME = my_service)))</pre><h4>Enabling Fast Application Notification (FAN)</h4><p>FAN is a high-availability notification mechanism that allows an active transaction to be immediately terminated when an instance or server fails. FAN is auto-configured and is enabled out of the box; no application code changes. FAN uses Oracle Clusterware’s Oracle Notification Service (ONS) to receive events from the cluster. ONS requires some ports to be available between the client and the servers.</p><p>The database uses the URL specified above to auto-configure FAN on the client side. To enable Fast Application Notification (FAN), add <strong><em>ons jar </em></strong>file to your project’s <strong><em>pom.xml </em></strong>file.</p><pre>&lt;dependencies&gt;<br>...<br>&lt;dependency&gt;<br>&lt;groupid&gt;com.oracle.database.ha&lt;/groupId&gt;<br>    &lt;artifactId&gt;ons&lt;/artifactId&gt;<br>    &lt;version&gt;${oracle.jdbc.version}&lt;/version&gt;<br>&lt;/dependency&gt;<br>...<br>&lt;/dependencies&gt;</pre><h4>Configuring HA Level 1 for Spring</h4><p>Configure the Oracle database and UCP in your project’s <strong><em>application.properties</em></strong> file as follows.</p><pre>#Oracle Database DataSource Configuration<br>spring.datasource.url=${JDBC_URL}<br>spring.datasource.username=${DB_USER}<br>spring.datasource.password=${DB_PASSWORD}<br><br>#UCP Settings<br>spring.datasource.type=oracle.ucp.jdbc.PoolDataSource<br>spring.datasource.oracleucp.connection-factory-class-name=oracle.jdbc.pool.OracleDataSource<br>spring.datasource.oracleucp.fast-connection-failover-enabled=true<br>spring.datasource.oracleucp.initial-pool-size=4<br>spring.datasource.oracleucp.min-pool-size=4<br>spring.datasource.oracleucp.max-pool-size=4<br>spring.datasource.oracleucp.validate-connection-on-borrow=false</pre><p>You may notice that we’ve added <strong><em>spring.datasource.oracleucp.validate-connection-on-borrow=false</em></strong> to disable connection validation. For more details on connection validation, see the section titled Session Validation of this blog.</p><p>At this stage, the basic High Availability has been configured for Level 1. If your application has been designed to handle planned and unplanned outages via retry logic, you don’t need anything else.</p><p>Next, we will walk you through HA Level 2 and Level 3 which furnish the following benefits:</p><ol><li>FAN event notification of unplanned connection failures. This is especially useful when the failure may have resulted in an application hang, such as when a database node fails, and the TCP/IP sockets are not cleaned up.</li><li>A connection string that results in connection requests being load-balanced across multiple RAC nodes using Single Client Access Name (SCAN) with retry on failure.</li></ol><h3>Configuring for High-Availability — Level 2</h3><p>Building on application HA Level 1, Level 2 adds session draining for minimal application impact during planned maintenance. You can use planned operations to relocate, stop services, or switch over, allowing for graceful completion of the users’ work.</p><p>UCP responds to FAN events and takes immediate action, either balancing connections or establishing new connections and routing work to the available database instances or where the service was started. When a DOWN event (Reason = User) occurs, connections to the databases scheduled for maintenance will be cleaned up gracefully. When a UP event occurs (i.e., new instance up), FAN informs the connection pool that the new instance is available, allowing sessions to be created on this instance.</p><h4>Performing Planned Maintenance</h4><p>Draining database sessions is the safest way to migrate work without interrupting applications. The following command initiates the draining of active sessions.<br>The <em>drain_timeout 60 parameter allows active sessions to finish their requests within a predefined timeout (60 seconds</em>).</p><pre>srvctl stop instance -db mydb -node node1 -stopoption immediate<br>drain_timeout 60 -force -failover</pre><h4>Planned Outage Success Test</h4><p>For the planned outage test, we will be using a two-node Oracle RAC environment. During normal operation, both RAC nodes are up and running and serving the application. Depending on your load-balancing strategy, the number of sessions might be different or equally distributed across both nodes. Under load (i.e., database activities), observe that the connections <strong>drain away</strong> from that instance and that the instance/node can be shut down.</p><p>We will monitor the draining process using the following SQL statement :</p><pre>select systimestamp time, machine, inst_id, count(*) from v$session where username=&#39;XXXX&#39; group by systimestamp, machine, inst_id;</pre><p>In our test run, we perform the following steps:</p><ul><li>Start the applications — app1 and app2 against nodes db1 and db 2.</li><li>Run the workload.</li><li>Drain the instance on node db1.</li><li>Monitor the draining.</li><li>Shut down the applications.</li></ul><p>During normal operation, both RAC nodes <em>db1</em> and <em>db</em>2 (inst_id 1 and inst_id2) are up and running. The following SQL output demonstrates how sessions for app1 and app2 are being distributed (count * column). Each application is using a connection pool that is configured to hold 4 sessions.</p><pre>SQL&gt;<br>TIME                                MACHINE     INST_ID   COUNT(*)<br>----------------------------------- --------- ---------- ----------<br>17-MAY-24 08.47.55.092067 PM +00:00 app1         1    1<br>17-MAY-24 08.47.55.092067 PM +00:00 app1         2    3<br>17-MAY-24 08.47.55.092067 PM +00:00 app2         2    1<br>17-MAY-24 08.47.55.092067 PM +00:00 app2         1    3</pre><p>To begin the planned maintenance test, we first stop the database services on node 1 using the following command:</p><pre>srvctl stop instance -db $(srvctl config database) -node db1 -stopoption immediate -drain_timeout 10 -force -failover</pre><p>Fast Application Notification (FAN) sends a STOP event. The connection pool reacts to FAN and starts closing connections on node 1. At the same time, new connections are being opened on node 2. The active session on node 1 is still executing its work. If it finishes within the drain timeout (10 sec) and returns the connection to the pool, then the session is closed and a new one is established on node 2 when requested.</p><pre>SQL&gt;<br>TIME                                MACHINE    INST_ID   COUNT(*)<br>----------------------------------- --------- ---------- ----------<br>17-MAY-24 08.47.58.090673 PM +00:00 app2        2        3<br>17-MAY-24 08.47.58.090673 PM +00:00 app2        1        1<br>17-MAY-24 08.47.58.090673 PM +00:00 app1        2        4</pre><p>If the drain timeout kicks in but some sessions are still connected to node 1, these will be disconnected. With Application Continuity in place, the sessions reconnect to node 2, and the interrupted work will be replayed transparently to the end user. See the next section for replay configuration details.</p><pre>SQL&gt;<br>TIME                                MACHINE     INST_ID   COUNT(*)<br>----------------------------------- --------- ---------- ----------<br>17-MAY-24 08.48.08.111763 PM +00:00 app1         2    4<br>17-MAY-24 08.48.08.111763 PM +00:00 app2         2    4</pre><h3>Configuring for High Availability — Level 3</h3><p>For planned maintenance (Level 2), draining allows active sessions to finish their work (drain) before the database instance is shut down. However, in the case of unplanned events such as an instance, node, or database service failure, all sessions belonging to the faulty node/instance will be terminated immediately, with no time for draining. The Fast Application Notification (FAN) mechanism will detect those unplanned events and notify the UCP that has been instrumented to receive and process the FAN messages.</p><p>The primary difference between unplanned (Level 3) and planned shutdown (Level 2) scenarios is how borrowed connections are handled. In the unplanned shutdown scenario, stale connections idle in the pool (i.e., not borrowed) are removed.</p><p>Starting with Oracle Database19c, Transparent Application Continuity (TAC) automatically tracks and records the session and transactional states to recover and rebuild the database session and its states following recoverable errors (i.e., node, server, outages; SQL exceptions requiring application or database schema changes are classified as unrecoverable errors). TAC protects your work without application knowledge or code changes.</p><p>To configure TAC, perform the following steps: (1) add extra failover parameters to the database service definition and (2) add a replay data source to the <strong><em>application.properties </em></strong>file.</p><p>1. Add the following parameters to the database service definition</p><ul><li><strong><em>-failovertype AUTO </em></strong>— enables Transparent Application Continuity (TAC).</li><li><strong><em>-failover_restore AUTO</em></strong> — restores client states automatically</li><li><strong><em>-replay_init_time 600</em></strong> — specifies the time in seconds when the replay will not be performed.</li></ul><pre>srvctl stop instance -db $(srvctl config database) -node db1 -stopoption immediate -drain_timeout 10 -force -failover AUTO -failover_restore AUTO -replay_init_time 600</pre><p>2. Add the replay data source <strong><em>spring.datasource.oracleucp.connection-factory-class-name=oracle.jdbc.replay.OracleDataSourceImpl </em></strong>to enable continuous service during unplanned outages to your <strong><em>application.properties </em></strong>file.</p><pre>#Oracle Database DataSource Configuration<br>spring.datasource.url=${JDBC_URL}<br>spring.datasource.username=${DB_USER}<br>spring.datasource.password=${DB_PASSWORD}<br><br>#UCP Settings<br>spring.datasource.type=oracle.ucp.jdbc.PoolDataSource<br>spring.datasource.oracleucp.connection-factory-class-name=oracle.jdbc.replay.OracleDataSourceImpl<br>spring.datasource.oracleucp.fast-connection-failover-enabled=true<br>spring.datasource.oracleucp.initial-pool-size=4<br>spring.datasource.oracleucp.min-pool-size=4<br>spring.datasource.oracleucp.max-pool-size=4<br>spring.datasource.oracleucp.validate-connection-on-borrow=false</pre><h3>Session Validation</h3><p>Connection validation on borrow in 19c UCP is configured by enabling or disabling <strong><em>spring.datasource.oracleucp.validate-connection-on-borrow </em></strong>property in the <strong><em>application.properties</em> </strong>file.</p><ul><li>If <strong><em>spring.datasource.oracleucp.validate-connection-on-borrow is </em></strong>set to false, no connection validation is performed.</li><li>If <strong><em>spring.datasource.oracleucp.validate-connection-on-borrow </em></strong>set to true, the level of validation is controlled by the <strong><em>oracle.jdbc.defaultConnectionValidation</em></strong> connection property (see more details in the next paragraph). The connection validation will be performed on every borrow unless the <strong><em>setSecondsToTrustIdleConnection()</em></strong> method specifies a positive value (in seconds), in which case, validation will only be performed if a connection has not been used for that period.</li></ul><p>The connection property <strong><em>oracle.jdbc.defaultConnectionValidation</em></strong> controls what <strong><em>connection.isValid()</em></strong> method call does under the covers. This connection property specifies the level of connection validation. The possible values for this property are::</p><ul><li>“SERVER” (or “COMPLETE”) makes the driver execute a basic SQL query “SELECT ‘x’ FROM DUAL”,</li><li>“NETWORK” causes the driver to issue an OPING TTC function. <strong>It’s the default.</strong></li><li>“SOCKET” causes the driver to write a zero-length NS data packet on the socket, which the server ignores.</li><li>“LOCAL” same as above</li><li>“NONE” checks the connection’s lifecycle (variable check)</li></ul><p>Here is an example for setting validation properties in the <strong><em>application.properties</em></strong> file:</p><pre>#Oracle Database DataSource Configuration<br>spring.datasource.url=${JDBC_URL}<br>spring.datasource.username=${DB_USER}<br>spring.datasource.password=${DB_PASSWORD}<br><br>#UCP Settings<br>spring.datasource.type=oracle.ucp.jdbc.PoolDataSource<br>spring.datasource.oracleucp.connection-factory-class-name=oracle.jdbc.pool.OracleDataSource<br>spring.datasource.oracleucp.initial-pool-size=4<br>spring.datasource.oracleucp.min-pool-size=4<br>spring.datasource.oracleucp.max-pool-size=4<br><br>#Session Validation<br>spring.datasource.oracleucp.validate-connection-on-borrow=true<br>spring.datasource.oracleucp.connection-properties=oracle.jdbc.defaultConnectionValidation=SOCKET<br>spring.datasource.oracleucp.seconds-to-trust-idle-connection=Wrap</pre><h3>Wrap-up</h3><p>The steps described in this blog post are based on a RAC system and Oracle JDBC Drivers v19.21.0.0. A follow-up blog will describe the steps for planned and unplanned outages using the Autonomous Databases and a more recent Oracle JDBC driver release.</p><h3>Further Readings</h3><ul><li><a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/jjdbc/#Oracle%C2%AE-Database">The Oracle JDBC Developer Guide v19c</a></li><li><a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/haovw/index.html#Oracle%C2%AE-Database">High Availability Overview and Best Practices</a></li><li><a href="https://www.oracle.com/a/tech/docs/application-checklist-for-continuous-availability-for-maa.pdf">Application Checklist for Continuous Service for Maximum Availability Architecture solutions</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fb837f8e195b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/oracledevs/ucp-best-practices-for-oracle-database-19c-and-spring-boot-fb837f8e195b">UCP Best Practices for Oracle Database 19c and Spring Boot</a> was originally published in <a href="https://medium.com/oracledevs">Oracle Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[HikariCP Best Practices for Oracle Database and Spring Boot]]></title>
            <link>https://medium.com/oracledevs/hikaricp-best-practices-for-oracle-database-and-spring-boot-4d6723621c0b?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/4d6723621c0b</guid>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[oracle-database]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[best-practices]]></category>
            <category><![CDATA[hikaricp]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Thu, 18 Jan 2024 18:53:30 GMT</pubDate>
            <atom:updated>2024-08-08T14:40:37.234Z</atom:updated>
            <content:encoded><![CDATA[<h3>HikariCP Best Practices for Oracle Database and Spring Boot — V2</h3><p><a href="https://medium.com/u/4ee7e5343ded">Irina Granat</a> — <a href="https://medium.com/u/012927bd8266">Richard Exley</a>— <a href="https://medium.com/u/66c52e475e23">Kuassi Mensah</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*d--2oNnkt3TU2fax" /><figcaption>Photo by <a href="https://unsplash.com/@federize?utm_source=medium&amp;utm_medium=referral">Federico Beccari</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>This previously published blog now covers the new Oracle Database 23ai release.<br>HikariCP is a popular Java connection pool, commonly used with Spring Boot. This blog post furnishes the best practices for configuring HikariCP with Spring Boot for the Oracle Database.</p><p>You will learn how to configure HikariCP to leverage the Oracle Databases’ High Availability (HA) capabilities for continuous service during planned and unplanned downtime. <br>All the recommendations in this blog post have been tested using the latest Long Term Support (LTS) Oracle Database release i.e., 19c (19.21) and 23ai.</p><h3>About UCP</h3><p>The Oracle Database furnishes the Universal Connection Pool (UCP), a feature-rich Java connection pool — one of the Spring Boot choices — that supports out-of-the-box, all Oracle database configurations, and mission-critical capabilities such as Oracle Real Application Cluster (RAC), Data Guard, Oracle Sharding, Asynchronous API, Runtime Load Balancing, XA, and front-end to Database Resident Connection Pool (DRCP).</p><p>UCP is released quarterly and fully supported by Oracle. <br>See more details at: <a href="https://www.oracle.com/jdbc/">https://www.oracle.com/jdbc/</a></p><p>You may have standardized on HikariCP and do not necessarily need the advanced and mission-critical UCP features. However, if you’d like to migrate from HikariCP to UCP, this <a href="https://juarezjunior.medium.com/a-guide-to-migrating-from-hikaricp-to-oracle-ucp-universal-connection-pool-e2f3fb6db2d5">blog post is</a> for you.</p><h3>The Basics</h3><p>The basic steps for using HikariCP with the Oracle Database are (i) configuring the Oracle JDBC driver and (ii) configuring HikariCP.</p><h4>Configure the Oracle JDBC Driver</h4><p>Add Oracle Driver as a dependency in Spring Initializr or manually add it to your project’s <em>pom.xml.</em></p><pre>&lt;properties&gt;<br>    &lt;oracle.jdbc.version&gt;19.21.0.0&lt;/&lt;oracle.jdbc.version&gt;  <br>&lt;/properties&gt;<br> <br>&lt;dependencies&gt;<br><br>&lt;dependency&gt;<br>      &lt;groupId&gt;com.oracle.database.jdbc&lt;/groupId&gt;<br>      &lt;artifactId&gt;ojdbc8&lt;/artifactId&gt;<br>      &lt;version&gt;${oracle.jdbc.version}&lt;/version&gt;<br>&lt;/dependency&gt;<br><br>&lt;/dependencies&gt;</pre><p><strong>For Oracle database 23ai, </strong>the version of JDBC is 23.4.0.24.05:</p><pre>&lt;properties&gt;<br>    &lt;oracle.jdbc.version&gt;23.4.0.24.05&lt;/&lt;oracle.jdbc.version&gt;<br>&lt;/properties&gt;<br><br>&lt;dependencies&gt;<br>...<br>&lt;dependency&gt;<br>    &lt;groupId&gt;com.oracle.database.jdbc&lt;/groupId&gt;<br>    &lt;artifactId&gt;ojdbc8&lt;/artifactId&gt;<br>    &lt;version&gt;${oracle.jdbc.version}&lt;/version&gt;<br>&lt;/dependency&gt;<br>...<br>&lt;/dependencies&gt;</pre><p>Use this <a href="https://www.oracle.com/database/technologies/faq-jdbc.html">page</a> for more information on Oracle RDBMS and JDK Version Compatibility for Oracle JDBC Drivers.</p><h4>Configure HikariCP</h4><ol><li>Starting with version 2, Spring Boot uses HikariCP as the default connection pool and it is transitively imported with the following Spring Boot starters: <em>spring-boot-starter-jdbc or </em><em>spring-boot-starter-data-jpa.</em></li></ol><pre>&lt;parent&gt;<br>  &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br>  &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;<br>  &lt;version&gt;3.0.4&lt;/version&gt;<br>  &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;<br> &lt;/parent&gt;<br><br>&lt;dependencies&gt;<br>...<br>&lt;dependency&gt;<br>&lt;! -- Assume Spring Data JDBC --&gt;<br>            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br>            &lt;artifactId&gt;spring-boot-starter-jdbc&lt;/artifactId&gt;<br>&lt;/dependency&gt;<br>...<br>&lt;/dependencies&gt;</pre><p>2. Then configure the application properties using one of the following methods: (i) using a<em>application.properties</em> file (Spring Boot automatically reads these files and applies the configuration), (ii) creating a configuration class annotated with <em>@Configuration</em> and using <em>@Bean </em>to define the DataSource bean with HikariCP settings — we are using this method hereafter, (iii) using a<em>application.yaml</em> file, and (iv) using a Kubernetes secret, for a more secure method. See <a href="https://petersong24.medium.com/configuring-springboot-with-oracle-autonomous-database-47b58d54fe93">this UCP-related blog post</a> for more details about the approaches. Pick the approach that best fits your project and preferences. The first method might be simpler and is often sufficient for basic setups, while the second method provides more flexibility and control over the configuration in a Java class.</p><p>HikariCP has default settings that perform well in most deployments without additional tweaking. Spring Boot exposes Hikari-specific properties using the<em>spring.datasource.hikari</em>namespace. Every property is optional except for the few essential ones that must be set. <a href="https://github.com/brettwooldridge/HikariCP#gear-configuration-knobs-baby">HikariCP’s official GitHub page</a> explains various configuration options. In addition, you can review the <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html">Common Application Properties page</a> listing all Spring Boot application.properties options.</p><p>Here are examples of an <em>application.properties</em> file and <em>DataSourceConfig.java</em> class with the minimum set of properties required to use the Oracle Database.</p><p><strong>i. </strong>An <strong><em>application.properties</em> file </strong>with the minimum set of properties required for using the Oracle Database.</p><pre># Oracle DataSource Configuration<br>spring.datasource.url=${JDBC_URL}<br>spring.datasource.username=${DB_USER}<br>spring.datasource.password=${DB_PASSWORD}<br>spring.datasource.driver-class-name=oracle.jdbc.OracleDriver<br><br># HikariCP settings<br>spring.datasource.hikari.maximum-pool-size=4<br>spring.datasource.hikari.data-source-properties.oracle.jdbc.defaultConnectionValidation=LOCAL</pre><p>Setting the <em>oracle.jdbc.defaultConnectionValidation</em> property set to LOCAL or SOCKET enables lightweight connection validation by the JDBC driver when you call the <em>isValid(timeout)</em> method. We strongly recommend setting up such a property.</p><p>You may add other HikariCP properties based on your application requirements. However, when setting multiple data source properties, beware of the syntax and side effects.</p><p>We also recommend enabling additional logging to verify that your properties were correctly registered:</p><pre>logging.level.com.zaxxer.hikari.HikariConfig=DEBUG <br>logging.level.com.zaxxer.hikari=TRACE</pre><p>Please refer to the <a href="https://github.com/brettwooldridge/HikariCP">HikariCP documentation</a> for more details.</p><p><strong>ii. </strong>An example of a <strong><em>DataSourceConfig</em> class</strong> defining the minimum set of properties that the DataSource requires to work with the Oracle Database.</p><pre>package maa.spring;<br>import org.springframework.context.annotation.Bean;<br>import org.springframework.boot.context.properties.ConfigurationProperties;<br>import org.springframework.context.annotation.Configuration;<br>import com.zaxxer.hikari.HikariDataSource;<br>import com.zaxxer.hikari.HikariConfig;<br><br>import java.util.Properties;<br>import javax.sql.DataSource;<br><br>@Configuration<br>public class DataSourceConfig {<br>    @Bean<br>    public HikariDataSource getDataSource () {<br>        HikariConfig config = new HikariConfig();<br>        config.setJdbcUrl(System.getenv(&quot;JDBC_URL&quot;));<br>        config.setUsername(System.getenv(&quot;DB_USER&quot;));<br>        config.setPassword(System.getenv(&quot;DB_PASSWORD&quot;));<br>        config.setMaximumPoolSize(4);<br>        config.addDataSourceProperty(&quot;oracle.jdbc.defaultConnectionValidation&quot;, &quot;LOCAL&quot;);<br>        return new HikariDataSource(config);<br>    }<br>}</pre><p>At this stage, you have successfully configured your Spring Boot application to work with the Oracle Database using HikariCP.</p><p>The next sections cover the steps for configuring HikariCP to leverage Oracle Databases’ high availability capabilities.</p><h3>Oracle Database’s High Availability</h3><p>With the Oracle Real Application Cluster system (RAC), any Oracle database service is accessible equally from several server nodes. If a node or a subset of the RAC cluster fails or is taken offline for maintenance, the database is still accessible through the remaining active nodes.</p><p>The building blocks for implementing Application High Availability with the Oracle database are: using <a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/haovw/configuring-continuous-availability-applicationsconfiguring-continuous-availability-applicati.html#GUID-5EBF37EA-48AB-4508-A14E-86A2583A24BF">a database service</a>, configuring a URL or a connection string for High Availability, enabling Fast Application Notification (FAN), implementing draining, and enabling continuous database availability for Java applications.<br>You may choose the level of HA that suits your requirements. A detailed explanation of HA protection levels can be found in Oracle’s “<a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/haovw/configuring-continuous-availability-applicationsconfiguring-continuous-availability-applicati.html#GUID-5EBF37EA-48AB-4508-A14E-86A2583A24BF">High Availability Overview and Best Practices</a>” under the Application High Availability Levels chapter.</p><p>The following steps allow you to configure the Oracle RAC system, the Oracle JDBC driver, and HikariCP for sustaining planned and unplanned outages. The detailed steps and explanations for the continuous availability of your applications are covered in Oracle’s “<a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/haovw/configuring-continuous-availability-applicationsconfiguring-continuous-availability-applicati.html#GUID-5EBF37EA-48AB-4508-A14E-86A2583A24BF">High Availability Overview and Best Practices</a>” documentation.</p><h3>Configuring for Basic High Availability — Level 1</h3><p>Implement a level of high availability that allows applications to immediately react to instance, node, or database failures, and quickly establish new connections to surviving database instances.</p><p>With application HA Level 1, downtime is minimized for unplanned and planned outages.</p><h4>Configure High Availability Database Services</h4><p>With Oracle RAC, the Oracle database service may be deployed over several nodes in the cluster. Planned outage allows performing maintenance operations on a subset of the service nodes/hosts. The database admin issues a command that generates a planned down event. As HikariCP is not instrumented to handle such event type, it will be handled by the Oracle JDBC. The driver will drain, i.e., transparently and smoothly close all active connections, thereby allowing the nodes scheduled for maintenance, to be shut down without impacting the applications (the remaining active nodes will absorb the workload).</p><p>Create a dedicated service to support HA features as follows.</p><pre>$ srvctl add service -db mydb -service MYSERVICE -pdb mypdb<br>-notification TRUE</pre><p>The <em>-notification TRUE</em> enables FAN for this service. Your application will connect to that service.</p><h4>Configure the JDBC Connection String for High Availability</h4><p>Configure your Java application to use the following connect string.</p><pre>jdbc:oracle:thin:@(DESCRIPTION = <br>  (CONNECT_TIMEOUT= 3)(RETRY_COUNT=4)(RETRY_DELAY=2)<br>  (TRANSPORT_CONNECT_TIMEOUT=3) (ADDRESS_LIST = (LOAD_BALANCE=on) <br>  (ADDRESS = (PROTOCOL = TCP)(HOST=clu_site_scan)(PORT=1521))) <br>  (CONNECT_DATA=(SERVICE_NAME = my_service)))</pre><h4>Enable Fast Application Notification (FAN) at the Driver Level</h4><p>As HikariCP has not been instrumented to handle FAN events, the planned maintenance will be managed by the Oracle JDBC driver. To configure the driver to handle FAN events, add <em>simplefan </em>and<em> ons jar </em>files to your project’s <em>pom.xml</em>.</p><pre><br>&lt;dependencies&gt;<br><br>...<br>    &lt;dependency&gt;<br>      &lt;groupId&gt;com.oracle.database.ha&lt;/groupId&gt;<br>      &lt;artifactId&gt;ons&lt;/artifactId&gt;<br>      &lt;version&gt;${oracle.jdbc.version}&lt;/version&gt;<br>    &lt;/dependency&gt;<br>    &lt;dependency&gt;<br>      &lt;groupId&gt;com.oracle.database.ha&lt;/groupId&gt;<br>      &lt;artifactId&gt;simplefan&lt;/artifactId&gt;<br>      &lt;version&gt;${oracle.jdbc.version}&lt;/version&gt;<br>    &lt;/dependency&gt;<br><br>...<br>  &lt;/dependencies&gt;</pre><p>At this stage, the basic High Availability has been configured and furnishes the following benefits:</p><ol><li>FAN event notification of unplanned connection failures. This is especially useful when the failure may have resulted in an application hang, such as when a database node is failing and the TCP/IP sockets are not cleaned up.</li><li>A connection string that results in connection requests being load-balanced across multiple RAC nodes using Single Client Access Name (SCAN) with retry on failure.</li></ol><p>If your application has been designed to handle planned and unplanned outages via retry logic, then you don’t need anything else.</p><h3>Configuring for Planned Maintenance — Level 2</h3><p>To prepare applications for planned maintenance, add the following connection validation settings to your application code.</p><h4>Enabling Predictable Connection Validation</h4><p>By design, HikariCP validates connections that have been idle for more than 500ms (in the latest version). If a connection is constantly being checked out and checked in, it won’t be validated and, hence, won’t be drained by the Oracle JDBC driver. <br>Set the following property either as a JVM system property or programmatically in your <em>DataSourceConfig.java</em> class (as shown above) to force connection validation at checkout.</p><ul><li><em>-Dcom.zaxxer.hikari.aliveBypassWindowMs=-1</em></li><li><em>System.property(&quot;com.zaxxer.hikari.aliveBypassWindowsMs&quot;,&quot;-1&quot;);</em></li></ul><p>Please be aware that a system property has JVM scope, so a setting like this will affect all HikariCP pools in that JVM instance.</p><p>A systematic connection validation on borrow may have a slight performance impact; Oracle recommends setting a lightweight connection validation property <em>oracle.jdbc.defaultConnectionValidation </em>to<em> </em>SOCKET or LOCAL. SOCKET has a small performance penalty while LOCAL might limit the driver&#39;s ability to detect the outage) to mitigate the impact.</p><pre>props.setProperty(&quot;oracle.jdbc.defaultConnectionValidation&quot;, &quot;LOCAL&quot;);</pre><p>Setting the data source class name using the <em>application.properties</em> or the <em>applications.yaml files </em>throw<em> </em>the following error message: “<em>Caused by: java.lang.IllegalStateException: both driverClassName and dataSourceClassName</em>.” We need to set it programmatically as follows (at this point, we recommend using only <strong><em>the DataSourceConfig</em></strong> class file for any additional settings and not combining it with the <strong>application.properties</strong> file).</p><pre>package maa.spring;<br>import org.springframework.context.annotation.Bean;<br>import org.springframework.boot.context.properties.ConfigurationProperties;<br>import org.springframework.context.annotation.Configuration;<br>import com.zaxxer.hikari.HikariDataSource;<br>import com.zaxxer.hikari.HikariConfig;<br><br>import java.util.Properties;<br>import javax.sql.DataSource;<br><br>@Configuration<br>public class DataSourceConfig {<br>    @Bean<br>    public HikariDataSource getDataSource () {<br>        System.setProperty(&quot;com.zaxxer.hikari.aliveBypassWindowMs&quot;, &quot;-1&quot;);<br>        HikariConfig config = new HikariConfig();<br>        config.setJdbcUrl(System.getenv(&quot;JDBC_URL&quot;));<br>        config.addDataSourceProperty(&quot;url&quot;,System.getenv(&quot;JDBC_URL&quot;));<br>        config.setUsername(System.getenv(&quot;DB_USER&quot;));<br>        config.setPassword(System.getenv(&quot;DB_PASSWORD&quot;));<br>        config.setMaximumPoolSize(4);<br>        Properties props = new Properties();<br>        props.setProperty(&quot;oracle.jdbc.defaultConnectionValidation&quot;, &quot;LOCAL&quot;);<br>        config.addDataSourceProperty(&quot;connectionProperties&quot;, props);<br>        return new HikariDataSource(config);<br>    }<br>}</pre><p><strong>For Oracle database 23ai, </strong>change <em>config.setDataSourceClassName </em>value for data source creation to <em>oracle.jdbc.datasource.impl.OracleDataSource:</em></p><pre>config.setDataSourceClassName(&quot;oracle.jdbc.datasource.impl.OracleDataSource&quot;);</pre><h4>Performing Planned Maintenance</h4><p>The following command initiates the draining of active sessions. <br>The <em>-drain_timeout 60</em>parameter, allows active sessions to finish their requests within a predefined timeout (60 sec).</p><pre>srvctl stop instance -db mydb -node node1 -stopoption immediate <br>–drain_timeout 60 -force -failover</pre><h4>Planned Outage Success Test</h4><p>For the planned outage test, we will be using a two-node Oracle RAC environment. During normal operation, both RAC nodes are up and running and serving the application. Depending on your load-balancing strategy, the number of sessions might be different or equally distributed across both nodes. Under load (i.e., database activities), observe that the connections <strong>drain away</strong> from that instance and that the instance/node can be shut down.</p><p>We will monitor the draining process using the following SQL statement:</p><pre>select systimestamp time, machine, inst_id, count(*) from v$session where username=&#39;XXXX&#39; group by systimestamp, machine, inst_id;</pre><p>During normal operation, both RAC nodes db1 and db2 (inst_id 1 and inst_id2) are up and running. The following SQL output demonstrates how sessions for app1 and app2 are being distributed (count * column). Each application is using a connection pool that is configured to hold 4 sessions.</p><pre>SQL&gt;<br>TIME                        MACHINE      INST_ID   COUNT(*)<br>----------------------------------- --------- ---------- ----------<br>24-JUN-24 04.44.50.330975 PM +00:00 app2         2    2<br>24-JUN-24 04.44.50.330975 PM +00:00 app1         2    1<br>24-JUN-24 04.44.50.330975 PM +00:00 app1         1    3<br>24-JUN-24 04.44.50.330975 PM +00:00 app2         1    2</pre><p>To begin the planned maintenance test, we first stop the database services on node 1 using the following command:</p><pre>srvctl stop instance -db $(srvctl config database) -node db1 -stopoption immediate -drain_timeout 10 -force -failover</pre><p>Fast Application Notification (FAN) sends a stop event. The connection pool reacts to FAN and starts closing connections on node 1. At the same time, new connections are being opened on node 2. The active session on node 1 is still executing its work. If it finishes within the drain timeout (10 sec) and returns the connection to the pool, then the session is closed and a new one is established on node 2 when requested.</p><pre>SQL&gt;<br>TIME                        MACHINE      INST_ID   COUNT(*)<br>----------------------------------- --------- ---------- ----------<br>24-JUN-24 04.44.58.313179 PM +00:00 app1         2    4<br>24-JUN-24 04.44.58.313179 PM +00:00 app2         2    2<br>24-JUN-24 04.44.58.313179 PM +00:00 app2         1    2</pre><p>If the drain timeout completes but the remaining session is still connected to node 1, it will be disconnected. With Application Continuity in place, the session reconnects to node 2, and the interrupted work will be replayed transparently to the end user. See the next section for replay configuration details.</p><pre>SQL&gt;<br>TIME                        MACHINE   INST_ID   COUNT(*)<br>----------------------------------- --------- ---------- ----------<br>24-JUN-24 04.45.04.310911 PM +00:00 app1         2    4<br>24-JUN-24 04.45.04.310911 PM +00:00 app2         2    4</pre><h3>Configuring for Unplanned Outages — Level 3</h3><p>For planned maintenance, draining is used to allow active sessions to finish their work (drain) before the database instance is shut down. However, in unplanned events such as an instance, node, or database service failures, all sessions connected to the faulty node/instance will be terminated immediately — there is no time for draining. The Fast Application Notification (FAN) mechanism will detect those unplanned events and notify the JDBC driver or any connection pool such as UCP that has been instrumented to receive and process the FAN messages.</p><p>As HikarCPi is not capable of handling FAN events, the Oracle JDBC driver transparently cleans up the orphan connections and replays in-flight requests on a surviving database instance (using new connections); the failures will, therefore, be transparent to the applications that were using those connections.</p><ol><li>Add the following parameters to the database service definition:</li></ol><p><em>-failovertype AUTO — </em>enables Transparent Application Continuity (TAC).</p><p><em>-failover_restore AUTO — </em>restores client states automatically</p><p><em>-replay_init_time 600 — </em>specifies the time in seconds upon which the replay will not be performed.</p><pre>$ srvctl add service -db mydb -service MYSERVICE -pdb mypdb<br>-notification TRUE -failover_restore AUTO -failovertype AUTO -replay_init_time 600</pre><p>2. To enable continuous service during unplanned outages, include the replay data source<em> </em><em>oracle.jdbc.replay.OracleDataSourceImpl</em>in your DataSourceConfig class.</p><pre>package maa.spring;<br><br>import org.springframework.context.annotation.Bean;<br>import org.springframework.boot.context.properties.ConfigurationProperties;<br>import org.springframework.context.annotation.Configuration;<br>import com.zaxxer.hikari.HikariDataSource;<br>import com.zaxxer.hikari.HikariConfig;<br><br>import java.util.Properties;<br>import javax.sql.DataSource;<br><br>public class DataSourceConfig {<br>    @Bean<br>    public HikariDataSource getDataSource () {<br>        System.setProperty(&quot;com.zaxxer.hikari.aliveBypassWindowMs&quot;, &quot;-1&quot;);<br>        HikariConfig config = new HikariConfig();<br>        config.setJdbcUrl(System.getenv(&quot;JDBC_URL&quot;));<br>        config.addDataSourceProperty(&quot;url&quot;,System.getenv(&quot;JDBC_URL&quot;));<br>        config.setUsername(System.getenv(&quot;DB_USER&quot;));<br>        config.setPassword(System.getenv(&quot;DB_PASSWORD&quot;));<br>        config.setDataSourceClassName(&quot;oracle.jdbc.replay.OracleDataSourceImpl&quot;);<br>        config.setMaximumPoolSize(4);<br>        Properties props = new Properties();<br>        props.setProperty(&quot;oracle.jdbc.defaultConnectionValidation&quot;, &quot;LOCAL&quot;);<br>        config.addDataSourceProperty(&quot;connectionProperties&quot;, props);<br>        return new HikariDataSource(config);<br>    }<br>}</pre><p>You may notice that we added <em>config.addDataSourceProperty(“url”,System.getenv(“JDBC_URL”))</em> setting to HikariDataSource in addition to <em>config.setJdbcUrl(System.getenv(“JDBC_URL”)) </em>(this setting will be ignored in this case) — it is required to resolve <em>java.sql.SQLException: Invalid Oracle URL specified: OracleDataSource.makeURL </em>exception.</p><p><strong>For Oracle database 23ai, </strong>change the value of <em>config.setDataSourceClassName </em>for the data source creation to <br><em>oracle.jdbc.datasource.impl.OracleDataSource</em>.</p><h3>JDBC Diagnosability</h3><p><strong>New in Oracle Database 23ai: </strong>A single ojdbc jar (e.g., <em>ojdbc8.jar, ojdbc11.jar</em>) for all use cases (production, debug, metrics). In other words, no more <em>ojdbc8_g.jar or ojdbc11_g.jar </em>for debugging.</p><p>Check out this technical brief—<a href="https://www.oracle.com/a/tech/docs/database/whats-in-oracledb23ai-for-java-developers.pdf"><em>What’s in ‘Oracle DB 23c Free Developer Release’ for Java Developers</em></a>—for more information about the new JDBC Self-Driven Diagnosability in Oracle database 23ai.</p><h3>Wrap-up</h3><p>The steps described in this blog post are based on an Oracle RAC system and Oracle JDBC Drivers v19.21.0.0 and 23.4.0.24.05.</p><p>Thank you for reading!</p><h4>Further Readings</h4><ul><li><a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/jjdbc/#Oracle%C2%AE-Database">The Oracle JDBC Developer Guide v19c</a></li><li><a href="https://docs.oracle.com/en/database/oracle/oracle-database/19/haovw/index.html#Oracle%C2%AE-Database">High Availability Overview and Best Practices</a></li><li><a href="https://juarezjunior.medium.com/e2f3fb6db2d5">A Guide to Migrating from HikariCP to Oracle UCP (Universal Connection Pool)</a></li><li><a href="https://www.oracle.com/a/tech/docs/application-checklist-for-continuous-availability-for-maa.pdf">Application Checklist for Continuous Service for Maximum Availability Architecture solutions</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4d6723621c0b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/oracledevs/hikaricp-best-practices-for-oracle-database-and-spring-boot-4d6723621c0b">HikariCP Best Practices for Oracle Database and Spring Boot</a> was originally published in <a href="https://medium.com/oracledevs">Oracle Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Infrastructure as Code — App Stack for Java]]></title>
            <link>https://kuassimensah.medium.com/app-stack-for-java-caaf7cd05102?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/caaf7cd05102</guid>
            <category><![CDATA[cloud-infrastructure]]></category>
            <category><![CDATA[oracle-database-cloud]]></category>
            <category><![CDATA[terraform]]></category>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Wed, 12 Jul 2023 20:48:14 GMT</pubDate>
            <atom:updated>2024-09-06T10:30:11.223Z</atom:updated>
            <content:encoded><![CDATA[<h3>Infrastructure as Code — App Stack for Java</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5gTyiWJzxdf68NBs1FhiZg.jpeg" /><figcaption>Photo by<strong>:</strong> <a href="https://burst.shopify.com/@matthew_henry">Matthew Henry</a>.</figcaption></figure><p>What are the pain points in deploying Java Apps? Infrastructure as Code (IaC) allows automating most tasks involved with provisioning Cloud infrastructure resources thereby eliminating those pains.<br>This post identifies the main steps in deploying your Java app and then introduces the App Stack for Java, a stack in the Oracle Cloud <br>Infrastructure marketplace for automating these steps.</p><h3>Pain Points for Deploying Java Apps</h3><p>Here are the common pains for deploying your Java applications over a Cloud infrastructure.</p><ol><li>Configuring the virtual network (VCN, subnets, security lists, route tables, gateways).</li><li>Provisioning of the deployment platform.</li><li>Provisioning a new database or reusing an existing one.</li><li>Configuring the JDBC data source.</li><li>Configuring the load balancer.</li><li>Configuring DNS.</li><li>Generating the build and deployment of CI/CD pipelines.</li><li>Activating the monitoring service.</li></ol><p>An IaC solution could take care of all these steps; all you’ll have to do is fill up some parameters then click a button and, after a few minutes, your application is up and listening for requests.</p><h3>Introducing the App Stack for Java</h3><p>The <a href="https://github.com/oracle-quickstart/appstack">App Stack for Java</a> is a Terraform-based IaC product (or “solution”) that provisions serverless resources in the Oracle Cloud Infrastructure and deploys your Java App. <br>Note: this is not a managed Cloud service.</p><h4>Target Apps &amp; Use Cases</h4><ul><li>Web applications (server-side HTML applications, aka servlets or Java Server Pages).</li><li>Back-end servers (REST APIs).</li><li>Standalone Java app that embeds a runtime (Netty for example).</li><li>Servlet or JSP packaged as a Web Application Archive (WAR) that the stack deploys on Tomcat.</li><li>Spring or SpringBoot application (with or without Hibernate) that configures Tomcat as a dependency.</li><li>Generic use case: container image that includes a web app (doesn’t have to be Java).</li></ul><h4>The Key Features</h4><ul><li>Simple to configure and launch.</li><li>Provisions the serverless Cloud resources required/configured by the Java App.</li><li>Mirror the Application source code from GitHub to OCI DevOps.</li><li>High Availability with a minimum of two container instances.</li></ul><h4>How Does the App Stack for Java Work?</h4><p>For deploying your Java app with the App Stack for Java, you need to</p><ol><li>Fulfill the OCI prerequisites.</li><li>Fill out the parameters; this is the only hard part.</li><li>Apply the stack -&gt; one-click deployment.</li></ol><p>That’s it, the Application is ready to handle requests!<br>A complete step-by-step tutorial and videos are furnished hereafter.</p><h4>Under the Covers</h4><p>The App Stack performs the following actions</p><ul><li>Create a new repository “xxxx_config”.</li><li>Leverage OCI services such as VCN, Object stores.</li><li>Download the database wallet (wallet.zip): the zip file includes Tnsnames.ora, cwallet.sso, and ojdbc.properties. If the database wallet is rotated this zip file needs to be updated.</li><li>Generate the Dockerfile for building the container image.</li><li>Generate the spec for the build pipeline.</li><li>Generate the self-signed keystore for the internal HTTPS connection between the load balancer and the container instances.</li><li>Pull orapki.jar for use by the build pipeline to add the DB password to cwallet.sso.</li><li>Generate a <em>container image</em> of the user’s application, including an HTTP/HTTPS server and pre-configured ADB access.</li><li>Add the generated image to the Container Registry.</li><li>Deploy the application in Container Instances.</li><li>Provisions the Autonomous Database.</li><li>Generates the dependencies to pull JDBC, UCP, R2DBC, and so on from Maven Central.</li><li>It provisions Oracle Application Performance Monitoring (Oracle APM) and connects your app.</li><li>And much more …</li></ul><p>These actions constitute pain relief and the main purpose of the App Stack.</p><h3>Prerequisites and Cloud Resources</h3><p>What are the prerequisites and Cloud resources used for deploying your Java App?</p><h4>Prerequisites</h4><p>This step is required whether you are using the App Stack for Java or not.</p><ol><li>Select an application in your GitHub repo and create a personal token if you don’t already have one.</li><li>Create an OCI compartment</li><li>Create an OCI Vault in that compartment then add an encryption key</li><li>Add the GitHub token as a secret</li><li>Create a dynamic group and related policies</li><li>For CI/CD managing, create an empty project (with its topic) in OCI DevOps and enable logging</li><li>Allow OCI DevOps to connect to your GitHub repo by creating a connection</li><li>Mirror your GitHub project in OCI DevOps.</li></ol><h4>The Cloud Resources Used by Your Java App</h4><p>Cloud resources are provisioned when you execute the stack based on its configuration. Most of these are free, even always free!</p><p><strong>Free-Tier and Always-Free Resources</strong></p><p>The <a href="https://www.oracle.com/cloud/free/">Oracle Cloud Free Tier service</a> allows you to build, test, and deploy your applications on Oracle Cloud for free. Upon signing up, the service comes with a $300 credit with 30 days expiration; following the expiration or the exhaustion of the credit, most of the provisioned services remain available as <a href="https://www.oracle.com/cloud/free/#always-free">Always Free</a>. You may add additional credit for services that do not fall under Always-Free.</p><p><strong>Container Instances</strong></p><p>OCI Container Instances are serverless compute resources (Open Container Initiative-compliant), optimized for containerized workloads that do not require a container orchestration platform such as Kubernetes.<br>You pay only for the CPU and memory resources allocated to your container instance, which are the same price as the regular Compute Instances for the chosen shape.</p><p><strong>Resources Map and List</strong></p><p>Here is the map and the list of OCI resources provisioned for your Java app by the App Stack.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YsLkpITF5_ZQWvPX7VMSUg.png" /></figure><ul><li>Container Instances for building and running the app. Not an Always-Free resource.</li><li>DevOps project (optional): used for the build pipeline and CI/CD of the Java app; an OCI DevOps project is a mirror of your GitHub project. This service isn’t required if the application is already packaged as a container image.</li><li>Database: an existing Autonomous Database — Shared Infrastructure (ADB-S) can be used with the stack. The stack may create a new one if specified during the Stack configuration. This is an Always-Free</li><li>Vault (optional): necessary to avoid the limit on the number of tokens the current user has; we do not recommend using the current user, however, the Vault isn’t required if the application is provided as a container image.</li><li>A load balancer; part of Always-Free.</li><li>DNS (optional): A DNS zone for creating the application URL (for example <a href="https://myapp.domain.com/">https://myapp.domain.com</a>). If not provided during the stack configuration, the application will be available through the load balancer’s public IP (Always-Free). You can then configure your third-party DNS provider to point to this IP address.</li><li>HTTPS certificate (optional): if no certificate is provided, HTTP will be used against the IP address; this resource is part of Always-Free</li><li>Security policies</li><li>Monitoring service (Oracle APM); part of Always-Free.</li></ul><p>With an average burn rate of $3 and the initial $300 Free-Tier credit, you have sufficient free and cheap resources (i.e., when Free-Tier ends) to build, test, and deploy your Java apps with the App Stack.</p><h4>Get Started — Tutorial &amp; Videos</h4><p>Before using the App Stack for your own apps, we urge you to go through this complete <a href="https://github.com/oracle-quickstart/appstack/blob/main/tutorials/mytodolist/tutorial.md">step-by-step tutorial</a> for deploying a SpringBoot app on OCI using the App Stack for Java.</p><p><a href="https://www.youtube.com/playlist?list=PLPIzp-E1msrbhZ5mTyNR6s5LssMd9V2Rv">Here is the playlist</a> of the walk-through videos including</p><ul><li><a href="https://www.youtube.com/watch?v=K2LZzmIrXso&amp;list=PLPIzp-E1msrbhZ5mTyNR6s5LssMd9V2Rv&amp;index=2&amp;t=50s">Prerequisites for source code deployment</a>.</li><li><a href="https://www.youtube.com/watch?v=qMdM6s7MKyY&amp;list=PLPIzp-E1msrbhZ5mTyNR6s5LssMd9V2Rv&amp;index=2&amp;t=24s">Configuring and provisioning for source code deployment</a>.</li><li><a href="https://www.youtube.com/watch?v=9DHmk0w8te4&amp;list=PLPIzp-E1msrbhZ5mTyNR6s5LssMd9V2Rv&amp;index=3&amp;t=48s">CI/CD workflow, and Observability</a>.</li></ul><p>We will soon release more videos related to apps packaged as Java artifacts (WAR, JAR) and Containerized images.</p><h4>Get Help</h4><ul><li>Submit a GitHub issue</li><li>Email appstack_ww at oracle.com.</li></ul><p>Follow<strong> @kmensah </strong>and<strong> #AppStack </strong>for notifications, questions, and discussions.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=caaf7cd05102" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[#OraOperator goes Production]]></title>
            <link>https://kuassimensah.medium.com/oraoperator-goes-production-5a0bbd5fff65?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/5a0bbd5fff65</guid>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[kubernetes-operator]]></category>
            <category><![CDATA[oracle-database]]></category>
            <category><![CDATA[cloud-native]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Thu, 06 Jul 2023 17:15:03 GMT</pubDate>
            <atom:updated>2023-09-07T18:55:57.597Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/175/0*70aYX-f2ga64tPQX.png" /><figcaption>OraOperator</figcaption></figure><p>I am very pleased to announce that the long overdue production release (v 1.0.0) of the <a href="https://github.com/oracle/oracle-database-operator">Oracle Database Operator for Kubernetes</a> (a.k.a. OraOperator) has been released.</p><h3>What’s In It?</h3><p>In this release, OraOperator supports containerized databases, database services deployed on the Oracle Cloud Infrastructure (OCI), and on-premises databases.</p><h4>Containerized Databases</h4><p>The Oracle database images (custom-built or from the container registry) are deployed within the Kubernetes cluster alongside OraOperator. These databases can be deployed in any Kubernetes cluster where the operator runs including OKE, 3rd party Kubernetes clusters, on-premises Kubernetes (Oracle Linux), and so on.<br><br>Let’s sum up the lifecycle operations supported for each kind.</p><p><strong><em>Single Instance Databases (a.k.a. SIDB)</em></strong></p><p>The Single Instance DB controller supports the following Oracle database editions: Standard Edition (SE), Enterprise Edition (EE), eXpress Edition (XE), and DB23c Free.</p><p>The supported lifecycle operations include: provisioning a new database instance, provisioning a new pre-built database instance, cloning a database, patching a database (in-place/out-of-place), deleting a database, and updating the database init parameters.<br>The SIDB controller furnishes additional features such as REST enabling a database, running multiple replicas of a database, setting up a database with LoadBalancer, installing APEX, enabling TCPS connections, and getting the connect string to the CDB. <br>For more details, please refer to the SIDB Readme (under the <em>…/doc/sidb</em> folder).</p><p><strong><em>Sharded Databases</em></strong></p><p>An Oracle Sharding database is made of Shards. Containerized Shards are deployed over several Kubernetes pods.</p><p>The Sharding Database controller supports the following lifecycle operations: deploy the Shard topology (i.e., the Sharding infrastructure) using various options (check out the <em>…/doc/sharding/Readme.md</em> for more details), Add a Shard, Delete a Shard, Clone a Shard.</p><p><strong><em>Data Guard (Preview)</em></strong></p><p>In this release, a new Data Guard controller is introduced as a preview.</p><p>This controller allows creating a Standby Database for a Single Instance database (see the prerequisites in <em>…/doc/sidb</em>), adding databases in the Data Guard configuration, and deleting a database configured for Data Guard. <br>Additional operations include connecting to the Primary, performing a Switchover, and patching the Primary and the Standby databases.</p><h4>OCI-Only Databases</h4><p>The operator manages also the lifecycle of Cloud database services deployed in the Oracle Cloud Infrastructure (OCI), outside the OKE Kubernetes cluster. Unlike containerized databases, these Cloud database services are only available/deployable in Oracle Cloud.</p><p><em>Autonomous Database (Shared, Dedicated)</em></p><p>Autonomous Databases are the flagship Oracle Cloud database services and come in two flavors: shared infrastructure (a.k.a. ADB-S) and dedicated infrastructure (a.k.a. ADB-D). ADB refers to both flavors. The infrastructure is known as the Autonomous Container Database (ACD).</p><p>The Autonomous Database controller supports the following lifecycle operations: provisioning an Autonomous Database (ADB), binding the operator to an existing ADB, scaling Up/Down the OCPU core count or the storage, managing the database ADMIN password, downloading ADB instance credentials (i.e., wallets), Starting/Stopping/Terminating an ADB, and deleting anADB from the resources (CRDs) known by the operator.</p><p><em>Base DB (formerly DBCS)</em></p><p>The Oracle Base Database Cloud Service allows deploying single-node and two-node database systems on virtual machines. See more details about the supported database editions and versions, <a href="https://docs.oracle.com/en-us/iaas/dbcs/doc/bare-metal-and-virtual-machine-db-systems.html">here</a>.</p><p>The BaseDB controller supports the following lifecycle operations: provision a BaseDB, binding to an existing BaseDB, scaling UP/DOWN the shape of an existing BaseDB, scaling UP the storage of an existing Base DB, deploying a two-nodes RAC, updating the license type, and terminating an existing BaseDB.</p><h4>On-Premises Databases</h4><p><em>Multitenant Databases (Exadata, PDBs)</em></p><p>A multitenant controller enables managing the lifecycle of pluggable databases (a.k.a. PDBs) associated with a Container database (a.k.a. CDB). The Oracle REST Data Service is required for reaching the PDBs.</p><p>The controller supports the creation of a new PDB, cloning a PDB, modifying the state of a PDB, unplugging a PDB from a CDB, plugging an unplugged PDB into a CDB, and deleting a PDB.</p><h4>Pre-installed on OKE</h4><p>On OCI, OraOperator is pre-installed and ready to use as an Add-on to OKE Console deployment. In future releases, a button will automatically provision Cloud database services (i.e., the Autonomous Databases and BaseDB).</p><h3>Resources</h3><p>Livelab: <a href="https://apexapps.oracle.com/pls/apex/f?p=133:180:106560118131679::::wid:3393">Oracle Database Operator for Kubernetes + DevOps</a>.</p><p>Get help either by submitting a GitHub issue and/or filing an <a href="https://support.oracle.com/portal/">Oracle Support service request</a> against the Oracle Database Operator for Kubernetes (product ID: 14423).</p><p>Visit our <a href="https://www.oracle.com/database/kubernetes-for-container-database">website</a> for the latest news about Oracle Databases, Containers, and Kubernetes.</p><p>Follow<strong> @kmensah </strong>and<strong> #OraOperator </strong>for notifications, questions, and discussions.</p><p>Thanks for reading.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5a0bbd5fff65" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What’s in ‘Oracle DB 23c Free — Developer Release’ for Java Developers]]></title>
            <link>https://kuassimensah.medium.com/whats-in-oracle-db-23c-free-developer-release-for-java-developers-26931081682c?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/26931081682c</guid>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[virtual-threads]]></category>
            <category><![CDATA[oracle]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[database]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Fri, 19 May 2023 13:47:52 GMT</pubDate>
            <atom:updated>2023-10-26T16:37:17.253Z</atom:updated>
            <content:encoded><![CDATA[<h3>What’s in ‘Oracle DB 23c Free Developer Release’ for Java Developers</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HuEcENi6VFxzpgZmzTGbrw.png" /></figure><h3>Free as in Free Beer</h3><p>The “<em>Oracle Database 23c Free — Developer Release</em>” is a full-featured, no-click-through, developer focussed Oracle database. It has been released under the <a href="https://www.oracle.com/downloads/licenses/oracle-free-license.html">Free Use Terms &amp; Conditions license</a>; see more details <a href="https://medium.com/oracledevs/introducing-oracle-database-23c-free-developer-release-5c21e5854092">here</a>.</p><p>It brings new features for Java developers. This blog post highlights my favorite features; others will be covered in depth in subsequent blog posts.</p><h3>My Favorites Cool Java Features</h3><p>I am totally biased here! I’ll cover Java support for pipelined database operations, Relational-JSON Duality Views, and Self-driven diagnosability.</p><h4>1 — Java and Pipelined Database Operations</h4><p>A database pipeline consists of a sequence of multiple database requests submitted without waiting for a response between operations. The database sends a response when the results of each query are ready. <br>Pipelined database operations foster an asynchronous programming model, in which a user thread returns immediately upon submitting a SQL statement for execution without waiting for its execution and the ResultSets.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/646/1*9SgFg5AzSzA96ku5hIbZgg.png" /><figcaption>Fig 1 — Pipelined vs Non-Pipelined Database Operations</figcaption></figure><p>Java developers would leverage database pipelining through the Oracle JDBC Reactive Extensions, the Reactive Streams libraries, Virtual Threads, and the standard JDBC Batching.</p><p><strong>JDBC Reactive Extensions and Database Pipelining</strong></p><p>Introduced in Oracle JDBC release 21.1, the JDBC Reactive Extensions implement the Java Flow API and extend it with the asynchronous forms of connection creation, SQL execution, row data fetching LOB I/O, and transaction control (i.e., commit/rollback). The API is fully compliant with the Reactive Streams 1.0.3 specification and interoperates with the ecosystem of reactive libraries including Spring, jOOQ, Helidon, Hibernate, Project Reactor, RxJava, Akka Streams, and more.<br>The following code introduces the concept of calling AsyncOracle methods — part of Oracle JDBCs’ Reactive Extensions — to compose a pipeline.<br> In the later examples, the intricacies of closing statements and consuming results for reactive and synchronous-using-Virtual-Threads programming models will be shown.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ef563523342f63617a0584ddc02b4d79/href">https://medium.com/media/ef563523342f63617a0584ddc02b4d79/href</a></iframe><p>In the example above, a call to <em>unwrap(OraclePreparedStatement.class)</em> is used to access the methods of the Reactive Extensions API i.e., <em>executeUpdateAsyncOracle</em> and <em>executeQueryAsyncOracle</em>. These methods return a <em>Flow.Publisher. </em>As the result of each SQL statement is received, the Publisher emits a ResultSet to a Subscriber. How exactly? JDBC “listens” for the database response to each SQL statement by polling the network using a single Selector across the driver. Upon the reception of the database response, the Selector invokes a callback that reads the message.</p><p><strong>Reactive Streams Libraries and Database Pipelining</strong><br>Reactive libraries such as Project Reactor, RxJava, Akka Streams, Spring, jOOQ, Helidon MP Reactive Streams, Hibernate Reactive, and so on — expose an API that is similar to <em>java.util.stream.Stream</em>. The code example from the previous section can be expanded to use the API of Project Reactor.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/526393a012a81a297e4e56852bc7aa65/href">https://medium.com/media/526393a012a81a297e4e56852bc7aa65/href</a></iframe><p>In the example above, instances of Mono and Flux are created by calling their “from” methods. The argument to the method is an <em>org.reactivestreams.Publisher</em>, which is adapted from a Flow.Publisher by calling <em>org.reactivestreams.FlowAdapters.toPublisher</em>. A “subscribe” method is called to asynchronously consume the results with a callback function. To consume a result of multiple rows, a call to <em>Mono.flatMapMany</em> converts a stream of a single ResultSet into a stream of multiple row values.</p><p><strong>Virtual Threads and Database Pipelining</strong><br>Looking ahead, Virtual Threads (Project Loom) is an alternative to Reactive Streams and is touted as the future of Java scalability.<br>Oracle JDBC has been instrumented with Virtual Threads since the 21.1 release. Specifically, the driver will not cause thread pinning by holding an intrinsic lock during I/O calls. For more details, see: <a href="http://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html#pinning">http://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html#pinning</a><br>With Virtual Threads, asynchronous APIs like Reactive Streams can easily be translated into synchronous code. A Virtual Thread only needs to block its execution until an asynchronous result has been received. To demonstrate this, the code example from the previous section can be re-written as follows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/01e1f3433808d48e7e1b7dec58bd02f9/href">https://medium.com/media/01e1f3433808d48e7e1b7dec58bd02f9/href</a></iframe><p>Just like the code sample of the previous section, each <em>Flow.Publisher</em> is converted into a Mono or Flux from the Project Reactor API. However, with Virtual Threads, there is no longer a need to consume the results asynchronously. Instead of calling the subscribe method with a callback function, a Virtual Thread can simply call the <em>block() </em>method. The block method blocks the Virtual Thread until the result of the asynchronous call is received. The result may then be processed in a traditional style using imperative programming.</p><p><strong>Standard JDBC Batching</strong></p><p>The Oracle JDBC driver will start a database pipeline as soon as you start using the JDBC batching APIs i.e., s<em>tmt.addBatch() or prepstmt.addBatch()</em>; the driver generates asynchronous calls under the covers, using the JDBC Reactive Extensions APIs.</p><h4>2 — Java and the JSON-Relational Duality Views</h4><p>Many applications require simplicity (self-describing, self-contained, and schema-less), ease of development (i.e., access JSON data programmatically), hierarchical data, common interchange format (i.e., easy to transmit across the network), and ease of conversion to Java types of JSON — and by the same token — the efficiency of space management, the queryability, consistency, and the powerful analytics and reporting capabilities of SQL . The JSON-relational duality views consist in presenting relational data as JSON documents. This feature gives developers the best of the Relational and JSON worlds. More details can be found <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/jsnvu/overview-json-relational-duality-views.html#GUID-CE7227BF-B4AF-4024-A578-ED52795F4525">here</a>.</p><p><strong>How to Setup and Use JSON-Relational Duality views?</strong></p><ol><li>Create and populate the regular relational tables (or reuse existing ones). E.g., Students, Teachers, and Classes tables.</li><li>Create one or several JSON-Relational Duality Views based on use cases, using either a SQL visual tool, a SQL CLI, or programmatically using JDBC <em>Statement.execute(“ …”)</em>.<br>Each view consists in leveraging several capabilities. The following SQL code fragment maps base table columns to JSON name/values pairs.</li></ol><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/58e58e1411220a65ec0a5b312ea0e163/href">https://medium.com/media/58e58e1411220a65ec0a5b312ea0e163/href</a></iframe><p>The following SQL code extends the previous one using a subquery to assemble nested data into a JSON array.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dc18a36822d962e538579c7918615b7c/href">https://medium.com/media/dc18a36822d962e538579c7918615b7c/href</a></iframe><p>The following SQL statement completes the previous ones by specifying update rules.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/77c994f53fc3cd5da4e0d137f1d84bda/href">https://medium.com/media/77c994f53fc3cd5da4e0d137f1d84bda/href</a></iframe><p>That’s it! You can now work directly with the JSON documents using the following query which returns John’s schedule as a JSON document.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8c95a02292decad3c4d46fcb98377436/href">https://medium.com/media/8c95a02292decad3c4d46fcb98377436/href</a></iframe><p>Using the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/sql/json/package-summary.html"><em>oracle.sql.json</em> </a>package in Oracle JDBC, you can retrieve the value of specific properties from John’s schedule.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/97caff94876500cc14b69687cbc201fa/href">https://medium.com/media/97caff94876500cc14b69687cbc201fa/href</a></iframe><p>JSON document transfer to the Java app can be performed either in binary JSON (OSON, suitable for large documents) or String (for small documents).</p><h4>3 — JDBC Self-Driven Diagnosability</h4><p>Every Java developer using the Oracle database will appreciate the following statement: “No more switching between the production jar and the debug jar to investigate an issue”! <br>A single ojdbc jar (e.g., <em>ojdbc8.jar, ojdbc11.jar</em>) for all use cases (production, debug, metrics). In other words, no more <em>ojdbc8_g.jar or ojdbc11_g.jar </em>for debugging, no more <em>ojdbc8dms.jar or ojdbc11dms.jar</em> for the Oracle Dynamic Monitoring Service (DMS) metrics, and no more <em>ojdbc8dms_g.jar or ojdbc11dms_g.jar</em> for DMS debugging.</p><p>Although the debug and metrics jars have been eliminated, the core JDBC jar furnishes enhanced logging, debugging (diagnose-on-first-failure), and execution tracing.</p><p><strong>Logging</strong>: the core JDBC Jars (i.e., <em>ojdbc8.jar</em> or <em>ojdbc11.jar</em>) include the logging capabilities which need to be turned on using the following properties:<br> <em>-Doracle.jdbc.diagnostic.enableLogging=true<br></em>in addition, the location of the logging configuration file <em><br> -Djava.util.logging.config.file=./logging.config <br></em>and the content of the logging configuration file<br> <em>handlers = java.util.logging.ConsoleHandler<br> oracle.jdbc.level = FINEST<br> java.util.logging.ConsoleHandler.level = FINEST<br> java.util.logging.ConsoleHandler.formatter =<br> oracle.jdbc.diagnostics.OracleSimpleFormatter</em></p><p><strong>Diagnose-on-first-failure</strong>: this feature diagnoses the first occurrence of a failure. It records the critical execution state in memory, then dumps the recording on error. It’s ON by default however, you may disable it either by setting the CONNECTION_PROPERTY_ENABLE_DIAGNOSE_FIRST_FAILURE<em> </em>property to FALSE<em> (</em>the default value)<em> </em>or via the <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/jajdb/oracle/jdbc/diagnostics/package-summary.html">DiagnosticMBeans interface</a>.</p><p>For security, each diagnosability feature has two modes, public and sensitive. In the public mode, these features do not record or persist sensitive information. This severely limits the amount of information captured and reduces the effectiveness of the diagnosability features. In the sensitive mode, these features record and persist sensitive information. Java developers can share traces with the redaction of sensitive data. The sensitive mode can only be enabled by a privileged user and is controlled by two switches; one for enabling and another one for permitting. Only the permit property is required. If the permit property is included in the java command line then sensitive mode can be enabled and disabled programmatically at runtime, or via MBean. It can also be enabled via the enable property as shown.<br> <em>-Doracle.jdbc.diagnostic.enableSensitiveDiagnostics=true<br> -Doracle.jdbc.diagnostic.permitSensitiveDiagnostics=true</em></p><p>You must configure java.util.logging (see above) to get diagnostic output on diagnose-on-first-failure.</p><p><strong>Execution Trace</strong>: this feature records the execution sequence details. <br>The JDBC driver has also been instrumented with a hook for tracing database round trips; this hook enables the support of OpenTelemetry.<br>In a nutshell, OpenTelemetry is enabled using 3rd party libraries such as <em>OpenTelemetry-JDBC</em> without code change. All top-level calls can be monitored; the Java agent creates a span for JDBC calls. <br>To be covered in detail in an upcoming blog post.</p><p><strong>DMS Metrics</strong>: The DMS metrics are recorded if the <em>dms.jar</em> is in the classpath.</p><p><strong>Caution</strong>: you must balance the volume of state information recording against the cost of recording. As execution trace has a significant cost involved, you are advised to enable it only in limited contexts.</p><h3>Other Java Goodies</h3><ul><li><em>Native Boolean datatype</em> in oracle.jdbc.OracleType.</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a7aeb6b5353a8bc26927b1597f945f05/href">https://medium.com/media/a7aeb6b5353a8bc26927b1597f945f05/href</a></iframe><ul><li><em>JDBC-Thin support for passwords up to 1024 bytes in length</em>.</li><li><em>JDBC-Thin generic support for token-based authentication</em> including Oracle Cloud Infrastructure (OCI) Identity Access Management (IAM), and Azure Active Directory (Azure AD). See more <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/jjdbc/client-side-security.html#GUID-62AD3F23-21B5-49D3-8325-313267444ADD">here</a>.</li><li><em>JDBC-Thin support for RADIUS and RADIUS two-factor authentication</em> where the RADIUS server asks for a valid response to a displayed challenge. See more <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/jjdbc/client-side-security.html#GUID-E8CEB076-4DD7-49EB-86D3-82F503E34A02">here</a>.</li><li><em>JDBC Support for Directory-based Sharding and Split Partition Set</em>.<br>No public Java API however, under the covers, during the partition-set split, the client-side connection pools receive ONS events about data in a chunk being split and moved across partition sets and update their sharding topology appropriately.</li><li><em>UCP Support for XA Transactions with Oracle Database Sharding.</em> Java applications that use the UCP native data source in WebLogic Server to connect to Sharded Oracle databases can participate in JTA/XA transactions managed by the WebLogic Transaction Manager (TM).</li><li><em>Oracle JVM Support for HTTP and TCP access while disabling other OS calls.</em> See more details in <a href="https://docs.oracle.com/en/database/oracle/oracle-database/23/jjdev/DB-security-in-multitenant.html#GUID-71533511-C90F-4656-A46A-306A4E56787E">Database Security in a Multitenant Environment</a>.</li></ul><h3>Wrap Up</h3><p>I trust that this post has inspired you to design new projects or re-architect existing ones, based on the new Java features in <em>Oracle Database 23c Free — Developer Release</em>.<br>Thank you for reading.<br>@kmensah #javaOracleDB http://oracle.com/jdbc</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=26931081682c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Oracle Database Operator for Kubernetes — Take 2]]></title>
            <link>https://medium.com/oracledevs/oracle-database-operator-for-kubernetes-take-2-e0227ca7b7c3?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/e0227ca7b7c3</guid>
            <category><![CDATA[kubernetes-operator]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <category><![CDATA[oracle]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Tue, 28 Jun 2022 17:09:08 GMT</pubDate>
            <atom:updated>2022-07-28T22:18:22.466Z</atom:updated>
            <content:encoded><![CDATA[<h3>Oracle Database Operator for Kubernetes — Take 2</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/175/0*xq6nxZ8a3MBnDq6T.png" /><figcaption>OraOperator</figcaption></figure><p>The introductory release (<a href="https://medium.com/oracledevs/making-oracle-database-kubernetes-native-401233c02780">v0.1.0</a>) of <a href="https://github.com/oracle/oracle-database-operator">Oracle Database Operator for Kubernetes</a> (#OraOperator) lets you manage the lifecycle of Single Instance Databases, Sharded Databases, and the Autonomous Database on shared infrastructure (ADB-S).</p><p>In this feature-packed v0.2.0 release, #OraOperator extends its reach over even more database configurations, and enhances existing features. Hopefully, you’ll appreciate why it took us a while, after v0.1.0, to get it out. But don’t just take my word for it — check it out yourself.</p><h3>What’s in #OraOperator v0.2.0?</h3><p>While the operator itself is deployed on a Kubernetes cluster (see “Where does OraOperator Run?<em>”</em>), its operational reach straddles databases deployed within the Kubernetes cluster and those deployed outside of it.</p><p>Here’ s what you’ll find in the v0.2.0 release.</p><h4>In-k8s Cluster Databases</h4><p>These databases run in containers are (such as Docker) deployed within the Kubernetes cluster.</p><p><em>Single Instance databases (SIDB)</em></p><p>This release brings new enhancements to the SIDB controller such as support for pre-built XE for faster provisioning. The list of features include provision, clone, patch (in-place/out-of-place), update database initialization parameters, update database configuration (Flashback, archiving), Oracle Enterprise Manager (EM) Express (a basic observability console), Oracle REST Data Service (ORDS) to support REST-based SQL, PDB management, SQL Developer Web, and Application Express (Apex). Get more details in the <a href="https://github.com/oracle/oracle-database-operator/tree/main/docs/sidb">SIDB controller doc</a>.</p><p><em>Sharded Databases</em></p><p>The operator can provision the shard topology, add a new shard, and delete an existing shard. Get more details in the <a href="https://github.com/oracle/oracle-database-operator/tree/main/docs/sharding">Sharded Database controller doc</a>.</p><h4>Off-k8s Cluster Databases</h4><p>These databases run either in the Oracle Cloud or on-premises.</p><p><em>Autonomous Databases &amp; Container</em></p><p>The autonomous database runs in the Oracle Cloud Infrastructure (OCI), off the Kubernetes cluster.</p><ul><li>ADB-S: stands for Autonomous Database on a shared infrastructure. In other words, multiple tenants share the same infrastructure but each deploy their own database. In this release, the operator can provision, bind, start, stop, terminate (soft/hard), and scale (up/down) an ADB; it can also perform manual or on-demand backup as well as manual restore.<br>Note: the Autonomous Database already performs automatic backup and restore.</li><li>ADB-D: stands for Autonomous Database on a dedicated infrastructure; the tenant has exclusive use of the infrastructure. The support for ADB-D is a new in this release. The operator can provision, bind, start, stop, terminate (soft/hard), and scale (up/down) an ADB. In addition — new to this release — it can also perform manual backup and manual restore.</li><li>Autonomous Container Database (ACD): this is the database infrastructure where Autonomous Databases are plugged in. The support for ACD is new, in this release. The operator can provision, bind, restart, and terminate (soft/hard) an ACD.</li></ul><p>Get more details in the <a href="https://github.com/oracle/oracle-database-operator/tree/main/docs/adb">ADB doc</a> as well as the <a href="https://github.com/oracle/oracle-database-operator/tree/main/docs/acd">ACD doc</a>.</p><p><em>Database Cloud Service (DBCS)</em></p><p>DBCS is made of single-node DB systems and two-nodes Oracle RAC systems on virtual machines; this is part of co-managed databases in OCI (i.e., managed by Oracle and customers). The support for the Database Cloud Service is new in this release. The operator can provision, bind, scale Up/Down, liveness probe a DBCS, and it can also perform manual backup. Get more details in the <a href="https://github.com/oracle/oracle-database-operator/tree/main/docs/dbcs">DBCS controller doc</a>.</p><p><em>On-Premises Databases</em></p><p>Requested by many customers, the automation of the lifecycle of on-premises multi-tenant databases is an indispensable part of IT modernization. With #OraOperator, multi-tenant databases (CDB/PDBs) can be integrated in DevOps CI/CD. In this release the operator can bind to an existing CDB, create a PDB, plug a PDB, unplug a PDB, delete a PDB, clone a PDB, and open/close a PDB. Get more details in the <a href="https://github.com/oracle/oracle-database-operator/tree/main/docs/onpremdb">On-Premises controller doc</a>.</p><h3>Where Does OraOperator Run?</h3><p>#OraOperator runs on almost every Kubernetes platform, in the Cloud or on-premises. It has been flawlessly installed and tested on the following Kubernetes platforms.</p><ul><li><a href="https://www.oracle.com/cloud-native/container-engine-kubernetes/">Oracle Container Engine for Kubernetes (OKE)</a> with Kubernetes 1.17 or later</li><li><a href="https://docs.oracle.com/en/operating-systems/olcne/">Oracle Linux Cloud Native Environment(OLCNE)</a> 1.3 or later</li><li><a href="https://minikube.sigs.k8s.io/docs/">Minikube</a> with version v1.21.0 or later</li><li><a href="https://azure.microsoft.com/en-us/services/kubernetes-service/">Azure Kubernetes Service</a></li><li><a href="https://aws.amazon.com/eks/">Amazon Elastic Kubernetes Service</a></li><li><a href="https://www.okd.io/">Red Hat OKD</a></li><li><a href="https://www.redhat.com/en/technologies/cloud-computing/openshift/">Red Hat OpenShift</a> (we’ve heard from partners)</li><li>Custom K8s platforms (we’ve heard of)</li></ul><p>The key difference between those platforms is the configuration of persistent volumes for in-cluster databases. Please share your experience installing (#oraoperator) if you have tested any of the k8s platforms listed above or others.</p><h3>Looking Forward …</h3><p>In the upcoming releases, #OraOperator will move to production status and add support for more database deployments, as well as furnishing additional services such as OLM install, OpenTelemetry-based unified observability (traces, logs metrics) with a Grafana dashboard, and so on.</p><p><strong>@kmensah </strong>and<strong> #OraOperator </strong>for notifications, questions, and discussions.</p><p>Thanks for reading.</p><p>Note: If you use k8s and swoon at DevOps at large, we know you’d love Oracle Cloud Infrastructure’s Free Tier account. <a href="https://signup.cloud.oracle.com/?language=en&amp;sourceType=:ex:tb:::::Medium_oracleDBoperatorForK8sTake2&amp;SC=:ex:tb:::::Medium_oracleDBoperatorForK8sTake2&amp;pcode=">Sign up for a Free Tier account today!</a></p><h3>Join the conversation!</h3><p>If you’re curious about the goings-on of Oracle Developers in their natural habitat, come <a href="https://bit.ly/devrel_slack">join us on our public Slack channel</a>! We don’t mind being your fish bowl 🐠</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e0227ca7b7c3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/oracledevs/oracle-database-operator-for-kubernetes-take-2-e0227ca7b7c3">Oracle Database Operator for Kubernetes — Take 2</a> was originally published in <a href="https://medium.com/oracledevs">Oracle Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making Oracle Database Kubernetes-native]]></title>
            <link>https://medium.com/oracledevs/making-oracle-database-kubernetes-native-401233c02780?source=rss-66c52e475e23------2</link>
            <guid isPermaLink="false">https://medium.com/p/401233c02780</guid>
            <category><![CDATA[database]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[oracle-cloud]]></category>
            <category><![CDATA[operators]]></category>
            <dc:creator><![CDATA[Kuassi Mensah]]></dc:creator>
            <pubDate>Mon, 25 Oct 2021 21:15:01 GMT</pubDate>
            <atom:updated>2021-11-02T06:02:51.731Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/175/1*HXGmy05SbbdYIqEpN7zTfQ.png" /><figcaption>Oracle Database &amp; Operator Framework — GitHub</figcaption></figure><p>Kubernetes has become the most popular and ubiquitous open-source framework for automating Continuous Integration and Continuous Delivery (CI/CD) pipelines. Its core functionality coupled with Helm Charts (i.e., a package manager for template YAML files and other capabilities) manages the lifecycle of simple and stateless applications (i.e., define, install, deploy, and delete). Operators, on the other hand, extend Kubernetes’s core functionality with custom resources definitions (i.e., complex and stateful applications such as databases) and controllers that encapsulate the knowledge or business logic involved in managing the lifecycle of those custom resources.</p><p>Oracle is releasing the <a href="https://github.com/oracle/oracle-database-operator">Oracle Database Operator for Kubernetes</a> (a.k.a. <em>OraOperator</em>) which extends the Kubernetes API with custom resources definitions and controllers for automating Oracle Databases operations.</p><h3>What’s in OraOperator for Developers, DBAs, DevOps, and GitOps Teams?</h3><p>By making Oracle Databases operatable by Kubernetes similarly to its native objects, OraOperator helps developers, DBAs, DevOps and GitOps teams reduce the time and complexity of deploying and managing Oracle Databases. It eliminates the dependency on a human operator or administrator for the majority of database operations.</p><p>This first release supports Oracle Database deployed in and off Kubernetes clusters, more specifically: the Autonomous Databases in OCI (Shared infrastructure), these do not run in Kubernetes; containerized Single Instance Databases in the OCI Kubernetes Engine (OKE), and the Oracle Linux Cloud Native Environment (OLCNE); finally, containerized Oracle Sharded Databases in OKE and OLCNE.</p><p>Here is a brief description of the lifecycle operations supported by each controller.</p><h4>Managing Autonomous Databases with OraOperator</h4><p><a href="https://docs.oracle.com/en-us/iaas/Content/Database/Concepts/adboverview.htm">Oracle Autonomous Databases</a> (ADB) are currently deployed in the Oracle Cloud Infrastructure (OCI), not in a Kubernetes cluster.<br>In this release, the Autonomous Database controller supports all current workloads on shared OCI infrastructure (as opposed to dedicated infrastructure). The workloads include the Autonomous Transaction Processing (ATP), the Autonomous Data Warehouse (ADW), the Autonomous JSON Database (AJD), and Oracle APEX Application Development (APEX Service). <br>The ADB controller allows provisioning a new instance or binding the operator to an existing one, then the following operation can be performed: start, stop, terminate, delete, rename, scale-up/down (CPU, storage), enable/disable auto-scaling, download the wallet associated with the database instance (a regional wallet is an alternative choice), and manage the password of the database ADMIN user.</p><h4>Managing Containerized Single Instance Databases with OraOperator</h4><p><a href="https://docs.oracle.com/en/database/oracle/oracle-database/">Oracle Database Single Instance</a> (SIDB) are instances of either Standard Edition (SE), or Enterprise Edition (EE) databases. These can be containerized and deployed over a Kubernetes cluster (OKE and OLCNE as of this release) and managed by the operator.<br>The SIDB controller furnishes the following lifecycle operations: provision a new database instance, clone an existing instance, in-place or out-of-place patching to a higher release update, or rolling back to a lower release update.</p><h4>Managing Containerized Oracle Database Sharding with OraOperator</h4><p><a href="https://docs.oracle.com/en/database/oracle/oracle-database/21/shard/index.html">Oracle Database Sharding</a> (SDB) is made of a Catalog database, Global Data Services, and Shards (i.e., databases). All these (a.k.a. the Sharding Database topology) can be containerized and deployed as a Statefulset in a Kubernetes cluster (OKE and OLCNS as of this release) and managed by the Operator.<br>The SDB controller furnishes the following lifecycle operations: provision a Sharding Database topology, Shard scale up/down, Sharding Database topology cleanup.</p><h3>Security Considerations</h3><p>Kubernetes Secrets are the usual means for storing credentials or passwords. The operator reads the Secrets programmatically, which limits the exposure of sensitive data. However, Oracle strongly recommends that you set and get sensitive data from Oracle Cloud Infrastructure Vault, or from third-party Vaults.</p><p>The following YAML file fragment specifies Oracle Cloud Infrastructure Vault as the repository for the admin password.<br>adminPassword:<br> ociSecretOCID: ocid1.vaultsecret.oc1...</p><h3>Community Contribution</h3><p>Members of the Oracle database community who were briefed about this product are very excited about it. We are eager to incorporate suggestions and contributions.<br>See <a href="https://github.com/oracle/oracle-database-operator/blob/main/CONTRIBUTING.md">Contributing to this Repository</a></p><h3>Looking Forward …</h3><p>In upcoming releases, OraOperator will extend the capabilities of existing controllers, add support for more deployments in-and-off Kubernetes clusters, support for more Kubernetes clusters or equivalent platforms, and additional services.</p><p><strong>@kmensah </strong>and<strong> #OraOperator </strong>for notifications, questions, and discussions.</p><p>Thanks for reading.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=401233c02780" width="1" height="1" alt=""><hr><p><a href="https://medium.com/oracledevs/making-oracle-database-kubernetes-native-401233c02780">Making Oracle Database Kubernetes-native</a> was originally published in <a href="https://medium.com/oracledevs">Oracle Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>