Checkpoint Lab — Database Backup, Restore, Disaster Recovery, and Data Protection
Execute an isolated recovery drill with a recovery manifest, integrity checks, an RPO marker, search-index rebuild evidence, a post-restore analysis, and guarded cleanup.
Learning objectives — Checkpoint objectives
- Produce a recovery manifest that records version, database, configuration, plugin, secret-owner, RPO/RTO, and rollback assumptions without exposing credentials.
- Take a PostgreSQL backup, verify its integrity, and prove its recovery point using a post-backup SonarQube analysis marker.
- Restore into an isolated target with fresh search state and validate the database/project history before any fresh analysis.
-
Run a post-restore analysis, preserve
report-task.txt/ceTaskId, and verify Compute Engine and Quality Gate state independently. - Demonstrate one deliberately broken restore configuration and repair only the owning layer while preserving first-failure evidence.
- Clean up only explicitly prefixed lab resources after the recovery packet is complete.
1. Checkpoint scenario
You are the recovery operator for a disposable SonarQube Community Build instance. The instance contains one synthetic project and one completed baseline analysis. You must prove that a database backup can reconstruct that state on an isolated target, show exactly which later analysis is outside the recovery point, and then prove the restored server can process a fresh analysis.
The checkpoint is successful only when the evidence packet explains what was restored, from which point, under which version/configuration, how search state was reconstructed, what data was intentionally lost after the backup point, and why no production system was touched.
2. Exact lab assumptions
| Item | Required lab value |
|---|---|
| SonarQube |
Community Build 26.9.0.129388;
sonarqube:26.9.0.129388-community
|
| Scanner | SonarScanner CLI 8.1.0.6389; token from environment |
| Database |
PostgreSQL 17.11; postgres:17.11-alpine; source
and restore databases in separate containers
|
| Java | Server image and current Scanner/JRE behavior as shipped/provisioned; record observed runtime |
| Plugins | No third-party plugin required; record that explicitly |
| CI/IdP/provider | None required; no production callback or identity integration |
| Project |
sq28-dr-lab, synthetic Python source only
|
| Ports | 9100 source; 9200 restore |
| RPO/RTO target | Lab target: RPO = backup point; RTO = measured, not promised |
3. Create the recovery manifest before taking the backup
# evidence/recovery-manifest.yml
exercise: sq28-dr-lab
production_data_touched: false
source:
sonarqube_version: 26.9.0.129388
edition: Community Build
image: sonarqube:26.9.0.129388-community
url: http://localhost:9100
project_key: sq28-dr-lab
database:
engine: PostgreSQL
version: 17.11
image: postgres:17.11-alpine
source_database: sonar
restore_database: sonar_restore
backup_method: pg_dump custom format
configuration:
compose_file: compose.yml
secrets_recorded_in_manifest: false
secret_owner: local disposable environment only
plugins:
third_party: []
search:
authority: rebuildable index
restore_strategy: fresh data volume / reindex from database
objectives:
rpo: backup snapshot timestamp
rto: measure through validation CE SUCCESS
rollback:
preserve_source_until_restore_accepted: true
Add image digests, Compose hash, scanner version, Git baseline SHA, backup destination, retention owner, and current date/time to your real packet.
4. Predictions required before execution
Write these predictions in
evidence/predictions.md before the backup:
- Prediction A: the custom-format dump will include the completed baseline analysis but not any analysis committed after the dump starts/completes.
-
Prediction B: the isolated restore target will
initially show project
sq28-dr-labat the backup recovery point and will not show the later version 2.0.0 marker. -
Prediction C: a fresh restore search-data volume
will cause SonarQube to reconstruct search indexes from the
restored database rather than needing the source
sonarqube_datavolume. - Prediction D: the wrong JDBC database name will fail before project validation and will be repairable by changing only the restore server configuration.
-
Prediction E: after creating a restore-only
analysis token, the current Git revision will scan successfully
and produce a new
ceTaskIdwhose CE state reachesSUCCESS.
5. Execute the recovery drill
Use the complete Compose and source workflow from Lesson 2. The checkpoint must preserve these boundaries:
baseline CE SUCCESS → verified pg_dump + hash → post-backup
analysis marker → isolated pg_restore → fresh SonarQube search
state → restored-history check → deliberate wrong-JDBC evidence →
corrected startup → fresh validation analysis → ceTaskId SUCCESS →
recovery accepted
Do not substitute a pre-existing local project or database. Do not
reuse the same database container for source and restore. Do not
start sonar-restore until the target database has been
restored.
For an in-place restore, current SonarQube guidance is to stop the
server, restore the database, clear the Sonar-owned
data/es8 index contents, and restart so search indexes
are rebuilt. This checkpoint uses a fresh restore data volume, which
is the isolated-lab equivalent: no stale search index is copied from
the source instance.
6. Integrity and database verification gates
sha256sum -c evidence/backup/sonarqube.dump.sha256
docker run --rm -i postgres:17.11-alpine \
pg_restore --list \
< evidence/backup/sonarqube.dump \
> evidence/backup/archive-list-recheck.txt
test -s evidence/backup/archive-list-recheck.txt
# After restore, prove target DB identity:
docker compose -p sq28dr exec -T pg-restore \
psql -U sonar -d sonar_restore -Atc \
'select current_database(), current_user, version();' \
| tee evidence/restore/database-identity.txt
If any integrity or restore command fails, stop. Preserve output. Do not continue to SonarQube startup and then infer that the archive was “probably fine.”
7. Prove the recovery point before creating new state
After the restore server reaches UP and reindex is underway/completed enough for the project view, inspect the project's Activity history. Record:
- baseline project version and analysis date;
- absence of the version 2.0.0 post-backup marker;
- restored Quality Gate/profile/project visibility;
- restored user/project metadata required for the lab;
- reindex status and any temporarily unavailable search features.
This is the strongest lab evidence that the backup represents a specific time. Only after recording it should you create a restore-only token and run the validation analysis.
8. Post-restore scanner and Compute Engine validation
export SONAR_HOST_URL=http://localhost:9200
export SONAR_TOKEN="$SONAR_TOKEN_RESTORE"
git rev-parse HEAD | tee evidence/validation/revision.txt
sonar-scanner -Dsonar.projectVersion=3.0.0-dr-validated \
2>&1 | tee evidence/validation/scanner.log
cp .scannerwork/report-task.txt evidence/validation/report-task.txt
CE_TASK_ID="$(sed -n 's/^ceTaskId=//p' .scannerwork/report-task.txt)"
printf '%s\n' "$CE_TASK_ID" | tee evidence/validation/ceTaskId.txt
# Poll in a loop in the lab until terminal; preserve every response if desired.
curl -fsS -H "Authorization: Bearer $SONAR_TOKEN" \
"$SONAR_HOST_URL/api/ce/task?id=$CE_TASK_ID" \
| tee evidence/validation/ce-task-final.json
Verification is not complete until CE is terminal, the analysis appears in Activity, expected measures/issues can be queried, and the Quality Gate state is recorded independently. Scanner process success, report upload, CE success, analysis completion, Quality Gate, CI status, and provider decoration remain separate states.
9. Required evidence packet
-
recovery-manifest.ymlandpredictions.md. - Source and restore image identities; PostgreSQL and scanner versions; Compose rendered configuration with secret values excluded/redacted.
-
Baseline Git SHA, scanner log,
report-task.txt,ceTaskId, and CE terminal response. -
Backup start/end timestamps,
sonarqube.dumpstorage reference, SHA-256, andpg_restore --listoutput. - Post-backup Git SHA and analysis marker proving state newer than the backup.
- Target DB identity and
pg_restorelog. - Restore SonarQube startup/reindex evidence plus the deliberately broken JDBC startup log and corrected startup evidence.
- Screenshot/note or API evidence that the restore initially stops at the backup recovery point.
-
Validation Git SHA, scanner log,
report-task.txt,ceTaskId, CE status, project/gate evidence. - Observed RTO timeline, actual recovery-point limitation, cleanup record, and explicit statement that no production data/system was used.
10. Verification checklist
- ☐ Source and restore PostgreSQL instances are distinct.
- ☐ Exact SonarQube/PostgreSQL/scanner versions are recorded.
- ☐ Backup hash verifies and archive listing is readable.
- ☐ Source remains intact until restore acceptance.
- ☐ Restore target uses fresh/cleared search state.
- ☐ Post-backup marker is absent before the validation scan.
- ☐ Wrong-JDBC first-failure evidence is preserved.
- ☐ Corrected restore reaches system UP and coherent project history.
-
☐ Fresh validation analysis produces
report-task.txtandceTaskId. - ☐ Compute Engine reaches terminal success and Quality Gate is recorded separately.
- ☐ No real credential, proprietary source, production IdP/provider, or uncontrolled database was used.
- ☐ Recovery packet includes RPO/RTO observations and limitations.
11. Guarded cleanup and rollback
docker compose -p sq28dr ps -a
docker volume ls --format '{{.Name}}' | grep '^sq28dr_' || true
# First stop containers without deleting volumes.
docker compose -p sq28dr down
# After explicit verification that no unrelated resources match the project:
docker compose -p sq28dr down -v --remove-orphans
unset SONAR_TOKEN SONAR_TOKEN_SOURCE SONAR_TOKEN_RESTORE SONAR_HOST_URL
Revoke any disposable SonarQube tokens before deleting the lab. If a cleanup command lists anything that is not clearly owned by this exercise, stop and investigate rather than broadening the delete command.
12. What Chapter 28 adds to the production operating model
You now have a recovery contract based on authoritative database
state, explicit configuration/plugin/secret ownership,
integrity-protected backups, isolated restoration, search-index
reconstruction, source preservation, ceTaskId-based
post-restore validation, and measured RPO/RTO evidence. That is
materially stronger than “our Docker volume exists” or “the backup
job was green.”
Chapter 29 continues with Release Cycle, LTA Strategy, Upgrade Paths, and Migration Planning. The separation is intentional: Chapter 28 proves you can reconstruct a known state; Chapter 29 teaches how to move that known state safely to another supported release.
Knowledge check
What evidence proves the lab's RPO boundary?
The baseline is present after restore while the deliberately created post-backup analysis marker is absent until a fresh validation scan creates new state.
Why is a successful database restore not sufficient checkpoint evidence?
You must also start a compatible SonarQube, rebuild/search state, verify project/configuration history, and prove a fresh scanner/Compute Engine analysis.
The restore server fails with a typo in the JDBC database name. Should you alter the dump?
No. Preserve the startup error, prove the target database identity, correct only the JDBC configuration, and rerun the same startup step.
What is the role of the original source during a restore drill?
It is the rollback anchor and must remain intact until the isolated target passes the acceptance criteria.
Why is ceTaskId required after the post-restore
scan?
It connects scanner upload evidence to the exact asynchronous Compute Engine task, preventing scanner exit status from being mistaken for server-side analysis success.
What is the natural next topic after a proven same-version restore?
A separately governed release/update strategy: LTA selection, update paths, compatibility checks, migrations, rollback, and validation—Chapter 29.
Official references and version notes
- SonarQube Community Build — Backup and restore — use the database vendor's backup tooling; hot database backups are supported; restore the database and rebuild Elasticsearch indexes.
- SonarQube Community Build — Reindexing — startup after restore rebuilds Elasticsearch indexes; project availability and background reindex behavior are documented.
- SonarQube Community Build — Installing database — current supported database engines and versions; PostgreSQL 14–18 is supported starting with Community Build 26.2.
-
Configuration methods
— startup/system properties can live in environment variables,
command line, Helm configuration, or
sonar.properties, and are not all database state. - Performing an update — use a fresh distribution/config review and install compatible third-party plugins rather than blindly copying an old installation.
- Sensitive settings — secret-key material and encrypted configuration require separate protected handling.
- PostgreSQL — pg_dump — produces a consistent logical backup while the database can remain in use.
-
PostgreSQL — pg_restore
— restores non-plain-text archives created by
pg_dump. - Official SonarQube Docker tags — exact Community Build image identity used in the lab.
- Official PostgreSQL Docker tags — exact PostgreSQL image identity used in the lab.
Rechecked 2026-09-08. Mandatory examples target
SonarQube Community Build 26.9.0.129388, the
official image sonarqube:26.9.0.129388-community,
PostgreSQL 17.11 via
postgres:17.11-alpine, and
SonarScanner CLI 8.1.0.6389. Community Build 26.9
supports PostgreSQL 14–18. The lab restores a 26.9 database into a
fresh 26.9 instance first; it does not combine disaster recovery
with a SonarQube upgrade or database-vendor migration. Search
indexes are treated as rebuildable Sonar-owned state, not the
backup authority. Recheck current database requirements, update
path, plugins, Java/runtime requirements, and restore instructions
before applying these procedures to another release.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.