Deploy on Oracle Kubernetes Engine (OKE)
The reference-validated knext deployment path — OKE with OCI Object Storage (S3-compatible) and the Kourier ingress-class fix.
OKE has been validated end-to-end with scale-to-zero and bytecode caching verified on a live cluster, so this guide is a tested path. The general control-plane install is on Operator & the NextApp CRD; the prerequisites and config walkthrough are in Getting started. This page covers only the OCI-specific pieces.
1 · Create the cluster
Create an OKE cluster (managed nodes), then fetch a kubeconfig. OKE kubeconfigs use the OCI CLI's
session-token auth — the kubeconfig invokes oci ce cluster generate-token, so the OCI CLI
must be installed and authenticated on whoever runs kubectl:
oci ce cluster create-kubeconfig \
--cluster-id <cluster-ocid> \
--file ~/.kube/config \
--region <region> \
--token-version 2.0.0knext itself needs no persistent volume — its compile cache is baked into the image. Stateful
components you run alongside it (Postgres, Redis) need a StorageClass that provisions writable
volumes. On OKE the OCI Block Volume provisioner ships as the oci-bv StorageClass:
kubectl get storageclass oci-bv2 · Install Knative, Kourier, cert-manager, and the operator
Follow Operator & the NextApp CRD for the one-command bundle install. The prerequisites — Knative Serving + Kourier, cert-manager, and a StorageClass — are listed in Getting started.
The Kourier ingress-class is the OKE gotcha. If knext apps are unreachable through the ingress,
the cause is usually that Knative Serving's config-network ConfigMap (namespace
knative-serving) left ingress-class unset, so Serving never programmed routes against
Kourier. The operator's install bundle ships a declarative config-network ConfigMap that pins
ingress-class: kourier.ingress.networking.knative.dev (the full controller-qualified form — the
short kourier.knative.dev form does not match and leaves routes unprogrammed). Apply the
bundle with kubectl apply --server-side so this ConfigMap merges into the one Knative Serving
owns rather than clobbering it.
3 · Storage — OCI Object Storage via the s3 provider
knext storage accepts gcs, s3, minio, and azure (see
Multi-cloud deploy). OCI Object Storage exposes an S3-compatible endpoint,
so use provider: 's3' with the OCI S3-compat endpoint and a Customer Secret Key (an
S3-compatible access-key/secret pair you generate against your OCI user).
The OCI S3-compat endpoint format is:
https://<namespace>.compat.objectstorage.<region>.oraclecloud.comwhere <namespace> is your tenancy's Object Storage namespace. Alternatively, run self-hosted
MinIO in-cluster and use provider: 'minio'.
4 · Cache — Redis
ISR / data cache uses Redis (cache.provider: 'redis'). Point cache.url at OCI Cache (managed
Redis) or a self-hosted Redis Service. cache.url is required when the provider is redis.
5 · Registry — OCIR
Push the app image to OCI Registry (OCIR), e.g.
<region-key>.ocir.io/<tenancy-namespace>/<repo>. The operator rejects any image that is not
digest-pinned (@sha256:…); knext deploy resolves the digest automatically.
6 · Complete knext.config.ts
import type { KnativeNextConfig } from '@getknext/core';
const config: KnativeNextConfig = {
name: 'acme',
registry: '<region-key>.ocir.io/<tenancy-namespace>/acme',
storage: {
provider: 's3', // OCI Object Storage is S3-compatible
bucket: 'acme-assets',
region: '<region>', // e.g. us-ashburn-1
endpoint:
'https://<namespace>.compat.objectstorage.<region>.oraclecloud.com',
publicUrl:
'https://<namespace>.compat.objectstorage.<region>.oraclecloud.com/acme-assets',
// S3-compatible access key / secret (an OCI Customer Secret Key). Prefer
// injecting these via env/Secrets rather than committing them.
accessKey: process.env.OCI_S3_ACCESS_KEY,
secretKey: process.env.OCI_S3_SECRET_KEY,
},
cache: {
provider: 'redis',
url: process.env.REDIS_URL || 'redis://acme-redis.default.svc.cluster.local.:6379',
keyPrefix: 'acme',
},
scaling: { minScale: 0, maxScale: 20 }, // minScale 0 = scale to zero
};
export default config;7 · Deploy and verify scale-to-zero
knext deploy --registry <region-key>.ocir.io/<tenancy-namespace>/acmeknext deploy builds the standalone image, pushes it (resolving the digest), and applies the
NextApp CR; the operator reconciles it into a Knative Service. Confirm the service scales to zero
when idle:
# After the idle window, the app's pods should be gone:
kubectl get pods -l serving.knative.dev/service=acme
# (no resources) — the ksvc scaled to zero
# The next request cold-starts a pod; the URL resolves either way:
kubectl get ksvc acme -o jsonpath='{.status.url}'A cold request reprovisions a pod; the compile cache baked into your image shortens that cold start
by reusing precompiled bytecode (the Bun executable's own, or V8's compile cache with runtime: 'node') — no configuration needed. (The older opt-in
volume-backed cache has been removed.) See Bytecode caching and
Scale to zero.