Reference implementation
Section titled “Reference implementation”The Migration Framework defines the strategy, design, landing-zone, migration, and operations principles for Rehost workloads. This asset applies those principles to one concrete, runnable Spring Boot and PostgreSQL implementation on STACKIT.
The maintained repository is the source of truth for Terraform, Ansible, application artifacts, migration scripts, validation, and runtime configuration. This asset explains how to use that implementation without duplicating its complete source code.
STACKIT CMF Rehost Spring Boot repository Open the runnable Terraform and Ansible reference implementation for the Spring Boot and PostgreSQL Rehost path. Open the repositoryMigration context and scope
Section titled “Migration context and scope”This example represents an application Rehost path for a Spring Boot workload (Spring Music sample). The migration focus is the runtime relocation of the application to STACKIT:
- Infrastructure Rehost: Terraform provisions one STACKIT VM, its boot volume, network, public IP, security group, SSH key, Observability resources, and an optional Server Backup schedule.
- Application Rehost: Ansible installs Java, deploys the Spring Boot JAR, and manages it with
systemdwithout changing the application runtime model. - Stateful Rehost: Ansible installs self-managed PostgreSQL on the same VM. The database engine is not changed to a managed service as part of this path.
- Controlled migration: The repository provides separate rehearsal, cutover, validation, and rollback workflows with machine-readable evidence.
The validated baseline deliberately does not include an application load balancer, DNS switch, multiple VMs, Kubernetes, Cloud Foundry, or PostgreSQL Flex. Add those only as separately designed and tested extensions; they are not implied by this Rehost example.
What is included in the repository
Section titled “What is included in the repository”- Provisioning: Terraform resources for network, security, one VM, boot volume, SSH key, and public IP.
- Configuration bridge: Terraform triggers Ansible after infrastructure provisioning.
- Application deployment: Ansible deploys a concrete Spring Boot artifact and configures a systemd service.
- VM-local database path: PostgreSQL installation, application role and database bootstrap, and a dump-based restore with ownership and data-integrity checks.
- Operations baseline: Node exporter metrics are scraped by STACKIT Observability, and Terraform can enable daily Server Backup for the VM boot volume.
- Migration controls: Source dump generation, independent restore validation, rehearsal, cutover, rollback verification, rollback execution, and evidence capture.
- Deployable sample artifact: A ready-to-run JAR is included in the repository and used by default deployment settings.
Unified automation flags
Section titled “Unified automation flags”To keep automation behavior consistent across CMF examples, use this common flag model in your Terraform variable set:
setup_project: create/use project context.setup_observability: enable/disable observability resources.setup_database: enable/disable optional VM-local PostgreSQL path.setup_workload: enable/disable workload installation on VM.setup_loadgen: enable/disable optional synthetic load generation.setup_dns: accepted by the shared wrapper but unsupported in this baseline.
In the current Rehost repository, these map to existing switches (create_project, enable_observability, enable_local_postgresql, and load-generation related flags).
Validated target architecture
Section titled “Validated target architecture”The following diagram shows the implemented and tested target, not a future high-availability variant.
Prepare the walkthrough workspace
Section titled “Prepare the walkthrough workspace”Use an isolated Linux lab with Git, Terraform, Ansible, ShellCheck, SSH/SCP, curl, jq,
and PostgreSQL server/client tools including pg_config. The sample dump scripts use
runuser and the local postgres OS account and require root privileges in that lab.
When Server Backup is enabled, the cutover workflow also needs an authenticated STACKIT CLI.
Use the Terraform version that created an existing saved plan; plan files are version-specific.
Start in a parent directory without an existing checkout of the same name. This revision contains the migration workflows and declarative Observability management. Its JAR is unchanged from the artifact pinned by the Replatform reference:
umask 077 && git clone https://github.com/stackitcloud/stackit-cmf-Rehost-springboot.git && git -C stackit-cmf-Rehost-springboot checkout --detach b9225eb35c64b9ef4761c208fadb9a2356431793 && test -f stackit-cmf-Rehost-springboot/scripts/run_cutover.sh && cd stackit-cmf-Rehost-springboot && printf '%s\n' "Workspace ready. Continue from this Rehost checkout." || { printf '%s\n' "Preparation failed. Resolve the error before continuing." >&2 false }Run the following steps from that checkout only after preparation succeeds. Preserve an existing checkout, state and evidence rather than replacing them. Keep credentials, plans, state, dumps, inventory and evidence private and outside version control; do not enable shell tracing.
Configure the target inputs
Section titled “Configure the target inputs”Create the private variable file only when it does not already exist:
umask 077test -e env.tfvars || cp env.tfvars.example env.tfvarschmod 600 env.tfvarsEdit the file before planning. Configure the approved existing project or project-creation scope,
service-account key path, SSH key pair, available image, availability zone, VM flavor and storage.
Restrict SSH and application ingress to the source CIDRs actually observed on the target path.
Verify the SSH host key through a trusted channel before migration scripts use strict host checking.
Set SSH_KEY and SSH_USER for those scripts when they differ from ~/.ssh/id_rsa and ubuntu;
keep them consistent with Terraform’s private_ssh_key_path and ssh_user.
Enable VM-local PostgreSQL, Observability and Server Backup for this walkthrough. For the initial
runtime deployment, leave postgresql_restore_after_copy = false and the source dump path empty:
provisioning must not import the source before rehearsal and cutover approval. Supply the database
password through the approved secret mechanism as TF_VAR_postgresql_app_password and retain it
securely for subsequent plans; do not put it in the variable file, shell history or documentation.
Confirm permissions, quota, cost approval and the private Terraform backend before initialization. This workflow assumes a prepared execution host, not a complete lab installation procedure.
Prepare source evidence
Section titled “Prepare source evidence”Create a custom-format source dump and record its SHA-256 checksum, expected row count, and a workload-specific deterministic fingerprint. The repository includes a reproducible eight-row sample:
./scripts/create_source_dump.sh./scripts/validate_source_dump.shThe validation script restores into a separate local PostgreSQL cluster before the dump can enter a migration rehearsal. These scripts generate the bundled sample in temporary local clusters; they do not export a running application or the STACKIT VM. Use a fresh artifact directory and do not overwrite a dump already approved for migration. For a real source, export it under the agreed write-freeze procedure and record equivalent checksum, count and fingerprint evidence.
Provision the target
Section titled “Provision the target”Configure an existing STACKIT project or project creation, restrict SSH and application ingress to
approved source CIDRs, and pass the database password through TF_VAR_postgresql_app_password rather
than a variable file. Review a saved plan before apply.
terraform init && ./scripts/check.sh && terraform plan -input=false -var-file=env.tfvars -out=tfplanStop if initialization, checks or planning fail. Review resource changes, target project, ingress, cost and the disabled initial restore before explicitly applying that saved plan:
terraform apply tfplanTerraform runs Ansible after provisioning. A successful apply proves completion of that orchestration, not acceptance of migrated data. Check the runtime before beginning rehearsal:
./scripts/validate_deployment.shRehearse the migration
Section titled “Rehearse the migration”Run the rehearsal against a temporary database on the target VM:
./scripts/run_migration_rehearsal.shThe rehearsal checks the source evidence, restores the dump, compares row count and fingerprint, and
removes its temporary database without changing the production springmusic database.
Execute cutover
Section titled “Execute cutover”Set the expected source evidence in env.tfvars:
enable_local_postgresql = truepostgresql_source_dump_local_path = "artifacts/source-postgresql.dump"postgresql_restore_after_copy = truepostgresql_expected_album_count = 8postgresql_expected_album_fingerprint = "<source-fingerprint>"Then execute the explicit approval gate:
./scripts/run_cutover.sh --confirmThe script requires a fully available Server Backup no older than 24 hours, creates a saved Terraform plan that replaces only the Ansible orchestration resource, rejects unrelated infrastructure changes, applies the restore, validates data and runtime behavior, and requires a final no-op Terraform plan. Retries of the same source-dump hash preserve the original database rollback point.
Validate and roll back
Section titled “Validate and roll back”Validation checks the source row count and fingerprint, table ownership, a transactionally rolled-back write as the application role, application reachability, services, and the protected rollback dump.
./scripts/validate_migration.sh./scripts/validate_deployment.sh./scripts/verify_rollback.shIf an approved rollback trigger is met during the rollback window, preserve the current target database and restore the original pre-cutover dump:
./scripts/rollback_postgresql.sh --confirmBackup and recovery boundary
Section titled “Backup and recovery boundary”With enable_server_backup = true, Terraform enables STACKIT Server Backup and a daily schedule for
the VM boot volume. The default retention is 14 days. Cutover requires a fully available backup no older
than 24 hours. Backup creation and status were validated against the real target; an in-place Server
Backup restore remains a disruptive disaster-recovery operation and must be rehearsed in a separate
recovery environment.
The Server Backup complements the PostgreSQL pre-restore dump. It does not replace database-level consistency checks or the application rollback procedure.
Follow workspace preparation, private target configuration, source evidence and reviewed provisioning
in that order. Rehearse before the approved cutover and retain the acceptance evidence afterwards.
The repository scripts invoke terraform explicitly; an OpenTofu-only execution host needs a
separately reviewed adaptation, not just replacement of commands in this page.
Monitoring and dashboard snapshot
Section titled “Monitoring and dashboard snapshot”The implementation provisions STACKIT Observability and scrapes node exporter. The Grafana provider
manages the included dashboard in the SCF Rehost folder with the existing Thanos datasource,
waiting for instance readiness instead of silently skipping dashboard creation.
Verify live VM, Spring Boot and PostgreSQL metrics through grafana_dashboard_url, then require a
no-op plan. Seven panels cover the active baseline; the synthetic request panel is included only
when the local load generator is enabled. Synthetic requests do not represent all application traffic.
The deployment validation also checks exporter metrics and service health after apply and database restore.
Initial Grafana admin credentials remain a temporary authentication dependency. Protect state and saved plans. Notification receivers, alert-routing ownership, application logs and distributed tracing require separate configuration and acceptance before production use.
Application landing zone alignment
Section titled “Application landing zone alignment”This example can be run in two valid setup modes.
- With an existing Application Landing Zone: Reuse the already defined project context and service account setup from your landing zone implementation.
Use the known project ID as deployment target (for example with
create_project = falseandproject_id = "...") and the service account JSON configured for that landing zone scope. - Standalone without existing landing zone project: Let the example create a dedicated project.
In this mode, set
create_project = trueand provideparent_container_idwith an existing folder/container where the service account has sufficient permissions.
For landing-zone design guidance, see Application Landing Zone.
Minimal configuration example
Section titled “Minimal configuration example”Use this as a minimal starting point in env.tfvars.
create_project = truetarget_project_name = "cmf-rehost-springboot"target_project_owner_email = "owner@example.com"parent_container_id = "cmf-xxxxxxxx"service_account_key_path = "~/.ssh/cmf-sa.json"public_ssh_key_path = "~/.ssh/id_rsa.pub"private_ssh_key_path = "~/.ssh/id_rsa"availability_zone = "eu01-1"machine_type = "g2i.2"ssh_allowed_cidr = "203.0.113.10/32"app_allowed_cidr = "203.0.113.10/32"enable_local_postgresql = trueenable_observability = trueenable_server_backup = trueDeployment artifact behavior
Section titled “Deployment artifact behavior”- Default artifact path:
ansible/files/springboot-app.jar - Default variable:
jar_local_pathpoints to the same file. - Alternative artifact: Replace the file or override
jar_local_path.
When the artifact changes, Terraform detects the checksum difference and re-runs the Ansible deployment step.
Evidence and acceptance
Section titled “Evidence and acceptance”Every rehearsal, cutover, and rollback writes an evidence.env file below
artifacts/evidence/<timestamp>-<mode>/. Accept a cutover only when the evidence records the expected
checksum, row count, fingerprint, target VM, successful runtime validation, and final Terraform no-op.
./scripts/validate_migration.sh./scripts/validate_deployment.shterraform plan -var-file=env.tfvars -detailed-exitcodeUse the same approved source path, restore flag, expected count and fingerprint as the completed
cutover. Exit code 0 means no changes, 2 means changes are proposed, and 1 means an error.
A plan alone is not proof of apply. The cutover workflow records status=passed and
terraform_noop=true only after applying its saved plan and completing data and runtime validation.
Migration decision gates
Section titled “Migration decision gates”- Prepare: Approve the target design, access paths, source evidence and recovery responsibilities.
- Provision: Review and apply the infrastructure plan, then verify the VM runtime independently.
- Rehearse: Restore into an isolated database and verify integrity without changing the application database.
- Cut over: Freeze source writes, approve the final dump and allow only the intended orchestration change.
- Accept or recover: Require data, runtime and no-op evidence; invoke the agreed rollback before its deadline when acceptance fails.
- Handover: Transfer monitoring, backup ownership, evidence and source-retention decisions before optimization.
Reuse as a Replatform baseline
Section titled “Reuse as a Replatform baseline”The Replatform reference reuses this repository’s pinned Spring Music JAR and sample-data generator. Its sample walkthrough therefore needs this checkout and validated dump artifacts, but not a newly provisioned Rehost VM. Do not create another VM solely to generate the local sample.
For an actual migration from the Rehost VM to SKE and PostgreSQL Flex, verify that the VM is currently healthy, freeze its application writes, export its real PostgreSQL database and qualify that export. A historical successful Rehost apply does not establish current reachability or make the local sample equivalent to live VM data. Source export, acceptance and source failback need their own approved procedure.
- Keep operational procedures aligned with the runbook and migration governance.
- For production usage, adapt security controls, sizing, image selection, and life cycle automation.
Asset historyActive 6 of the last 12 weeksLWUpdatedNo updates · 1 bar = 1 week i
- LWLukas WeberrußHead of STACKIT Cloud Migration Framework · STACKITOwner
Lukas WeberrußHead of STACKIT Cloud Migration Framework · STACKITOwnerActive 10 of the last 12 weeks · 47 updateswww.linkedin.com/in/lukas-weberruß-a360b081