An OCI VisionAI Service and Cloud-navtive Pipeline
Migrating Serverless Applications to OCI: End-to-End AI Vision Pipeline
I’ve been working on this project for some time, and I’m excited to finally share it with you. This post also serves as a preview of my upcoming session at Oracle CloudWorld / AI World — Strategies for Migrating Serverless Applications to OCI [SHO1222] — where I’ll be co-presenting with my colleagues Tom Moore and Shadai Williams on October 15th 2025.
👉 Session link here.
If you’ve ever wondered how to stitch together OCI Functions, Object Storage, AI Vision, and Autonomous Database into a practical serverless architecture — this tutorial is for you.
Why This Matters (Use Cases)
The architecture we’ll build shows how build an end-to-end serverless pipeline in OCI and taking advantage of event-driven services and resource principals for secure, low-maintenance operation. Example use cases:
- 📷 Image analysis pipelines: Auto-tagging, object detection, and metadata enrichment for uploaded files.
- 🏢 Enterprise workflows: Automating back-office tasks like claims processing or inventory audits.
- 🎓 Education & research: Students uploading images and receiving AI-assisted analysis through a web portal.
- ⚡ Modernization: Re-platforming serverless apps from other clouds into OCI with Terraform-based automation.
Project Overview
At a high level, this pipeline delivers an end-to-end serverless app on OCI:
- A Flask web UI uploads images to Object Storage.
- When new files arrive, an OCI Function runs AI Vision object detection.
- The JSON output is persisted in Autonomous JSON Database via ORDS REST APIs.
- The results are rendered back in the web app dashboard.
Repository Layout
The GitHub repo (link coming soon 👀) provides everything you need:
- app/ # Flask web application (UI + APIs)
- vision_function/ # Fn handler for AI Vision
- main.tf # Terraform for full infra provisioning
- terraform.tfvars.example
- Dockerfile # Build Flask container image
Step 1: Provision OCI Resources with Terraform
While there’s a lot in step one I’m confident that once you have everything necessary you’ll be up and running in no time.
1a: Get an OCI account
You’ll need an Oracle Cloud Infrastructure account. If you don’t have one, sign up for a Free Tier:
https://www.oracle.com/cloud/free/
Tip: the Free Tier is enough to follow along and understand the workflow. Some services may require paid limits for production scale.
1b: Install the necessary dependencies
-
OCI CLI (used to sanity-check your credentials and environment)
Docs: https://docs.oracle.com/en-us/iaas/Content/API/Concepts/cliconcepts.htm -
Podman or Docker (to build/push the Flask web app image and the vision function image)
Either works. Use whichever you prefer or already have installed. -
Terraform (with OCI provider)
Guide: https://developer.hashicorp.com/terraform/tutorials/oci-get-started
Quick checks:
oci -v docker --version # or: podman --version terraform -version
1c: Collect the values you’ll put in terraform.tfvars
You’ll create an API key for your user and copy a few identifiers from the Console. Here’s exactly what you need and where to find each item:
-
tenancy_ocid– Tenancy OCID- Console: click your avatar (top right) → Tenancy:
→ Tenancy OCID → Copy.
- Console: click your avatar (top right) → Tenancy:
-
user_ocid– User OCID- Console: click your avatar → User settings → OCID → Copy.
-
fingerprint– API key fingerprint for your user- Console: User settings → API Keys → Add API Key → choose Paste Public Key (see key generation below) → after adding, copy the Fingerprint shown in the table.
-
private_key_path– Local path to your API key’s private key- You’ll store the private key on your machine (e.g.,
~/.oci/oci_api_key.pem).
- You’ll store the private key on your machine (e.g.,
-
region– Your home region code (e.g.,us-ashburn-1,ca-toronto-1, etc.)- Console: top-nav region selector shows your current region’s code.
- (Optional) CLI list:
oci iam region list --query "data[].name" --raw-output
-
compartment_ocid– Target compartment OCID- Console: Identity & Security → Compartments → pick (or create) a compartment → Copy OCID.
Generate an API key pair (one-time)
If you don’t already have an OCI API key for your user:
mkdir -p ~/.oci
openssl genrsa -out ~/.oci/oci_api_key.pem 2048
openssl rsa -pubout -in ~/.oci/oci_api_key.pem -out ~/.oci/oci_api_key_public.pem
chmod 600 ~/.oci/oci_api_key.pem
1d: Create and fill in terraform.tfvars file
Copy the template below into a new file named terraform.tfvars in the repo root and replace the placeholder values with the ones you collected above.
# Copy this file to terraform.tfvars and fill in your values
# Find these values in the OCI Console:
tenancy_ocid = "ocid1.tenancy.oc1..aaaaaaaa..." # Console → Tenancy Information
user_ocid = "ocid1.user.oc1..aaaaaaaa..." # Console → User Settings
fingerprint = "xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx" # Console → User → API Keys → Fingerprint
private_key_path = "~/.oci/oci_api_key.pem" # Local path to your private key
region = "ca-toronto-1" # e.g., us-ashburn-1, ca-toronto-1
compartment_ocid = "ocid1.compartment.oc1..aaaaaaaa..." # Identity & Security → Compartments
1d Verify and Proceed
Run Terraform from the repo root:
terraform init
terraform plan # should succeed and show the resources to be created
If plan succeeds, you’re ready for terraform apply in the next step of the tutorial.
If you hit auth or permission errors:
- Re-check the fingerprint and private key path.
- Confirm your user has permission to manage resources in the chosen compartment (IAM policies).
- Make sure the region string exactly matches the Console (e.g., us-ashburn-1).
Here’s a simplified version of the Terraform configuration (main.tf):
provider "oci" {
region = var.region
}
resource "oci_objectstorage_bucket" "images" {
compartment_id = var.compartment_ocid
name = "image-uploads"
namespace = data.oci_objectstorage_namespace.ns.namespace
storage_tier = "Standard"
}
resource "oci_database_autonomous_database" "json_db" {
compartment_id = var.compartment_ocid
db_name = "JSONDB"
display_name = "Autonomous JSON DB"
workload = "AJD"
data_storage_size_in_tbs = 1
cpu_core_count = 1
is_free_tier = true
}
This config creates an Object Storage bucket and an Autonomous JSON Database. The full repo includes networking, Vault, Fn application, container instance, and a public load balancer.
Step 2: Build the Flask Web App
The Flask app lets users upload images and view AI Vision results.
# app/app.py
from flask import Flask, request, render_template
import oci
import requests, json, os
app = Flask(__name__)
# OCI resource principal signer
signer = oci.auth.signers.get_resource_principals_signer()
object_storage_client = oci.object_storage.ObjectStorageClient(config={}, signer=signer)
@app.route("/", methods=["GET", "POST"])
def upload():
if request.method == "POST":
file = request.files["file"]
object_storage_client.put_object(
"my-namespace",
"image-uploads",
file.filename,
file
)
return render_template("index.html")
The app uploads images into Object Storage and lists results from the Autonomous JSON Database via ORDS.
Step 3: Serverless AI Vision Function
The function is triggered automatically when a new file lands in Object Storage.
# vision_function/func.py
import io, json, oci
def handler(ctx, data: io.BytesIO = None):
signer = oci.auth.signers.get_resource_principals_signer()
vision_client = oci.ai_vision.AIServiceVisionClient(config={}, signer=signer)
obj_storage_client = oci.object_storage.ObjectStorageClient(config={}, signer=signer)
evt = json.loads(data.getvalue())
bucket = evt["data"]["resourceName"].split("buckets/")[1].split("/")[0]
name = evt["data"]["resourceName"].split("/")[-1]
# Run AI Vision
resp = vision_client.analyze_image(
analyze_image_details=oci.ai_vision.models.AnalyzeImageDetails(
features=[oci.ai_vision.models.ImageObjectDetectionFeature()],
image=oci.ai_vision.models.ImageObjectStorageUri(
source_uri=f"oci://{bucket}@namespace/{name}"
)
)
)
detections = [obj.name for obj in resp.data.image_objects]
# Persist via ORDS
ords_url = os.environ["ORDS_URL"]
payload = {"file": name, "detections": detections}
requests.post(ords_url, auth=("user","pass"), json=payload)
return {"status": "success", "detections": detections}
This uses AI Vision Object Detection and stores structured results in the JSON database.
Step 4: Connect Autonomous JSON Database via ORDS
No wallet, no drivers — just REST APIs.
Example insert via curl:
curl -u $DB_USER:$DB_PASS \
-X POST $ORDS_URL/IMAGE_ANALYSIS/ \
-H "Content-Type: application/json" \
-d '{"file":"example.png","detections":["cat","sofa"]}'
Step 5: Deploy and Test
- Build and push your Flask container to OCIR:
docker build -t <region>.ocir.io/<tenancy>/flask-app .
docker push <region>.ocir.io/<tenancy>/flask-app
- Apply Terraform:
terraform init
terraform apply
Closing
This project is more than a tutorial — it’s a pattern for migrating serverless apps into OCI, using Terraform for repeatability and OCI’s cloud-native services for scale and security.
I’ll go deeper into strategies, migration considerations, and live demos during my CloudWorld session on October 15th. 👉 Join me here .
Stay tuned for the GitHub repo drop — and let me know if you try the pipeline. 🚀