App Lifecycle
Service: app-service · Port: 8112
KubeOpera deploys applications without anyone writing YAML. You describe what your app is — its image, ports, resources, scaling and exposure — and the app service generates everything Kubernetes needs, following production best practices by default. app-controller commits the result to Git and Flux deploys it.
End-to-end flow
From Deploy to live
The four stages the Deploy Application wizard shows. Select a stage for details.
- You describe the app in the dashboard or through the API.
- kubeopera-api records it as a
KubeOperaAppresource. - app-controller asks the app service to generate manifests.
- app-controller commits them to Git and points Flux at them.
- Flux applies them in the tenant's vCluster.
What gets generated
From one app definition, the app service produces:
| Resource | When | Why |
|---|---|---|
Namespace | Always | Each app gets its own namespace. |
ServiceAccount | Always | A dedicated identity per app, with no extra permissions. |
Deployment | Always | Your containers, with resources, probes, environment and a safe rolling-update strategy. |
ConfigMap | When you set plain environment variables | Configuration, kept out of the pod spec. |
Service | When service.enabled | A stable in-cluster address (ClusterIP by default). |
Ingress | When ingress.enabled | External HTTPS access, with a cert-manager certificate when tls is on. |
HorizontalPodAutoscaler | When autoscaling.enabled | Scale on CPU (and memory, if set). |
PodDisruptionBudget | When running 2+ replicas | Stay available during node maintenance. |
NetworkPolicy | Always | Deny inbound traffic by default, and allow only what the app exposes. |
Defaults follow Kubernetes best practice: containers run as non-root with a read-only root filesystem where possible, resource requests are always set, and liveness and readiness probes are added for the app's port.
The app definition
{
"app": {
"name": "payments-api",
"namespace": "payments",
"type": "api",
"containers": [
{
"name": "payments-api",
"image": "registry.example.com/payments-api:v1.2.3",
"ports": [{ "containerPort": 8080 }],
"env": [
{ "name": "LOG_LEVEL", "value": "info" },
{ "name": "DB_PASSWORD", "valueFrom": { "secretKeyRef": { "name": "payments-db", "key": "password" } } }
],
"resources": {
"requests": { "cpu": "100m", "memory": "128Mi" },
"limits": { "cpu": "500m", "memory": "512Mi" }
},
"healthCheck": { "path": "/healthz" }
}
],
"service": { "enabled": true },
"ingress": { "enabled": true, "host": "payments.example.com", "tls": true },
"autoscaling": { "enabled": true, "minReplicas": 2, "maxReplicas": 10, "targetCPU": 70 }
}
}
| Field | Description |
|---|---|
name, namespace | The app's name and namespace. |
type | api, web, worker or job — sets sensible defaults (for example, workers get no Service or Ingress). |
containers[] | One or more containers: image, ports, environment, resources and health check. |
service | Whether to create a Service, and its type (ClusterIP or LoadBalancer). |
ingress | Whether to expose the app, its host and whether to use TLS. |
autoscaling | Replica bounds and target utilization. |
Preview the manifests
See exactly what KubeOpera will deploy before it does, with the preview endpoint:
curl -X POST http://app-service:8112/api/v1/preview \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d @payments-api.json
It returns multi-document YAML — the same manifests app-controller would commit. The dashboard's View manifests option on the Deploy wizard uses this endpoint.
Git and Flux
For each app, app-controller creates two Flux resources in the tenant's vCluster:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: payments-api-source
spec:
url: https://github.com/acme/fleet-repo
ref: { branch: main }
interval: 1m
secretRef: { name: fleet-git-credentials }
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: payments-api-sync
spec:
sourceRef: { kind: GitRepository, name: payments-api-source }
path: tenants/alice/apps/payments-api
targetNamespace: payments
prune: true
interval: 1m
The Git credentials Secret contains either ssh-privatekey (SSH) or password (an HTTPS access token).
Configuration
| Variable | Default | Description |
|---|---|---|
PORT | 8112 | HTTP port. |
AUTH_JWT_ACCESS_SECRET | — | Validates bearer tokens. |
DEFAULT_NETWORK_POLICY | deny-ingress | Default network policy for new apps (deny-ingress or none). |
The fleet repository, branch and Flux interval are configured on kubeopera-api.
Next steps
- App Creation Flow — deploy from the dashboard.
- app-controller — how definitions are reconciled.