An open API service indexing awesome lists of open source software.

https://github.com/stackitcloud/stackit-cmf-replatform-springboot-k8s

STACKIT Cloud Framework Replatform Springboot Example for Kubernetes
https://github.com/stackitcloud/stackit-cmf-replatform-springboot-k8s

Last synced: about 1 month ago
JSON representation

STACKIT Cloud Framework Replatform Springboot Example for Kubernetes

Awesome Lists containing this project

README

          

# stackit-cmf-replatform-springboot-k8s

Runnable replatform example for STACKIT: migrate a Spring Boot workload to SKE with DNS and Observability.

## What this example creates

- Optional target project creation
- SKE cluster (small default node pool)
- DNS zone and external-dns integration
- STACKIT Observability instance
- Spring Boot Deployment + Service (LoadBalancer)
- Optional Horizontal Pod Autoscaler (HPA) for Spring Boot
- Optional STACKIT PostgreSQL Flex target database
- Metrics exporter sidecar on port 9090
- Observability scrape config for Spring Boot metrics
- Grafana dashboard import
- Optional load-generator pod
- Optional Kubernetes migration job for VM PostgreSQL -> PostgreSQL Flex

## Prerequisites

- Terraform >= 1.5
- Service account key file
- Required permissions for SKE, DNS, Observability, and optional project creation

## 1) Configure variables

Copy the example file:

```bash
cp env.tfvars.example env.tfvars
```

Then edit `env.tfvars`.

### Common flag wrapper

To use the common CMF flags, copy and adjust:

```bash
cp flags.env.example flags.env
```

Then run:

```bash
./scripts/apply_with_common_flags.sh flags.env env.tfvars
```

Common flags:

- `setup_project`
- `setup_observability`
- `setup_database`
- `setup_workload`
- `setup_loadgen`
- `setup_dns`

### Values you must replace (currently `xxxx`)

- `target_project_owner_email`
- `parent_container_id`
- `ske_cluster_name`
- `observability_instance_name`
- `dns_zone_name`
- `dns_zone_display_name`

### Notes for these required values

- `target_project_owner_email`: service account or owner email used for project creation
- `parent_container_id`: folder/container ID (for `create_project = true`)
- `ske_cluster_name`: max 11 characters
- `observability_instance_name`: unique readable instance name
- `dns_zone_name`: delegated DNS zone (for example `cmf-1234.runs.onstackit.cloud`)
- `dns_zone_display_name`: display name for the DNS zone resource

### Commonly adjusted values

- `service_account_key_path`
- `target_project_name`
- `region`, `availability_zone`
- `node_pool_machine_type`
- `springboot_image`
- `enable_postgres_flex`
- `enable_springboot_hpa`, `springboot_hpa_*`
- `enable_load_generator`, `load_profile`

## Kubernetes rightsizing options

For replatformed workloads on SKE, rightsizing can be applied at multiple layers:

- Pod layer: adjust requests/limits and optionally enable HPA.
- Node pool layer: tune node pool min/max and machine type.
- Storage layer: choose suitable storage classes for persistence characteristics.

### Enable HPA (optional)

Set in `env.tfvars`:

```hcl
enable_springboot_hpa = true
springboot_hpa_min_replicas = 1
springboot_hpa_max_replicas = 5
springboot_hpa_target_cpu_utilization_percentage = 70
```

Then apply:

```bash
terraform apply -var-file=env.tfvars
```

## PostgreSQL Flex target option

Set the following values in `env.tfvars` to enable a managed database target:

```hcl
enable_postgres_flex = true
postgres_flex_instance_name = "cmf-rpltf-postgres"
postgres_flex_app_username = "springmusic"
postgres_flex_target_database = "postgres"
postgres_flex_target_app_acl_cidrs = ["203.0.113.10/32"]
```

When enabled, Terraform creates PostgreSQL Flex (`stackit_postgresflex_instance` and `stackit_postgresflex_user`) and injects datasource settings into the Spring Boot deployment.

ACL is intentionally strict by default: only CIDRs in `postgres_flex_target_app_acl_cidrs` (or legacy `postgres_flex_acl`) are allowed.

If `enable_observability_alerts = true` and PostgreSQL Flex metrics scraping is enabled,
the baseline alert group also includes PostgreSQL-focused alerts for exporter availability,
connection saturation, cache-hit ratio, and temp file usage.

## VM PostgreSQL to PostgreSQL Flex migration job

To migrate source data from the VM-based PostgreSQL (for example from the Rehost setup), enable:

```hcl
enable_postgres_flex = true
deploy_postgres_migration_job = true
source_postgres_host = ""
source_postgres_port = 5432
source_postgres_database = "springmusic"
source_postgres_username = "springmusic"
source_postgres_password = ""
include_source_postgres_host_in_temp_acl = true
```

The migration job runs a `pg_dump` from source and restores the dump into PostgreSQL Flex using `pg_restore`.

If migration is executed from a source-side client that must connect directly to PostgreSQL Flex,
temporarily add its CIDR via `postgres_flex_temp_migration_acl_cidrs`.
Terraform output `postgres_flex_source_host_acl_suggestion` provides `source_postgres_host/32` when source host is an IPv4 address.

After migration, remove temporary migration CIDRs and apply again.

## 2) Deploy

```bash
terraform init
terraform validate
terraform plan -var-file=env.tfvars
terraform apply -var-file=env.tfvars
```

## 3) Verify workload

```bash
mkdir -p .tmp
terraform output -raw kubeconfig > .tmp/replatform.kubeconfig
export KUBECONFIG=$PWD/.tmp/replatform.kubeconfig
kubectl get ns
kubectl get deploy,svc -n springboot
kubectl get pods -n springboot
```

## 4) Verify metrics path

```bash
HOST=$(terraform output -raw springboot_hostname)
curl -sS "http://$HOST:9090/metrics" | head -n 30
```

Expected: lines beginning with `springboot_legacy_counter`, `springboot_legacy_gauge`, `springboot_legacy_metric`.

## 5) Verify outputs

```bash
terraform output
```

Important outputs:

- `springboot_url`
- `springboot_hostname`
- `observability_grafana_url`
- `project_id`
- `postgres_flex_host`
- `postgres_flex_jdbc_url`
- `postgres_flex_effective_acl_cidrs`
- `postgres_flex_source_host_acl_suggestion`

## Troubleshooting

- If `metrics-exporter` restarts, inspect logs:

```bash
POD=$(kubectl get pod -n springboot -l app=springboot -o jsonpath='{.items[0].metadata.name}')
kubectl logs -n springboot "$POD" -c metrics-exporter --tail=200
kubectl logs -n springboot "$POD" -c metrics-exporter --previous --tail=200
```

- If scrape exists but no data arrives, check target health in Prometheus/Grafana datasource (`up{job=""}`).
- Scrape interval must be greater than `60s` for this environment (`61s` is set by default).

## Destroy

```bash
terraform destroy -var-file=env.tfvars
```