Docker configuration
Prepare your project
Domain name system (DNS)
Qodana Self-Hosted exposes different HTTP endpoints as base URLs. Make sure to allocate a top-level domain like qodana.local. The majority of Qodana Self-Hosted components require dedicated base URLs, for example:
Component | URL |
|---|---|
Frontend |
|
Backend |
|
Linter API |
|
Built-in file storage |
|
Built-in SSO provider |
|
Built-in ingress controller (optional) |
|
These hostnames enable interaction of Qodana components and access to essential services. services. The IP can be of your server or a load balancer, depending on your deployment architecture.
In production environments, you should use a domain that aligns with your naming conventions like qodana.mycompany.com, files.qodana.mycompany.com and others.
If you intend to use Qodana only internally, configure DNS records in your internal DNS server. For external access, ensure that public DNS records point to appropriate IP addresses of your server or load balancer.
PostgreSQL
Databases
Qodana Self-Hosted operates multiple services with each service requiring their own database:
Database | Description | Variable |
|---|---|---|
API Database | Stores data related to Qodana’s API |
|
Git Database | Manages repositories and version control data |
|
Audit Database | Handles audit logs and compliance data |
|
Keycloak Database | Optional. Used for authentication and authorization services like Keycloak |
|
Users and roles
Each service requires a dedicated PostgreSQL user for having access to its corresponding database. These users are assigned specific permissions to ensure security and proper data isolation:
Database | Description | Variable |
|---|---|---|
API User | Read/write permissions for the API database |
|
Linters API User | Read-only permissions for certain tables |
|
Report Processor User | Read/write permissions for processing reports |
|
Git User | Full permissions for Git-related data |
|
Audit User | Full permissions for audit logs |
|
Keycloak User | Optional. Full ownership and permissions for the Keycloak database |
|
Permissions
The following permission rules are applied to ensure proper access control:
Users are granted access only to their respective databases.
Default privileges are configured so that users automatically receive permissions on newly created objects like tables, sequences, and functions.
Sensitive databases like an audit database are strictly controlled to prevent unauthorized access.
Database organization
Each Qodana service (API, Git, Audit, Keycloak) should have its own database. This prevents data corruption, unauthorized access between services, and lets you tune each database better to your needs.
Databases can be hosted on a single server or on different servers. A shared server is suitable for small-scale deployments with low traffic and minimal resource requirements. Separate servers are best suited for large-scale deployments or when handling highly sensitive data like audit logs or authentication.
Security and compliance
Use strong, randomly generated passwords for all database users. Store credentials securely, such as in an environment variable manager or secret storage like HashiCorp Vault and others.
Restrict permissions to ensure users can only access their assigned databases. Avoid granting superuser or unnecessary privileges.
Enable logging for database activity to monitor access and changes, especially for the audit database.
Backup and recovery
Implement a robust backup and recovery plan:
Schedule regular automated backups for all databases.
Test restoration processes regularly to ensure reliability.
For critical data like audit logs and Keycloak, use frequent point-in-time recovery backups.
Monitoring and maintenance
Use PostgreSQL monitoring tools like pgAdmin, Prometheus, or other to track database performance and health.
Periodically review database usage and clean up unused objects. Apply security updates and patches for PostgreSQL.
Example SQL script for a single database server setup
This snippet contains an example script that documents the instructions for configuring a single database server for Qodana Self-Hosted. The script references environment variables instead of hard coded values. The Keycloak database and user permissions configuration are optional. They are documented in the script if you plan to use Keycloak as an identity provider.
RabbitMQ
RabbitMQ acts as a message broker for various Qodana services facilitating communication and task processing.
Virtual hosts
Each Qodana instance requires a dedicated virtual host to isolate messaging operations from other applications. Define a virtual host using the environment variable: ${RABBITMQ_VHOST}. Example: /qodana
Users
A dedicated RabbitMQ user is required by Qodana for authenticating and performing operations on a virtual host. Create a user with the following parameters:
Parameter | Description |
|---|---|
Username |
|
Password |
|
Tags | Assign the administrator tag to grant full access |
Example:
Queues
Qodana requires several durable queues for handling messaging related to reports, Git operations, and triggers. Create the following queues within the ${RABBITMQ_VHOST} variable:
Description | Name | Example |
|---|---|---|
Report queue |
|
|
Git contributor request queue |
|
|
Git contributor response queue |
|
|
Trigger queue |
|
|
All queues must be durable to ensure message persistence in case of RabbitMQ restarts.
Permissions
Define access permissions for the Qodana user to operate within the vhost. Grant the following permissions to the ${RABBITMQ_APPLICATION_USERNAME} variable for the ${RABBITMQ_VHOST} variable:
Permission | Configuration | Description |
|---|---|---|
Configure |
| Enables configuration of all resources |
Write |
| Enables publishing to all queues |
Read |
| Enables consuming from all queues |
This is an example configuration in JSON:
Example definition in JSON
This is and example RabbitMQ configuration. For more details, see visit the RabbitMQ website.
MinIO
Qodana Self-Hosted supports MinIO for object storage. Qodana requires pre-signed URLs, which lets Qodana clients connect directly to a storage and upload artifacts for asynchronous processing or storage purposes.
Qodana Self-Hosted requires the MINIO_RESULTS_BUCKET and MINIO_BASELINES_BUCKET buckets, and they should be hosted on the same storage service.
OIDC provider
Qodana Self-Hosted does not provide a built-in user management module, so users should authenticate using an OIDC provider. Qodana Self-Hosted authorizes their actions according to permissions given to a specific user by an administrator.
To get assistance with configuring an OIDC provider, please contact our support at qodana-support@jetbrains.com.
Run Qodana Self-Hosted
Assuming that requirements from the Overview of self-hosting and Prepare your project chapters are satisfied, pull the quay.io/jetbrains/qodana-installer-cli:latest Docker image. All commands running this image require the /var/run/docker.sock Docker socket file for communicating with the Docker engine and Docker Swarm.
Basic use case
Follow the steps below for installing Qodana Self-Hosted on your machine:
On your local Linux machine, configure the
/etc/hostsfile as shown below:# Added for Qodana Self-Hosted Lite Version 127.0.0.1 qodana.local 127.0.0.1 files.qodana.local 127.0.0.1 api.qodana.local 127.0.0.1 ingress.qodana.local 127.0.0.1 login.qodana.local 127.0.0.1 lintersapi.qodana.localOn your local machine, run the following Docker command:
docker run \ -v /var/run/docker.sock:/var/run/docker.sock \ -e API_ORGANIZATION_NAME="<Specify the name of your organization>" \ -e COMMON_LICENSE_KEY_SECRET="<Specify a valid license key>" \ quay.io/jetbrains/qodana-installer-cli:latest \ install-app
In your browser, navigate to http://qodana.local to receive access to Qodana Self-Hosted.
By default, Qodana Self-Hosted comes configured with local dependencies for quick Proofs Of Concepts (PoCs) or Proofs of Value (PoV). The credentials for a built-in administrator test user are as follows:
Credential | Value |
|---|---|
Username |
|
Password |
|
You can update these credentials by navigating to the http://login.qodana.local page.
Use configuration from file
Run the following Docker command to use a configuration contained in a file:
This command uses the --env-file option to specify the path to the configuration file, in this case this is the qodana-self-hosted.env file.
Persist secrets
This command lets you export and persist secrets created during installation in the ${PWD}/secrets directory:
To make the secret idempotent, this command mounts the /app/qodana-installer/secrets directory for storing secrets.
Docker commands
This chapter provides Qodana Self-Hosted commands executed in the quay.io/jetbrains/qodana-installer-cli:latest Docker image.
help
Help for the qodana-installer-cli tool:
environment
Display all active configurations passed or used by the qodana-installer-cli tool:
install-app
Deploy Qodana Self-Hosted on your machine:
uninstall
Uninstall Qodana Self-Hosted from your machine:
To remove Docker volumes of Qodana Self-Hosted, run the following command:
To delete persisting secrets from your machine located in the ${PWD}/secrets directory, run this command:
logs
Print logs related to Qodana Self-Hosted to the standard output:
You can filter log output using the --filters parameter and labels described in the Labels and environment variables chapter and separated by a space character, for example:
Labels and environment variables
Global labels
Qodana Self-Hosted uses several global labels to mark the resources it owns and manages. You can use these labels to operate Qodana Self-Hosted:
Label and value | Description |
|---|---|
| Identify all resources that are part of the Qodana Self-Hosted installation |
| Display at runtime a Qodana Self-Hosted version that a specific resouce is related to. Dependent on the |
Component-specific labels
Qodana Self-Hosted is operated by several services. To simplify administration, they are combined into the following groups:
Group name | Description |
|---|---|
| Stateful components |
| Qodana API, Qodana Git API, linter API and others |
| Ingress and garbage collection of Docker images and others |
Here, each group identifies a specific Docker Swarm stack.
Labels related to local dependencies
The qodana.jetbrains.self-hosted.lite.dependencies.local=true and qodana.jetbrains.self-hosted.lite.service-type=local-dependencies labels identify resources related to the qodana_self_hosted_local_dependencies stack or group.
The qodana.jetbrains.self-hosted.lite.database.volume.name label defines the internal name of a volume that will be mapped to a related stateful service that is part of a certain Docker stack.
You can find out the volume name for a given container using this Docker CLI command:
To understand the mount point of a specific Docker volume, you can use the qodana.jetbrains.self-hosted.lite.database.volume.path label.
Labels related to Qodana Self-Hosted
The qodana.jetbrains.self-hosted.lite.service-type=application label identifies the resources related to the qodana_self_hosted_local_service_tools stack.
Label related to supporting tools
The qodana.jetbrains.self-hosted.lite.service-type=supporting-tools label identifies the resources related to the qodana_self_hosted_local_service_tools stack.
Environment variables
Product
General
Environment variable | Description | Default value |
|---|---|---|
| Main domain of the application |
|
| Application logging level |
|
| Subdomain for identity provider (Keycloak) |
|
| Container registry URL for pulling images |
|
| Mode for Qodana dependencies (local or remote) |
|
| Current version of Qodana Self-Hosted |
|
| Memory limit for Frontend service |
|
| Object storage provider type |
|
| Message broker provider (RabbitMQ) |
|
FUS
Variables used for statistics collection and processing.
Environment variable | Description | Default value |
|---|---|---|
| Memory limit for FUS service |
|
| Java options for FUS |
|
| Whether FUS is internal only |
|
| Endpoint URL for FUS configuration |
|
Linter API
Linter API validates linters and checks for versions of supported linters and plugins.
General
Environment variable | Description | Default value |
|---|---|---|
| Memory limit for Linters API service |
|
| Java options for Linters API |
|
| Username for Linters API Postgres database |
|
| Name of the Linters API Postgres database |
|
| Memory limit for API service |
|
| Java options for API (optional override) |
|
| Username for API Postgres database |
|
| Name of the API Postgres database |
|
| Zendesk feedback email for API support |
|
| Default version for linters CI templates |
|
| Organization name (optional) | |
| License ID for API (optional) |
|
GitHub
Environment variable | Description | Default value |
|---|---|---|
| Whether GitHub integration is enabled |
|
| Origin URL for GitHub |
|
| GitHub Application ID |
|
| GitHub Application Name |
|
| GitHub OAuth Client ID |
|
OAuth
Environment variable | Description | Default value |
|---|---|---|
| OAuth redirect URI for API |
|
| Base URL for OAuth provider |
|
| Authorization frontend URL for OAuth |
|
| OAuth client ID |
|
| List of OAuth request scopes |
|
| Required scopes for OAuth |
|
| Service name for OAuth provider |
|
| URL to fetch user info from OAuth provider |
|
| User ID field title in OAuth response |
|
| Email field title in OAuth response |
|
| Full name field title in OAuth response |
|
| Whether SAML is enabled for OAuth |
|
| Roles field in OAuth token (if any) |
|
| Realm access field in OAuth token |
|
| Resource access field in OAuth token |
|
| Current client field in OAuth token |
|
| Custom roles field in OAuth token |
|
Dependency services
Utility Swiss Knife container
Environment variable | Description | Default value |
|---|---|---|
| Utility Swiss Knife container image name |
|
| Tag for the Swiss Knife container |
|
Docker Swarm
Environment variable | Description | Default value |
|---|---|---|
| Whether to initialize Docker Swarm |
|
| Address pool for Docker Swarm overlay network |
|
| Docker Swarm garbage collection image name |
|
| Tag for the Docker GC image |
|
Ingress traffic
Environment variable | Description | Default value |
|---|---|---|
| Ingress container image name |
|
| Tag for the ingress container (Traefik version) |
|
| Subdomain for ingress traffic |
|
Database
Environment variable | Description | Default value |
|---|---|---|
| Postgres container image name |
|
| Tag for the Postgres container image |
|
| Default Postgres database user |
|
| Password for Postgres user |
|
| Hostname for the database |
|
| Database port |
|
MinIO
Environment variable | Description | Default value |
|---|---|---|
| Hostname for MinIO | |
| MinIO registry image name |
|
| Tag for the MinIO registry image |
|
| MinIO client image name |
|
| Tag for the MinIO client image |
|
| Root user for MinIO instance |
|
| Root password for MinIO |
|
| Port for MinIO API service |
|
| Bucket name for storing Qodana results |
|
| Bucket name for storing Qodana baselines |
|
| Expiration time for MinIO presigned URLs in minutes |
|
RabbitMQ
Environment variable | Description | Default value |
|---|---|---|
| RabbitMQ registry image name |
|
| Tag for the RabbitMQ registry image |
|
| Hostname for the RabbitMQ service |
|
| Port for RabbitMQ service |
|
| Virtual host for RabbitMQ |
|
| Queue name for Qodana reports |
|
Keycloak
Environment variable | Description | Default value |
|---|---|---|
| Keycloak registry image name |
|
| Tag for the Keycloak image |
|
| Hostname for Keycloak instance |
|
| Keycloak database name |
|
Audit
Environment variable | Description | Default value |
|---|---|---|
| Memory limit for Audit service |
|
| Java options for Audit |
|
| Username for Audit Postgres database |
|
| Name of the Audit Postgres database |
|
Git
Environment variable | Description | Default value |
|---|---|---|
| Queue name for Git contributors request |
|
| Queue name for Git contributors response |
|
| Wait time for contributors' responses |
|
| Max number of messages for contributors' responses |
|
| Number of workers for contributors' responses |
|
| Queue name for Git triggers |
|
| Wait time for Git triggers |
|
| Max number of messages for Git triggers |
|
| Number of workers for Git triggers |
|
| Memory limit for Git Service |
|
| Java options for Git Service |
|
| Username for Git Postgres database |
|
| Name of the Git Postgres database |
|
| Timeout for Git probe checks |
|
Report processor
Environment variable | Description | Default value |
|---|---|---|
| Memory limit for the Report Processor service |
|
| Java options for the Report Processor |
|
| Username for Report Processor Postgres database |
|
| Name of the Report Processor Postgres database |
|
Troubleshooting
To troubleshoot the issues that may arise during deployment, configuration, or operation of Qodana Self-Hosted, use the following command to extract log entries:
Study log entries and also try to:
Look for the message related to a specific issue
Review the possible causes of the issue
Find the trace and debug the issue
If you cannot debug the issue or if the issue persists, navigate to the JetBrains website and create a request containing the following information:
Information item | Description |
|---|---|
Summary | Short and self-contained description of the issue |
Description | Additional information to outline the issue better |
Attachments | Any log files and screenshots, if available |
Tags | Specify the version |
Type | Try to categorize the title and the description of your case. This will be refined after the maintainers analyze the issue |
Priority | Set the priority to the issue. Apply common sense for the definition of the urgency level |