Docker, Containers, Persistent Storage, and Production Deployment: Diagnostics, Failure Modes, and Production Practices
Diagnose containerized SonarQube failures by preserving evidence and isolating image, configuration, network, database, volume, host/search, resource, and edition layers before changing anything.
Learning objectives
- Preserve first-failure evidence before restart, cleanup, or image replacement.
- Separate network/DNS, database, volume/ownership, host/search, resource, image/configuration, and SonarQube policy failures.
- Diagnose an intentionally broken localhost JDBC configuration without weakening TLS, authentication, host checks, or quality policy.
- Explain how floating tags, ephemeral DB data, broad port exposure, and volume deletion create operational ambiguity or data loss.
- Apply the least destructive correction and rerun the smallest equivalent scenario.
1. Evidence-first diagnostic sequence
-
Freeze change. Preserve
docker ps -a, inspect output, image digests, logs, Compose/run configuration, and timestamps. - Confirm exact SonarQube/PostgreSQL image identities and architecture.
- Confirm effective JDBC/server environment without printing sensitive values into shared artifacts.
- Inspect mounts and volume identities.
- Inspect Docker network membership, aliases, and DNS assumptions.
- Inspect DB readiness and DB logs.
-
Inspect SonarQube web/CE/search logs and
/api/system/status. - Inspect host sysctl/ulimit/resource state if search or resource failures appear.
- Apply the least destructive correction, then rerun the same smallest scenario.
2. Preserve first-failure evidence before touching the container
mkdir -p evidence
docker ps -a --no-trunc > evidence/docker-ps.txt
docker image inspect sonarqube:26.9.0.129388-community > evidence/sonarqube-image.json
docker inspect sq-lab > evidence/sq-lab-inspect.json 2>&1 || true
docker inspect sq-db > evidence/sq-db-inspect.json 2>&1 || true
docker network inspect sq_net > evidence/sq-net.json 2>&1 || true
docker logs sq-lab > evidence/sq-lab.log 2>&1 || true
docker logs sq-db > evidence/sq-db.log 2>&1 || true
Before sharing evidence, redact passwords, tokens, private hostnames, and sensitive labels. Preserve raw evidence securely if needed; publish only the minimum sanitized subset.
3. Intentionally broken example: localhost points to the wrong process
Assume PostgreSQL is healthy in sq-db on
sq_net, but SonarQube was started with:
SONAR_JDBC_URL=jdbc:postgresql://localhost:5432/sonar
Expected evidence: SonarQube cannot connect to PostgreSQL because
TCP 5432 inside sq-lab is not the sibling database
container. Confirm before fixing:
docker network inspect sq_net
docker exec sq-db pg_isready -U sonar -d sonar
docker logs --tail 160 sq-lab
The least destructive correction is to recreate only
sq-lab with
jdbc:postgresql://db:5432/sonar. Do not publish
PostgreSQL broadly, lower a quality gate, delete volumes, or switch
project keys. Those changes are unrelated to the failing layer.
4. Volume and ownership failures
A SonarQube startup can fail because a bind-mounted directory is not writable by the effective container user, because a volume was mounted at the wrong destination, or because an operator deleted a needed named volume. Inspect rather than guessing:
docker inspect sq-lab --format '{{json .Mounts}}'
docker image inspect sonarqube:26.9.0.129388-community --format 'user={{.Config.User}}'
docker volume inspect sq_data sq_extensions sq_logs
Do not solve ownership by running the whole container as root. Align volume semantics and permissions with the supported image behavior.
5. “The project disappeared” is usually a database-identity question
If the SonarQube container recreates successfully but
projects/users/settings disappear, first verify the JDBC endpoint
and PostgreSQL volume identity. A fresh Postgres container without
the original data volume is a fresh durable store. Reusing
sonarqube_data cannot reconstruct missing database
rows.
6. Embedded-search failures: container logs can point back to the host
Symptoms such as bootstrap-check failures, inability to use
/tmp, file-descriptor exhaustion, or search process
exits belong to host/search/runtime state. Inspect current Linux
limits and resource pressure before changing SonarQube policy:
sysctl vm.max_map_count
sysctl fs.file-max
ulimit -n
ulimit -u
docker stats --no-stream sq-lab
docker logs --tail 200 sq-lab
Do not normalize
SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true as a production
shortcut. Fix the owning host/runtime prerequisite.
7. Floating-tag drift: “same Compose file” may not mean same software
If a stack uses sonarqube:latest or
sonarqube:community, a later pull can select new image
content without changing YAML. Compare RepoDigests,
container image IDs, deployment timestamps, and release notes. The
correction is a controlled version/digest policy, not deleting logs
that expose the change.
8. Secret failures versus secret exposure
An authentication error can come from a wrong DB password, wrong user, wrong JDBC endpoint, or database-side permissions. Diagnose without printing passwords. Conversely, a correct password embedded in a Dockerfile or committed Compose file is an incident even if the container starts. Correctness and confidentiality are separate properties.
9. Destructive cleanup is not troubleshooting
Commands such as docker system prune,
docker volume prune, or
docker compose down -v can remove evidence and durable
state. Preserve logs/inspect output and identify exact resource
names first. SonarSource’s container update guidance explicitly
warns operators about volume-removal commands because database state
can be lost.
10. Symptom-to-layer matrix
| Symptom | Likely layer | First evidence | Wrong shortcut |
|---|---|---|---|
| DB connection refused | Network/DB/JDBC | network inspect, DB readiness, Sonar logs | lowering quality gate |
| Permission denied under extensions/data | Mount/UID/security context | mounts, image user, host perms | run everything as root |
| Elasticsearch bootstrap failure | Host/search | es/server logs, sysctl/ulimit | disable bootstrap checks |
| Projects gone after redeploy | DB identity/persistence | JDBC endpoint + PG volume | edit DB/search directly |
| Unexpected new behavior after pull | Image drift | tag/digest + release notes | delete caches/logs |
11. Production practice: make rollback evidence explicit
A production container change record should include source configuration revision, old/new image tags and digests, supported upgrade path, database backup point, plugin compatibility, host/resource preflight, maintenance window, expected migration behavior, health checks, and rollback/recovery decision criteria. An older image is not automatically a safe rollback after a database migration.
Knowledge check
What is the first thing to do when a containerized SonarQube startup fails?
Preserve first-failure evidence and exact deployment identity before restarting, deleting, or changing configuration.
Why is publishing PostgreSQL port 5432 not the fix for a wrong
localhost JDBC URL?
The intended architecture already provides private Docker-network connectivity. The correct fix is the service DNS name; broad host publication widens exposure without fixing the causal model.
If project history disappears, why is
sonarqube_data not enough to restore it?
Project/application history is stored in the database. The SonarQube data volume holds search/index data, not a supported replacement for database state.
What should you do instead of disabling Elasticsearch bootstrap checks?
Inspect and satisfy the documented host/search prerequisites or move the workload to a compatible host/runtime.
Why can latest make incident diagnosis
harder?
The tag can resolve to different image content over time, making the actual deployed release ambiguous unless digest/image IDs were recorded.
Official references and version notes
- SonarQube Community Build downloads — current Community Build release identity.
- Official SonarQube Docker image tags — current official image tags and digests.
- Prepare the Docker installation — pre-installation checks and named-volume guidance.
- Set up and start your container — docker run/Compose, JDBC environment variables, ports, and volume warnings.
- Linux pre-installation — embedded-search host limits and writable /tmp requirements.
- Configuration methods — preferred Docker environment-variable configuration model.
- System properties — current JDBC and web-server property names.
- Installing database — supported database versions and H2 non-production boundary.
- Updating Community Build — container recreation and persistent-state upgrade guidance.
- SonarQube official image overview — official image usage, host prerequisites, port and edition tags.
Version-sensitive statements were rechecked against current
SonarSource and Docker Hub primary material on 2026-09-07.
Mandatory examples use SonarQube Community Build
26.9.0.129388 with the official
sonarqube:26.9.0.129388-community image and
PostgreSQL postgres:17.11, which is inside the
currently supported PostgreSQL 14–18 range. The recorded
multi-platform SonarQube image index digest at authoring time is
sha256:62930c7f510534bb2bf551ca69ad3ee6f8e12b4116d394597c64cefccbb3313b; learners should inspect the digest they actually pull and
retain it in their evidence packet. The SonarQube image supplies
its own Java runtime; record java -version inside the
running container when runtime provenance matters. No SonarScanner
execution, third-party plugin, CI/provider integration, enterprise
identity provider, or commercial feature is required by the
mandatory Chapter 04 labs. Commercial Server/Data Center,
Kubernetes, managed databases, paid CI, and enterprise identity
are optional/later-course boundaries.
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.