Architecture overview
Decision Control is a stateless Spring Boot application. A namespace deployment consists of:
PostgreSQL is assumed to exist already, reachable from the namespace (managed service, an operator-provisioned instance, or a database in another namespace).
Namespace
ConfigMap
Secret
Deployment
Service
Ingress (Kubernetes)
https://dc.example.com/auth/callback.
Database connectivity
- Point
SPRING_DATASOURCE_URLat the database’s in-cluster service DNS or external endpoint. - For TLS, append SSL parameters to the URL and mount the CA — see Database Configuration.
- First rollout against an empty database: set
HIBERNATE_DDL_AUTO=update, then switch tovalidateand re-apply.
OpenShift specifics
- Replace the
Ingresswith aRoute:
- The image runs as non-root and is compatible with the default
restricted-v2SCC. Do not grantanyuid. - Use
ImageStreamsif your registry workflow relies on them; otherwise reference the image directly.
High availability
- Decision Control is stateless — scale horizontally by raising
replicas. All state lives in PostgreSQL. - The OIDC flow uses stateless tokens, so no session affinity is required.
- Size the database connection pool and PostgreSQL
max_connectionsfor the total replica count.
Diagnostics
For diagnostics that require a shell, the Decision Control image is distroless and ships no shell of its own. Use
kubectl debug with a container image your organization trusts (an ephemeral debug container targeting the pod), or run the diagnostic command from a separate pod in the same namespace.
Updating configuration
ConfigMap and Secret changes are not picked up by running pods. After editing either, restart the Deployment to roll the change forward:Deployment) use the rolling update strategy without manual intervention — kubectl set image triggers the rollout. Provider envs, secrets, and TLS material continue to be sourced from the existing ConfigMap and Secret.
For scaling decisions, see the High availability note above. kubectl scale deployment/decision-control --replicas=N works as expected once the prerequisites (stateless auth and a DB pool sized for the total replica count) are satisfied.
Monitoring and observability
Decision Control exposes the standard Spring Boot Actuator endpoints. The default exposed set ishealth, info, metrics, and prometheus — adjust via ACTUATOR_ENDPOINTS if your stack requires a different list.
Liveness and readiness
The Kubernetes probes consume the same/actuator/health endpoint as documented in Container Configuration. A healthy pod returns HTTP 200 with body:
readinessProbe and livenessProbe against this endpoint with conservative initial-delay and failure-threshold values. Tighten them only after measuring real boot times for your image and JVM.
Prometheus
AServiceMonitor scrapes the application directly when you run the Prometheus Operator. The example below assumes the Service is decision-control exposing the default Spring Boot port:
prometheus.io/scrape: "true" pod annotation pattern; the path is the same.
Logs
Decision Control writes JSON-structured logs to stdout. Stream them withkubectl logs; pipe to your log-aggregation stack (Loki, ELK, Datadog) the same way as any other Spring Boot service in the cluster.
LOGGING_LEVEL_* env variables (Spring’s standard mechanism). Set them on the ConfigMap and roll the Deployment; remove the override before normal operation to avoid log-volume cost.
Troubleshooting
Common failure modes and where to look:Pod stuck in ImagePullBackOff
Verify the image-pull Secret in the same namespace as the Deployment is the one referenced by imagePullSecrets, and that the registry credentials are still valid. The Aletyx portal lets you reissue an API token without revoking the previous one — useful for rotating without downtime.
Pod stuck in CrashLoopBackOff
Read the pod logs — kubectl logs <pod> -n <namespace> --previous shows the last crash even after restart. The two most common causes:
HIBERNATE_DDL_AUTO=validateagainst a stale schema after a major image bump that added tables. Either run a migration manually or temporarily switch toupdate(then revert).401against/actuator/healthbecause the probe is going through the OIDC filter. The health endpoint must be unauthenticated; if the path is filtered behind auth, the probe will 401 and Kubernetes will restart the pod.
Pod stuck in Pending
The scheduler has no node that fits the pod. Inspect with kubectl describe pod — the events line at the bottom names the constraint (resource shortfall, taint, PVC binding, etc.).
Database connection failures
Test reachability from inside the namespace before suspecting application config:SPRING_DATASOURCE_* env values match what the netcheck used.
Ingress / Route returns 404 or 503
Verify the Ingress / Route is matched by the controller (kubectl get ingress -A shows the address); then verify TLS termination:
503 typically means the Service has no Ready endpoints — i.e. the upstream Deployment is not Running. A 404 from the controller (rather than the application) means the host header doesn’t match a known Ingress.