App Lifecycle
Service: app-service · Port: 8112
Tantilium Cloud Runner (TCR) 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 TCR 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.