SonarQube is a popular open-source platform for continuous code inspection that helps developers identify and fix coding issues, security vulnerabilities, and other bugs in their codebase. As someone who has worked on multiple software projects, I can attest to the importance of having a tool like SonarQube in your toolkit. It saves time and prevents headaches by catching issues early on rather than at the end of a project. Recently, I struggled with deploying the latest version of SonarQube on Azure App Service, so I created the repository mhdbouk/azure-sonarqube (github.com) to document my process and help others avoid the same pitfalls. In this blog post, I’ll share my experience with deploying SonarQube on Azure App Service and provide the repository for anyone who may find it useful.

TL;DR

  • Deploy SonarQube as a Docker container on Azure App Service for Linux, fronted by Bicep modules for the App Service plan and SQL Server.
  • Fix the vm.max_map_count error by adding app setting SONAR_SEARCH_JAVAADDITIONALOPTS=-Dnode.store.allow_mmap=false.
  • Point SonarQube at Azure SQL via SONARQUBE_JDBC_URL, SONARQUBE_JDBC_USERNAME, and SONARQUBE_JDBC_PASSWORD app settings.
  • Compose reusable Bicep modules (linux-plan.bicep, sqlserver.bicep) and pass outputs (like fullyQualifiedDomainName) between them.
  • Full ready-to-deploy template at github/mhdbouk/azure-sonarqube.

mhdbouk/azure-sonarqube (github.com)

The issue with latest version in App Service

I encountered a frustrating issue when attempting to deploy SonarQube using a Bicep file that included an Azure App Service, App Service plan. When trying to run the Docker image inside the Azure web app, I received an exception stating that the virtual memory allocated to the container was too low and needed to be increased to 262144. However, this option cannot be updated in Azure App Service, so I had to find an alternative solution.

max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

I spent hours hitting my head against the keyboard, frantically searching the web for a solution. One option I considered was using an older version of SonarQube, as versions 7.8 and above require the vm.max_map_count to be set to 262144. However, I was not willing to downgrade to a version of SonarQube that was 4 years old in order to fix the issue. After crying out loud in frustration, I finally found a solution: adding the following app setting SONAR_SEARCH_JAVAADDITIONALOPTS with a value of -Dnode.store.allow_mmap=false. This allowed me to successfully run the latest version of SonarQube without any issues, and I was extremely relieved and happy to have found a solution.

SQL Server Support

By default, SonarQube creates an in-memory database that is useful for testing purposes only. In order to run SonarQube in a production environment, it is necessary to configure it to use a persistent database such as SQL Server. In this case, I added the needed Bicep resources and the necessary configuration to run SonarQube using SQL Server, which was also created and deployed using the Bicep file.

In order to configure SonarQube to use a persistent database, you added the following app settings to the siteConfig block in the Bicep file:

...
siteConfig {
  appSettings: [
    {
      name: 'SONARQUBE_JDBC_URL'
      value: 'jdbc:sqlserver://${sqlserver.outputs.fullyQualifiedDomainName}:1433;database=${sqlDatabaseName};encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;'
    }
    {
      name: 'SONARQUBE_JDBC_USERNAME'
      value: adminSqlUsername
    }
    {
      name: 'SONARQUBE_JDBC_PASSWORD'
      value: adminSqlPassword
    }
  ]
}
...

Bicep Modules

Bicep modules are self-contained blocks of Bicep code that can be reused and imported into other Bicep files, making it easier to manage and maintain complex deployments. I used the following Bicep modules in this repository:

  • linux-plan.bicep: This module creates an Azure App Service Plan with a Linux operating system. It includes the necessary output for the web app resource.

  • sqlserver.bicep: This module creates an Azure SQL Server and an Azure SQL database. It includes the necessary output for the web app resource, including the full qualified domain name of the SQL server.

To use a Bicep module, first you create a new bicep file, add the resources and the parameters needed, and then simply import it using the module function and specify the path to the module file. For example:

// sqlserver.bicep
param location string = resourceGroup().location
...

resource sqlServer 'Microsoft.Sql/servers@2022-05-01-preview' = {
  location: location
  name: sqlServerName
  tags: {
    displayName: 'Sql Server'
  }
  properties: {
    administratorLogin: adminSqlUsername
    administratorLoginPassword: adminSqlPassword
    version: '12.0'
    publicNetworkAccess: 'Enabled'
  }
}

output fullyQualifiedDomainName string = sqlServer.properties.fullyQualifiedDomainName

// main.bicep
module sqlserver 'sqlserver.bicep' = {
  ...
}

// Use the module output
fqdn: sqlserver.outputs.fullyQualifiedDomainName

Conclusion

In this blog post, we shared our experience with deploying the latest version of SonarQube on Azure App Service using Bicep and Docker. We encountered an issue during the deployment process, but were able to find a solution and successfully run the latest version of SonarQube.

We also explained how we used Bicep modules to organize and deploy the necessary resources. We then configured SonarQube to use the SQL Server by adding the necessary configuration to the Bicep file.

Overall, using Bicep and Docker made it easy to deploy and configure SonarQube on Azure. And now, with the provided bicep file, you can easily create a new instance of SonarQube with just a few clicks. Happy coding!

FAQ

How do I deploy SonarQube on Azure App Service?

Use the official sonarqube Docker image on Azure App Service for Linux, configure persistent storage for the database via Azure SQL or PostgreSQL, and set SONAR_SEARCH_JAVAADDITIONALOPTS=-Dnode.store.allow_mmap=false as an app setting. A Bicep template at github/mhdbouk/azure-sonarqube provisions the App Service plan, web app, and SQL Server in one deployment.

Why does SonarQube fail with “vm.max_map_count too low” on App Service?

SonarQube 7.8 and later require Elasticsearch’s vm.max_map_count kernel parameter to be at least 262144. Azure App Service does not allow modifying kernel parameters on the underlying host. The workaround is to switch Elasticsearch off its memory-mapped storage by setting SONAR_SEARCH_JAVAADDITIONALOPTS=-Dnode.store.allow_mmap=false in the App Service application settings. Search performance is slightly slower but the container starts cleanly.

Can I run SonarQube on Azure SQL Server instead of PostgreSQL?

Yes, though it’s worth noting that SonarSource has deprecated SQL Server support in newer versions. If you are on a SonarQube version that still supports it, set SONARQUBE_JDBC_URL to a JDBC connection string pointing at your Azure SQL database, along with SONARQUBE_JDBC_USERNAME and SONARQUBE_JDBC_PASSWORD. For new deployments, Azure Database for PostgreSQL is the safer long-term choice.

What’s the difference between Azure App Service and Azure Container Apps for SonarQube?

App Service is the easier path: managed platform, straightforward Bicep, no Kubernetes knowledge required. Container Apps gives you scale-to-zero, KEDA-based scaling, and more flexible networking, but requires more setup. For a single internal SonarQube instance, App Service is enough. For multi-tenant or production-scale deployments, look at Container Apps or AKS.

How much does it cost to run SonarQube on Azure?

The cheapest viable setup is an S1 Linux App Service plan ($70/month) plus an Azure SQL Basic database ($5/month), so roughly $75/month. For a team of fewer than ten developers that’s plenty. Bump to P1v3 and a S0 SQL tier if you start seeing the App Service warm-start delay or database timeouts. Prices vary by region; check the Azure pricing calculator for your subscription.

Is SonarQube production-ready on App Service or should I use AKS?

For internal-developer-only deployments with light traffic, App Service is production-ready. The mmap=false workaround is documented and stable. If you need horizontal scaling, custom networking, or strict SLA guarantees, AKS with the official SonarQube Helm chart is the more robust path.