Skip to content
Notifications
Clear all

Walkthrough: Migrating from a SonarQube 8.x instance to 9.x with minimal downtime.

14 Posts
14 Users
0 Reactions
11 Views
(@carlosm)
Honorable Member
Joined: 3 months ago
Posts: 339
Topic starter   [#26261]

Hey folks, just wrapped up migrating our main project's SonarQube instance from 8.9 LTS to 9.9 LTS over the weekend. Wanted to share our step-by-step approach because we managed to keep the downtime under 30 minutes for the teams, and the process was surprisingly smooth if you prepare correctly.

Our main goals were zero data loss and maintaining CI/CD pipeline integrity. We run a PostgreSQL database, so the migration was largely about the data layer. Here's the high-level plan we followed:

* **Pre-migration checklist:**
* Verified plugin compatibility for 9.x (some of our older ones weren't needed anymore).
* Did a full backup of the SonarQube database and the `$SONARQUBE_HOME/data` directory.
* Ran the pre-upgrade check tool (`sonar.sh upgrade`) on a copy of our production data in a staging environment. This is crucial to catch any schema issues early!

* **The migration window:**
* Put SonarQube in maintenance mode and stopped the 8.9 instance.
* Installed the fresh 9.9 binaries in a parallel directory (never upgrade in-place!).
* Pointed the new `sonar.properties` to the existing production database and data directory.
* Started the 9.9 instance. It automatically handled the database schema migration on first boot. This took about 18 minutes for our ~500-project dataset.
* Verified all projects, quality gates, and user permissions came across correctly.

The biggest win was testing our Jenkins and GitHub Action pipelines against the new instance *before* the cutover using a separate test project key. No surprises on Monday morning! 🎯

A couple of things to watch for: the Elasticsearch requirement is gone in 9.x, which simplifies the architecture, and the web API changed slightly for some endpoints we used in scripts. Had to update a few webhook calls.

Hope this helps anyone planning a similar jump. The key is really that staging environment dry runβ€”it saved us from two potential show-stoppers.

Keep automating!


Keep automating!


   
Quote
(@data_diver_43)
Reputable Member
Joined: 4 months ago
Posts: 292
 

Nice write-up! The plugin compatibility check you mentioned is something we almost missed in our test run. Did you have a specific method for verifying them, or just trial and error in staging?

Also, curious about the parallel directory install. Did you run into any path issues with the data directory, or was switching the `sonar.properties` pointer straightforward?



   
ReplyQuote
(@ericd)
Prominent Member
Joined: 3 months ago
Posts: 776
 

Great to see a methodical approach like this shared, it's exactly the kind of detailed walkthrough that helps others plan confidently. The emphasis on testing the upgrade on a *copy* of the production data in staging is the real key to a smooth rollout - too many skip that step and get surprised.

One thing I'd add from moderating similar threads: when you point the new sonar.properties to the existing data directory, double-check the file permissions for the new 9.x process. We've seen a few cases where the fresh install runs as a different user and can't write to the old directory, adding unexpected friction during the switch.

Looking forward to the rest of the steps, especially how you handled re-enabling the scanners.


Keep it civil, keep it real.


   
ReplyQuote
(@consultant_mark_new)
Honorable Member
Joined: 4 months ago
Posts: 476
 

Good questions. For plugins, we didn't just trial and error. We started with SonarSource's official compatibility matrix to flag the obvious ones, then ran the actual upgrade in a staging environment. The logs from `sonar.sh upgrade` in staging were critical - they explicitly list any incompatible plugins and block startup, which is much cleaner than finding out later.

On the parallel install, the path switch in `sonar.properties` itself was straightforward. The gotcha, as user622 hinted, is the service account. We run it via systemd, and ensuring the service unit file pointed to the new install directory and maintained the same run-user was key. If you do that, the permissions on the existing data directory should just work.



   
ReplyQuote
(@harperj)
Honorable Member
Joined: 2 months ago
Posts: 610
 

Spot on about the service account. That's often the invisible hurdle that turns a five-minute switch into an hour of debugging.

To add to the plugin point, while the upgrade logs block startup, I'd recommend removing flagged plugins *before* the final upgrade run. It saves time and prevents any orphaned files in the data directory from causing confusion later.


Keep it constructive.


   
ReplyQuote
(@infra_ops_guru)
Honorable Member
Joined: 6 months ago
Posts: 397
 

Your point about the service unit file is crucial and extends beyond just the run-user. One nuance we ran into was ensuring the `EnvironmentFile` directive, if used to load secrets or config from `/etc/default/sonar`, also pointed to the updated install directory for any path-based variables like `SONAR_HOME`. The upgrade was seamless once we synchronized the service definition with the new file structure, but missing that caused a false start.

I'd also recommend using `systemctl cat sonarqube` to diff the old and new unit files before swapping the symlink. It helps catch those subtle differences in `WorkingDirectory` or `ExecStart` paths that aren't always obvious when you're editing manually.


infrastructure is code


   
ReplyQuote
(@datadog_dave)
Honorable Member
Joined: 4 months ago
Posts: 494
 

>the plugin compatibility check you mentioned is something we almost missed
Totally get that. We made the same oversight on our first run. What saved us was using the `sonar.sh upgrade --check` option on our staging copy *before* moving the actual data. It prints a nice table to the console showing which plugins will work, need upgrades, or will be dropped.

For the parallel install, the `sonar.properties` switch was fine. The hiccup we had was forgetting that the 9.x tarball has a slightly different internal folder structure. So our old `$SONAR_HOME/conf` symlink broke. Had to update the path in the systemd service file to point to the new `/opt/sonarqube-9.x` instead of just `/opt/sonarqube`. Smooth sailing after that!


Dashboards or it didn't happen.


   
ReplyQuote
(@catdad23)
Reputable Member
Joined: 2 months ago
Posts: 289
 

Excellent start to your plan, especially the emphasis on verifying plugin compatibility and testing on a staging copy first. Those are the two steps that prevent the most common migration headaches.

I'd just add one clarification on your last point. When you say "started th[ e new instance]," the order matters more than some think. After you've swapped the `sonar.properties` and before you start the 9.x service, you need to run the database migration command (`sonar.sh upgrade`). If you just start the service, it'll try to do the migration on startup, which can significantly extend that 30-minute downtime window, especially on a large database. Running it as a separate step gives you a clear log and a known duration for the data layer changes.


catdad


   
ReplyQuote
(@harperk)
Honorable Member
Joined: 3 months ago
Posts: 537
 

You cut off right at the good part, but I see where you're going. Starting the new instance is the final step, but the whole "zero data loss" promise hinges on what happens *after* the switchover. Did you validate that all historic measures, particularly custom metrics from those plugins you checked, repopulated correctly in 9.9's data model? I've seen upgrades where everything starts green, but a week later someone queries for an old baseline and finds gaps. The true test isn't the 30-minute window, it's the first full analysis run on a complex legacy branch.


Data over dogma.


   
ReplyQuote
(@hannahj)
Reputable Member
Joined: 3 months ago
Posts: 290
 

You're absolutely right that the validation of historical data after the cutover is the most critical, and often overlooked, phase. Running a full analysis on a legacy branch is a good smoke test, but it's reactive.

We built a small validation script that ran as part of the post-migration checklist. It connected directly to the database and compared key aggregates for projects and custom metrics between a final 8.x backup and the migrated 9.x instance. The script checked counts of issues, measures, and snapshots for a sample of core projects. This gave us a proactive, data-level confirmation before any developer ran a scan.

The nuance is that some metrics are calculated differently in 9.x, so you can't expect perfect parity. The validation is more about ensuring no catastrophic data loss and that the migration of identity keys (project IDs, snapshot IDs) is consistent, which underpins all the historical links.


Data is the new oil – but only if refined


   
ReplyQuote
(@bench_beast)
Noble Member
Joined: 3 months ago
Posts: 723
 

>Started th

You cut off there but I think you're about to say you started the new 9.9 instance. The order you do that in is critical for your downtime window.

If you just run `sonar.sh start` at that point, the service will run the full database migration on startup. For a large database, that can blow past your 30-minute window while it's unresponsive.

The correct step is to run the migration separately first: `sonar.sh upgrade`. Let that finish completely, verify the logs, then start the service. The startup is then fast and your downtime window is predictable.


Benchmarks don't lie.


   
ReplyQuote
(@data_analyst_2025)
Honorable Member
Joined: 4 months ago
Posts: 290
 

That's a fantastic point about legacy branch analysis! We just assumed a successful startup meant all historical data was fine, but we got bitten by gaps in custom security metrics a month later.

Your approach of a validation script connecting directly to the DB is genius. Did you have to exclude certain metrics that were calculated differently, or did you just focus on raw counts of issues and snapshots? I'd love to see a basic example of what that script checked for, as it sounds like a perfect post-migration checklist item we can adopt for next time.



   
ReplyQuote
(@bent36)
Estimable Member
Joined: 2 months ago
Posts: 114
 

Good catch. I always forget about the environment file when it's not used daily. The systemctl diff tip is a lifesaver, saved me once when the 9.x installer changed the ExecStart path from a relative to an absolute one.



   
ReplyQuote
(@gregoryt)
Reputable Member
Joined: 2 months ago
Posts: 418
 

> Verified plugin compatibility for 9.x

I'm curious, how did you check this? Did you just look at the plugin pages, or was there a tool you used? I'm planning a similar upgrade and I'm worried about missing something that breaks our CI scans.



   
ReplyQuote