Automated Oracle Database provisioning and schema management for feature branch development using Oracle Database Kubernetes Operator, GitHub Actions, Liquibase, and Kustomize.
This repository contains the complete implementation of an automated CI/CD pipeline that creates isolated Oracle Database instances for each feature branch, deploys schemas using Liquibase, and automatically cleans up resources when branches are deleted.
Read the full story: Database CI/CD with Oracle Database Kubernetes Operator, GitHub Actions, and Liquibase
Traditional database development workflows suffer from:
- Shared development databases causing conflicts between developers
- Manual database provisioning taking 2-3 days
- Inconsistent environments across development teams
- No automated cleanup of test databases
- Schema deployment inconsistencies
Automatically provision an isolated Oracle Database instance for every feature branch with:
- โ Automated database creation (15-20 minutes from branch creation to ready)
- โ Consistent schema deployment via Liquibase
- โ External access via LoadBalancer for connectivity
- โ Automatic cleanup when branches are deleted
- โ Configuration management using Kustomize
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ GitHub Repository โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Feature Branches โ โ
โ โ - feature/user-auth โ โ
โ โ - feature/payment-system โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ Triggers on push/delete
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ GitHub Actions Runner โ
โ - Authenticates with OCI โ
โ - Deploys database via Kustomize โ
โ - Runs Liquibase migrations โ
โ - Exposes via LoadBalancer โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โ kubectl apply
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Oracle Kubernetes Engine (OKE) Cluster โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Oracle Database Operator โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Namespace: feature-user-auth โ โ
โ โ - SingleInstanceDatabase CR โ โ
โ โ - Oracle Database Pod โ โ
โ โ - Services (ClusterIP + LoadBalancer)โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Namespace: feature-payment-system โ โ
โ โ - SingleInstanceDatabase CR โ โ
โ โ - Oracle Database Pod โ โ
โ โ - Services (ClusterIP + LoadBalancer)โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- Create: Triggered on feature branch creation
- Deploy: Automatic schema deployment via Liquibase
- Delete: Automatic cleanup on branch deletion
Each feature branch gets:
- Dedicated Kubernetes namespace
- Isolated Oracle Database instance
- Independent schemas and data
- OCI LoadBalancer for external access
- Enables Liquibase to run from GitHub Actions
- Provides connection strings for developer access
- Base configurations in
base/sidb-free-lite/ - Dynamic patching via Kustomize
- Environment-specific customization
- Oracle Cloud Infrastructure (OCI) account
- Oracle Kubernetes Engine (OKE) cluster
- Oracle Database Operator for Kubernetes installed
kubectlconfigured for your OKE cluster- OCI CLI configured with proper credentials
- Git
Configure the following secrets in your GitHub repository:
| Secret Name | Description |
|---|---|
OCI_USER_OCID |
OCI user OCID |
OCI_FINGERPRINT |
API key fingerprint |
OCI_TENANCY_OCID |
OCI tenancy OCID |
OCI_KEY_PRIVATE |
Private API key (PEM format) |
OCI_REGION |
OCI region (e.g., us-ashburn-1) |
OCI_CLUSTER_ID |
OKE cluster OCID |
FT_DEFAULT_ADMIN_PASSWORD |
Default admin password for databases |
git clone https://github.com/Kuassim/AiWorld.git
cd AiWorldEnsure Oracle Database Operator is installed:
kubectl get pods -n oracle-database-operator-systemNavigate to your repository's Settings โ Secrets and variables โ Actions, and add all required secrets.
Check the base database configuration:
cat base/sidb-free-lite/sidb-free-lite.yamlUpdate your database schemas in:
liquibase/admin/- System-level changesliquibase/user_service/- Application schemasliquibase/[other_services]/- Additional services
.
โโโ .github/
โ โโโ workflows/
โ โโโ deploy-to-oke.yml # Connecting to OKE
| |โโ create-db.yml # Database creation workflow
โ โโโ delete-db.yml # Database deletion workflow
โโโ base/
โ โโโ sidb-free-lite/
โ โโโ sidb-free-lite.yaml # Base database configuration
โโโ liquibase/
โ โโโ admin/
โ โ โโโ changelog.xml # System-level changes
โ โโโ user_service/
โ โ โโโ changelog.xml # User service schema
โ โโโ [other_services]/
โ โโโ changelog.xml # Additional service schemas
โโโ README.md
- Create a feature branch:
git checkout -b feature/my-new-feature- Push the branch:
git push -u origin feature/my-new-feature- Monitor the workflow:
- Navigate to Actions tab in GitHub
- Watch the "Create Oracle Database" workflow
- Wait 15-20 minutes for completion
- Get connection details:
- Check workflow output for external IP
- Connection string format:
jdbc:oracle:thin:@//<EXTERNAL_IP>:1521/FREEPDB1
# Using SQL*Plus
sqlplus system/<password>@//<EXTERNAL_IP>:1521/FREEPDB1
# Using SQLcl
sql system/<password>@//<EXTERNAL_IP>:1521/FREEPDB1Simply delete the branch:
git push origin --delete feature/my-new-featureThe workflow will automatically clean up all resources.
Triggered on push to feature/* branches:
- Configures OCI CLI and kubectl
- Handles stuck namespace cleanup (if needed)
- Creates namespace and secrets
- Deploys database using Kustomize
- Waits for database to be ready (8-12 minutes)
- Exposes database via LoadBalancer (2-3 minutes)
- Runs Liquibase migrations (system + schemas)
Triggered on branch deletion:
- Configures OCI CLI and kubectl
- Deletes the namespace
- Removes finalizers if namespace is stuck
- Cleans up all resources
Challenge: Securely authenticate kubectl from CI/CD
Solution: OCI CLI with dynamically generated fingerprints
Challenge: Dynamic resource naming per branch
Solution: JSON patches in kustomization.yaml
Challenge: Namespaces stuck in "Terminating" state
Solution: Remove finalizers from SingleInstanceDatabase CR
Challenge: Liquibase can't reach internal ClusterIP
Solution: Expose via OCI LoadBalancer with external IP
| Phase | Duration | Notes |
|---|---|---|
| Setup (OCI CLI & kubectl) | 45s | Downloads and configures tools |
| Force delete stuck namespace | 15s | Only if namespace exists |
| Create namespace & secrets | 5s | Fast Kubernetes operations |
| Deploy database with Kustomize | 30s | Manifest generation and apply |
| Wait for database ready | 8-12 min | Oracle DB initialization |
| Expose via LoadBalancer | 2-3 min | OCI Load Balancer provisioning |
| Liquibase: System setup | 30s | Create users and grants |
| Liquibase: Schema deployment | 1-2 min | Deploy tables and data |
| Total End-to-End | 15-20 min | From branch push to ready |
- Databases exposed via public LoadBalancer
- Suitable for development/test environments
- Credentials stored in GitHub Secrets
- Run Liquibase as Kubernetes Job (internal cluster access)
- Implement network policies to restrict database access
- Use OCI Vault for secret management
- Add TLS/SSL for database connections
- Restrict LoadBalancer access to specific IP ranges
- Run Liquibase as Kubernetes Job
- Add network policies for database access
- Migrate to OCI Vault for secrets
- Implement TLS/SSL connections
- Automated backups before schema changes
- Prometheus metrics for database health
- Cost tracking per feature branch
- Slack notifications for deployment status
- Database seeding with realistic test data
- Schema diff tool (compare to main)
- Direct kubectl access for troubleshooting
- Rollback capability for schema changes
- Blog Post: Full implementation story
- Oracle Database Operator: GitHub
- Liquibase: Documentation
- Kustomize: Documentation
Initial version by Norman Aberin's blog post on Oracle DB Operator CI/CD.
Copyright (c) 2023 Oracle and/or its affiliates. Released under the Universal Permissive License v1.0 as shown at https://oss.oracle.com/licenses/upl/.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Blog: Read the full article
For questions or feedback, please open an issue or reach out through GitHub.
Built with โค๏ธ using Oracle Database Kubernetes Operator, GitHub Actions, Liquibase, and Kustomize