|
1 | | -# OBaas Sample App Chart |
| 1 | +# OBaaS Sample Application Helm Chart |
2 | 2 |
|
3 | | -This chart provides an extensible sample for applications running on [OBaaS](https://oracle.github.io/microservices-datadriven/obaas/). |
| 3 | +Deploying microservices to Kubernetes typically means maintaining separate Helm charts for Spring Boot and Helidon applications, or worse—writing framework-specific conditional logic throughout your application code. This chart takes a different approach: **one chart, one parameter, automatic configuration**. |
4 | 4 |
|
5 | | -To use this chart for a given application, download the chart and update the [Chart.name](./Chart.yaml) value to your application's name. |
| 5 | +Whether you're building with Spring Boot or Helidon, this chart automatically wires up database connections, service discovery, health checks, and observability—all based on a single `framework` parameter in your values file. |
6 | 6 |
|
7 | | -## Customizing the chart |
| 7 | +## How It Works |
8 | 8 |
|
9 | | -The OBaaS sample app chart is meant to serve as a developer template, and is fully customizable. |
| 9 | +The chart uses Helm's templating engine to detect your framework choice and inject the appropriate environment variables, probe configurations, and metrics endpoints. When you deploy a Helidon application, you get `/health/live` probes and MicroProfile-style datasource configuration. Choose Spring Boot instead, and you automatically get `/actuator/health/liveness` endpoints and Spring-style environment variables. |
10 | 10 |
|
11 | | -Standard parameters for Kubernetes options like node affinity, HPAs, ingress and more are provided in the [values.yaml file](./values.yaml). |
| 11 | +Behind the scenes, the deployment template queries your OBaaS platform's ConfigMaps to retrieve Eureka URLs, SigNoz collector endpoints, and other platform-wide settings. This means you never hardcode connection strings or service endpoints—everything adapts to your environment automatically. |
12 | 12 |
|
13 | | -## OBaaS options |
| 13 | +Your application pods start with their Oracle Autonomous Database wallet already mounted at `/oracle/tnsadmin`, database credentials injected from Kubernetes secrets, and OpenTelemetry configured to push metrics to SigNoz. Service discovery happens automatically if you enable Eureka, and health probes use the correct endpoints for your framework. |
14 | 14 |
|
15 | | -Within the [values.yaml file](./values.yaml), the `obaas` key allows chart developers to enable or disable OBaaS integrations like database connectivity, OpenTelemetry, MicroProfile LRA, SpringBoot, and Eureka. |
16 | | -enabled: true |
| 15 | +## What You Get |
| 16 | + |
| 17 | +This chart eliminates configuration boilerplate by automatically setting up: |
| 18 | + |
| 19 | +- **Framework-appropriate health checks**: The right probe paths for Spring Boot (`/actuator/health/*`) or Helidon (`/health/*`) |
| 20 | +- **Database integration**: Wallet mounting, connection string injection, and framework-specific datasource configuration |
| 21 | +- **Service discovery**: Eureka registration with hostname and zone settings pulled from your OBaaS platform |
| 22 | +- **Observability**: OpenTelemetry integration pushing metrics, traces, and logs to SigNoz, plus Prometheus scraping annotations |
| 23 | +- **Production readiness**: Resource limits, horizontal pod autoscaling, and configurable probe timings |
| 24 | + |
| 25 | +The deployment template includes over 150 lines of framework-specific environment variable configuration, all selected automatically based on your choice. Spring Boot applications receive `SPRING_DATASOURCE_*` variables and Spring Cloud Config integration. Helidon applications get MicroProfile Config-style `javax.sql.DataSource.*` properties and explicit OTLP protocol settings to work around Helidon's OpenTelemetry quirks. |
| 26 | + |
| 27 | +## Before You Begin |
| 28 | + |
| 29 | +Your Kubernetes cluster needs an OBaaS installation before this chart can render templates. The chart uses Helm's `lookup` function to retrieve platform configuration from ConfigMaps, which means you can't fully render templates without a live cluster connection. Verify your platform is ready: |
| 30 | + |
| 31 | +```bash |
| 32 | +kubectl get configmap obaas-config -n <obaas-namespace> |
| 33 | +kubectl get configmap obaas-observability-config -n <obaas-namespace> |
| 34 | +``` |
| 35 | + |
| 36 | +You'll also need three secrets in your target namespace: database credentials (username, password, and service name), an Autonomous Database wallet (the ZIP file from OCI Console, unzipped), and optionally an image pull secret for private registries. |
| 37 | + |
| 38 | +For database credentials, create a generic secret with keys `db.username`, `db.password`, and `db.service` (the TNS service name from your wallet's `tnsnames.ora`). Spring Boot applications using Liquibase for schema migrations need two additional keys: `db.lb_username` and `db.lb_password` for the admin user. |
| 39 | + |
| 40 | +The wallet secret should contain all files from your ADB wallet ZIP—`tnsnames.ora`, `sqlnet.ora`, `cwallet.sso`, and the various keystore files. The chart mounts this secret as a volume at `/oracle/tnsadmin`, and the JDBC connection string references this path automatically. |
| 41 | + |
| 42 | +## Getting Started |
| 43 | + |
| 44 | +Start by creating a custom values file for your application. The chart's default `values.yaml` contains placeholders with `TODO` comments marking required changes. Copy it and fill in your specifics: |
| 45 | + |
| 46 | +```yaml |
| 47 | +image: |
| 48 | + repository: "us-ashburn-1.ocir.io/mytenancy/customer-helidon" |
| 49 | + tag: "1.0.0" |
| 50 | + |
| 51 | +imagePullSecrets: |
| 52 | + - name: ocir |
| 53 | + |
| 54 | +fullnameOverride: "customer" |
| 55 | + |
| 56 | +obaas: |
| 57 | + namespace: obaas-dev |
| 58 | + framework: HELIDON # or SPRING_BOOT |
| 59 | + |
| 60 | + database: |
| 61 | + credentialsSecret: customer-db-secret |
| 62 | + walletSecret: dev-adb-wallet |
| 63 | + |
| 64 | + helidon: |
| 65 | + enabled: true |
| 66 | + datasource: |
| 67 | + name: "customer" |
| 68 | + otel: |
| 69 | + serviceName: "customer" |
| 70 | + |
| 71 | + eureka: |
| 72 | + enabled: true |
| 73 | + |
| 74 | + otel: |
| 75 | + enabled: true |
| 76 | +``` |
| 77 | +
|
| 78 | +Notice the `obaas.helidon.datasource.name` and `obaas.helidon.otel.serviceName` settings. These are **critical** for Helidon deployments—the datasource name must match your application's `microprofile-config.properties`, and the OTEL service name must match your `otel.service.name` property. Mismatches cause runtime "DataSource not found" errors or metrics appearing under the wrong service in SigNoz. |
| 79 | + |
| 80 | +Spring Boot deployments are simpler because Spring's convention-over-configuration approach means fewer explicit mappings. Just set `framework: SPRING_BOOT`, enable `obaas.springboot.enabled: true`, and the chart handles the rest. |
| 81 | + |
| 82 | +Deploy with Helm: |
| 83 | + |
| 84 | +```bash |
| 85 | +helm install customer ./obaas-sample-app \ |
| 86 | + -f values-customer.yaml \ |
| 87 | + -n your-namespace \ |
| 88 | + --create-namespace |
| 89 | +``` |
| 90 | + |
| 91 | +Check that your pod starts successfully: |
| 92 | + |
| 93 | +```bash |
| 94 | +kubectl get pods -n your-namespace |
| 95 | +kubectl logs -f deployment/customer -n your-namespace |
| 96 | +``` |
| 97 | + |
| 98 | +If you see connection errors, verify your secrets exist and contain the correct keys. Database authentication failures usually mean typos in `db.username` or `db.password`. TNS resolution errors mean `db.service` doesn't match an entry in your wallet's `tnsnames.ora`. |
| 99 | + |
| 100 | +## Framework Differences That Matter |
| 101 | + |
| 102 | +Spring Boot and Helidon have different conventions for database configuration, health checks, and metrics. The chart handles these differences automatically, but understanding them helps when troubleshooting. |
| 103 | + |
| 104 | +**Spring Boot** uses Spring Data JPA and Spring Boot Actuator. Database settings go in `SPRING_DATASOURCE_*` environment variables, and Spring automatically configures connection pooling. Health endpoints appear under `/actuator/health/`, and metrics use Micrometer with Prometheus export at `/actuator/prometheus`. Eureka integration happens through Spring Cloud Netflix, with service registration managed by Spring's `@EnableDiscoveryClient` annotation. |
| 105 | + |
| 106 | +**Helidon** follows the MicroProfile specification. Database configuration uses `javax.sql.DataSource.<name>.*` properties where the name maps to your application's datasource bean. Helidon doesn't auto-configure datasources like Spring does—you must explicitly match the datasource name between your `microprofile-config.properties` and your Helm values. Health endpoints are simpler paths: `/health/live` and `/health/ready`. Metrics follow MicroProfile Metrics at `/metrics`, and OpenTelemetry requires explicit protocol configuration (`http/protobuf` instead of gRPC) to work with SigNoz. |
| 107 | + |
| 108 | +Resource-wise, Helidon is lighter. A typical Helidon microservice idles around 200-350 MB of memory and starts in 3-8 seconds, compared to Spring Boot's 350-500 MB and 8-15 second startup. Production Helidon deployments can run comfortably with 100m CPU and 256 Mi memory requests, while Spring Boot typically needs 250m CPU and 512 Mi to avoid throttling under load. |
| 109 | + |
| 110 | +## Observability and Debugging |
| 111 | + |
| 112 | +Every pod deployed by this chart includes OpenTelemetry integration pushing metrics to your OBaaS platform's SigNoz installation. Metrics flow two ways: OTLP push (the pod actively sends metrics via HTTP) and Prometheus scraping (SigNoz pulls from your `/metrics` endpoint). The chart sets pod annotations (`signoz.io/scrape: "true"`) to enable scraping and injects OTEL environment variables for push. |
| 113 | + |
| 114 | +Helidon has a quirk: it defaults to gRPC for OTLP, which doesn't work with many SigNoz installations. The chart works around this by explicitly setting `OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf` and enabling Java's global OpenTelemetry auto-configuration via `JAVA_TOOL_OPTIONS`. Without these settings, you'll see "failed to export" errors in your logs and metrics won't appear in SigNoz. |
| 115 | + |
| 116 | +When metrics don't show up in SigNoz, the debugging process is straightforward. Port-forward to your pod and curl the metrics endpoint directly—if it returns data, the problem is with OTEL export or scraping configuration. If it returns a 404, your application isn't exposing metrics correctly. Check that Spring Boot Actuator is enabled or Helidon Metrics is in your dependencies. |
| 117 | + |
| 118 | +Query SigNoz metrics using Kubernetes metadata filters. Metrics are tagged with `k8s_pod_name` (includes your Helm release name), `k8s_namespace_name`, and `service_name`. The service name comes from your OTEL configuration for Helidon applications, or defaults to "signoz-scraper" for Prometheus-scraped metrics from Spring Boot. |
| 119 | + |
| 120 | +Health probe failures usually mean one of two things: slow startup or failed dependencies. Increase `livenessProbe.initialDelaySeconds` to 60 seconds if your application takes time to initialize. If your readiness probe fails immediately after startup, it's often because the database connection hasn't established—increase `readinessProbe.initialDelaySeconds` and `failureThreshold` to give the pod more time. |
| 121 | + |
| 122 | +## Configuration Patterns |
| 123 | + |
| 124 | +Most teams deploy the same application to multiple environments with different settings. Use value overlays to keep environment-specific config separate from base settings: |
| 125 | + |
| 126 | +Create a base `values.yaml` with common settings: |
| 127 | + |
| 128 | +```yaml |
| 129 | +image: |
| 130 | + repository: "us-phoenix-1.ocir.io/mytenancy/customer" |
| 131 | + pullPolicy: Always |
| 132 | +
|
| 133 | +obaas: |
| 134 | + framework: HELIDON |
| 135 | + helidon: |
| 136 | + enabled: true |
| 137 | + datasource: |
| 138 | + name: "customer" |
| 139 | + otel: |
| 140 | + serviceName: "customer" |
| 141 | + eureka: |
| 142 | + enabled: true |
| 143 | + otel: |
| 144 | + enabled: true |
| 145 | +``` |
| 146 | + |
| 147 | +Then create environment overlays like `values-dev.yaml`: |
| 148 | + |
| 149 | +```yaml |
| 150 | +image: |
| 151 | + tag: "latest" |
| 152 | +
|
| 153 | +replicaCount: 1 |
| 154 | +
|
| 155 | +obaas: |
| 156 | + namespace: obaas-dev |
| 157 | + database: |
| 158 | + credentialsSecret: customer-dev-db |
| 159 | + walletSecret: dev-wallet |
| 160 | + helidon: |
| 161 | + hibernate: |
| 162 | + hbm2ddl_auto: create # Auto-create schema in dev |
| 163 | + show_sql: true # Show SQL for debugging |
| 164 | +``` |
| 165 | + |
| 166 | +And `values-prod.yaml` with production settings: |
| 167 | + |
| 168 | +```yaml |
| 169 | +image: |
| 170 | + tag: "2.1.0" # Pinned version |
| 171 | +
|
| 172 | +replicaCount: 3 |
| 173 | +
|
| 174 | +obaas: |
| 175 | + namespace: obaas-prod |
| 176 | + database: |
| 177 | + credentialsSecret: customer-prod-db |
| 178 | + walletSecret: prod-wallet |
| 179 | + helidon: |
| 180 | + hibernate: |
| 181 | + hbm2ddl_auto: validate # Never modify prod schema |
| 182 | + show_sql: false # No debug output |
| 183 | +
|
| 184 | +resources: |
| 185 | + requests: |
| 186 | + cpu: 200m |
| 187 | + memory: 384Mi |
| 188 | + limits: |
| 189 | + cpu: 1000m |
| 190 | + memory: 768Mi |
| 191 | +
|
| 192 | +autoscaling: |
| 193 | + enabled: true |
| 194 | + minReplicas: 3 |
| 195 | + maxReplicas: 20 |
| 196 | + targetCPUUtilizationPercentage: 70 |
| 197 | +``` |
| 198 | + |
| 199 | +Deploy by layering multiple value files: |
| 200 | + |
| 201 | +```bash |
| 202 | +# Development |
| 203 | +helm install customer ./obaas-sample-app \ |
| 204 | + -f values.yaml \ |
| 205 | + -f values-dev.yaml \ |
| 206 | + -n development |
| 207 | +
|
| 208 | +# Production |
| 209 | +helm install customer ./obaas-sample-app \ |
| 210 | + -f values.yaml \ |
| 211 | + -f values-prod.yaml \ |
| 212 | + -n production |
| 213 | +``` |
| 214 | + |
| 215 | +Later values files override earlier ones, so environment-specific settings replace base defaults. |
| 216 | + |
| 217 | +## Managing Secrets |
| 218 | + |
| 219 | +Database credentials and wallet files are sensitive—never commit them to version control. Create secrets imperatively from local files or secure storage: |
| 220 | + |
| 221 | +```bash |
| 222 | +# Database credentials |
| 223 | +kubectl create secret generic customer-db-secret \ |
| 224 | + --from-literal=db.username=CUSTOMER_USER \ |
| 225 | + --from-literal=db.password='SecurePassword123!' \ |
| 226 | + --from-literal=db.service=myatp_high \ |
| 227 | + -n your-namespace |
| 228 | +``` |
| 229 | + |
| 230 | +For Spring Boot with Liquibase: |
| 231 | + |
| 232 | +```bash |
| 233 | +kubectl create secret generic customer-db-secret \ |
| 234 | + --from-literal=db.username=CUSTOMER_USER \ |
| 235 | + --from-literal=db.password='SecurePassword123!' \ |
| 236 | + --from-literal=db.service=myatp_high \ |
| 237 | + --from-literal=db.lb_username=ADMIN \ |
| 238 | + --from-literal=db.lb_password='AdminPassword456!' \ |
| 239 | + -n your-namespace |
| 240 | +``` |
| 241 | + |
| 242 | +ADB wallet secrets need all files from the wallet ZIP: |
| 243 | + |
| 244 | +```bash |
| 245 | +unzip Wallet_MyATP.zip -d /tmp/wallet/ |
| 246 | +kubectl create secret generic customer-adb-wallet \ |
| 247 | + --from-file=/tmp/wallet/ \ |
| 248 | + -n your-namespace |
| 249 | +rm -rf /tmp/wallet # Clean up |
| 250 | +``` |
| 251 | + |
| 252 | +Verify secrets contain the expected keys: |
| 253 | + |
| 254 | +```bash |
| 255 | +kubectl get secret customer-db-secret -n your-namespace -o jsonpath='{.data}' | jq 'keys' |
| 256 | +``` |
| 257 | + |
| 258 | +Image pull secrets for private registries follow Kubernetes' standard format: |
| 259 | + |
| 260 | +```bash |
| 261 | +kubectl create secret docker-registry ocir \ |
| 262 | + --docker-server=us-phoenix-1.ocir.io \ |
| 263 | + --docker-username='tenancy-namespace/oracleidentitycloudservice/[email protected]' \ |
| 264 | + --docker-password='your-auth-token' \ |
| 265 | + -n your-namespace |
| 266 | +``` |
| 267 | + |
| 268 | +Reference the secret in your values file: |
| 269 | + |
| 270 | +```yaml |
| 271 | +imagePullSecrets: |
| 272 | + - name: ocir |
| 273 | +``` |
| 274 | + |
| 275 | +## Common Problems |
| 276 | + |
| 277 | +**Pods in CrashLoopBackOff** with database connection errors mean your credentials secret is missing, has wrong keys, or contains incorrect values. Check that `db.service` matches a service name in your `tnsnames.ora`. Oracle returns "TNS: could not resolve the connect identifier" when the service name doesn't exist in your wallet. |
| 278 | + |
| 279 | +**Helidon "DataSource not found" errors** happen when `obaas.helidon.datasource.name` in your values file doesn't match your application's datasource bean name. Check environment variables in the running pod: |
| 280 | + |
| 281 | +```bash |
| 282 | +kubectl exec deploy/customer -n your-namespace -- env | grep javax.sql.DataSource |
| 283 | +``` |
| 284 | + |
| 285 | +The datasource name appears in the middle of the variable names. It must match your `microprofile-config.properties` exactly. |
| 286 | + |
| 287 | +**Metrics not appearing in SigNoz** usually means OTEL configuration issues. For Helidon, verify the protocol is set correctly: |
| 288 | + |
| 289 | +```bash |
| 290 | +kubectl exec deploy/customer -n your-namespace -- env | grep OTEL |
| 291 | +``` |
| 292 | + |
| 293 | +You should see `OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf`. If it's missing or set to `grpc`, metrics won't export. Check your application logs for "failed to export" errors. |
| 294 | + |
| 295 | +**ImagePullBackOff errors** mean Kubernetes can't pull your container image. Verify the image path and tag are correct, and that your image pull secret exists and has valid credentials: |
| 296 | + |
| 297 | +```bash |
| 298 | +kubectl get secret ocir -n your-namespace -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d |
| 299 | +``` |
| 300 | + |
| 301 | +The decoded JSON should contain your registry credentials. |
| 302 | + |
| 303 | +**Health probe failures** show as pods that never become Ready or that restart frequently. Port-forward to the pod and manually test the health endpoints: |
| 304 | + |
| 305 | +```bash |
| 306 | +kubectl port-forward deploy/customer 8080:8080 -n your-namespace |
| 307 | +
|
| 308 | +# Helidon |
| 309 | +curl http://localhost:8080/health/live |
| 310 | +curl http://localhost:8080/health/ready |
| 311 | +
|
| 312 | +# Spring Boot |
| 313 | +curl http://localhost:8080/actuator/health/liveness |
| 314 | +curl http://localhost:8080/actuator/health/readiness |
| 315 | +``` |
| 316 | + |
| 317 | +If endpoints return errors or don't exist, check that you've included the correct dependencies (Spring Boot Actuator or Helidon Health) and that your application framework matches the chart's `framework` setting. |
| 318 | + |
| 319 | +## Helm Operations |
| 320 | + |
| 321 | +Beyond basic installation, you'll need to update deployments, debug template rendering, and inspect running releases. |
| 322 | + |
| 323 | +Upgrade a deployed release with new values: |
| 324 | + |
| 325 | +```bash |
| 326 | +helm upgrade customer ./obaas-sample-app \ |
| 327 | + -f values-customer.yaml \ |
| 328 | + -n your-namespace |
| 329 | +``` |
| 330 | + |
| 331 | +Render templates locally without installing (requires cluster access to query ConfigMaps): |
| 332 | + |
| 333 | +```bash |
| 334 | +helm template customer ./obaas-sample-app \ |
| 335 | + -f values-customer.yaml \ |
| 336 | + --debug |
| 337 | +``` |
| 338 | + |
| 339 | +Inspect what's actually deployed: |
| 340 | + |
| 341 | +```bash |
| 342 | +# Show current values |
| 343 | +helm get values customer -n your-namespace |
| 344 | +
|
| 345 | +# Show rendered Kubernetes manifests |
| 346 | +helm get manifest customer -n your-namespace |
| 347 | +
|
| 348 | +# List all releases |
| 349 | +helm list -n your-namespace |
| 350 | +``` |
| 351 | + |
| 352 | +Validate your chart before deploying: |
| 353 | + |
| 354 | +```bash |
| 355 | +helm lint ./obaas-sample-app -f values-customer.yaml |
| 356 | +``` |
| 357 | + |
| 358 | +Uninstall a release (keeps namespace): |
| 359 | + |
| 360 | +```bash |
| 361 | +helm uninstall customer -n your-namespace |
| 362 | +``` |
| 363 | + |
| 364 | +## Additional Resources |
| 365 | + |
| 366 | +- [Oracle Backend for Microservices and AI Documentation](https://docs.oracle.com/en/database/oracle/oracle-database/) |
| 367 | +- [Helidon Documentation](https://helidon.io/docs/latest) |
| 368 | +- [Spring Boot Documentation](https://spring.io/projects/spring-boot) |
| 369 | +- [Helm Documentation](https://helm.sh/docs/) |
| 370 | +- [SigNoz Documentation](https://signoz.io/docs/) |
| 371 | + |
| 372 | +## License |
| 373 | + |
| 374 | +Copyright (c) 2025 Oracle and/or its affiliates. |
| 375 | + |
| 376 | +Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ |
0 commit comments