Skip to main content
Version: 1.0

App Creation Flow

This page walks through what actually happens between submitting the Deploy Application Wizard and having a live, reachable app. An earlier version of this page described a much more elaborate flow — per-app provisioning of a new AWS EKS/GCP GKE/OCI OKE cluster, Cloud Native Buildpacks, Trivy image scanning, ArgoCD, multi-region active-active failover — none of which exists in KubeOpera today. The real platform is simpler and more specific than that: every tenant deploys into their own vCluster, a lightweight virtual Kubernetes control plane sharing one real, already-provisioned host cluster — there's no per-app cloud infrastructure to stand up, which is exactly what makes a deploy take minutes rather than the 5–15 the old version of this page described.

From Deploy to live

The four stages the Deploy Application wizard shows. Select a stage for details.

Select a stage to see what happens behind it.

Two sources, one deploy path after that​

The wizard supports two ways to get an image running: an existing container image in a registry (public or private), or a GitHub repository, which triggers a real build before deploying. Both converge on the same mechanism from that point on — see Basic Operations for the tenant-facing walkthrough of this.

Container image. You supply a registry image reference (and, for a private registry, credentials) and KubeOpera deploys it directly — no build step.

GitHub repository. build-service runs a Kaniko build Job in the host cluster's dedicated kubeopera-builds namespace, using the Dockerfile path and build context you specify, then pushes the resulting image to KubeOpera's own self-hosted, per-tenant-isolated registry. Once the push succeeds, the wizard hands the resulting image reference into the exact same deploy path a registry-image deploy uses — a build never gets its own separate deployment mechanism. See Build Service for how the build itself works, and KubeOpera API for the registry-credential isolation model.

Deploying: what actually runs​

  1. Write desired state. The app's configuration (image, port, environment variables, resource requests/limits, autoscaling, domain, TLS) is written to the KubeOperaApp custom resource.
  2. Generate manifests. app-controller reconciles the CR: it calls app-service to turn the schema into real Kubernetes YAML (Deployment, Service, Ingress, Namespace, and anything else the schema calls for), then pushes those manifests to a Git repository — the fleet repo that GitOps reconciles from.
  3. Flux syncs inside your vCluster — not the host cluster. A GitRepository/Kustomization pair inside your own vCluster picks up the commit and applies it there. This is why deleting an app later genuinely tears down everything it created, rather than just removing a database row — and why a tenant's Pods/Deployments live inside their own vCluster, never the shared host cluster's namespaces.
  4. Ingress and TLS. When TLS is enabled (the default), the generated Ingress carries a cert-manager.io/cluster-issuer annotation for letsencrypt-prod-dns — a DNS-01 challenge against Route53, not HTTP-01. Because this Ingress is inside the vCluster, vCluster's own sync.toHost.ingresses config carries it to the host cluster automatically, where the real, already-running letsencrypt-prod-dns ClusterIssuer and external-dns take over with no per-app infrastructure work.
  5. Subdomain. The app's hostname is computed server-side, not client-supplied: <app>-<cloudspace-slug>.apps.kubeopera.io, a subdomain of the already-DNS-01-enabled kubeopera.io zone.

The wizard's progress view is a real reachability check, not a timer​

The wizard polls GET /apps/{id}/deploy-status, which composes three real signals — GitOps sync phase, live Pod/Deployment readiness (read from inside your vCluster), and, only once both look healthy, an actual outbound HTTPS request from kubeopera-api against the app's own computed subdomain. The "View live app" link only appears once that request genuinely succeeds — the wizard doesn't guess.

In practice, the dominant source of wait time on a fresh TLS-enabled deploy is cert-manager's own DNS-01 challenge — Route53 TXT record propagation plus Let's Encrypt's own validation step — measured at roughly 150–170 seconds from "Deployment ready" to "reachable," comfortably inside the wizard's poll timeout. A registry-only deploy with TLS disabled reaches "reachable" much faster, since there's no certificate to issue.

What the wizard collects​

FieldNotes
NameUsed to derive the app's namespace and computed subdomain
SourceContainer image, or a GitHub repo (Dockerfile path + build context)
Registry credentialsOptional — only needed for a private image or base image
Target vClusterOnly shown when a Cloud Space owns more than one vCluster; auto-selected otherwise
PortContainer port the app listens on
Environment variablesPlain values or references to an existing Secret
ResourcesCPU/memory requests and limits
AutoscalingOptional min/max replicas and CPU threshold
TLSOn by default; when enabled, the generated Ingress requests a real cert as described above

API reference​

The application endpoints described above (POST/GET/PUT/DELETE /apps, GET /apps/{id}/deploy-status, /logs, /pods, /events) are documented in full, with real request/response shapes, on the KubeOpera API page — this page intentionally doesn't duplicate that table, to avoid the two drifting apart.

What this page no longer claims​

For anyone who read an earlier version of this page: KubeOpera does not provision a new cloud cluster per app, does not use Cloud Native Buildpacks or Trivy scanning, does not offer SAML or a choice between Flux and ArgoCD, and doesn't publish a disaster-recovery SLA (RTO/RPO/MTTR figures). Those described a different, more generic platform than the one that exists today. If any of that functionality gets built for real, this page is the right place to document it.