Skip to content

Fix #1933: Improve Docker Compose configuration#1971

Open
rishabhvaish wants to merge 4 commits intosteve-community:masterfrom
rishabhvaish:fix/issue-1933-improve-docker-compose
Open

Fix #1933: Improve Docker Compose configuration#1971
rishabhvaish wants to merge 4 commits intosteve-community:masterfrom
rishabhvaish:fix/issue-1933-improve-docker-compose

Conversation

@rishabhvaish
Copy link
Contributor

@rishabhvaish rishabhvaish commented Feb 21, 2026

Fixes #1933

This PR improves the Docker Compose setup to be more production-ready while maintaining backward compatibility.

Changes

docker-compose.yml

  • Upgrade compose version from 3.0 to 3.8
  • Add health check for MariaDB with proper startup period
  • Add service_healthy dependency so the app waits for a healthy DB (replaces the links: directive)
  • Add network alias mariadb for the DB service to maintain hostname compatibility with the Dockerfile and application-docker.properties
  • Remove DB port exposure to host — the app connects via internal Docker network, no need to publish 3306
  • Add named Docker network for service isolation
  • Add resource limits to prevent excessive memory usage
  • Add configurable app ports via environment variables (HTTP_PORT, HTTPS_PORT)
  • Add container names for easier management

.env.example (new)

  • Template for runtime-configurable environment variables (app ports only)
  • Clear documentation that DB credentials are configured in application-docker.properties (baked at Maven build time)

Usage

The setup now properly waits for database health before starting the app and provides better resource management.

- Upgrade compose version to 3.8 for better feature support
- Add environment variables for better configuration management
- Add health checks for both database and application services
- Add resource limits to prevent excessive memory usage
- Use dedicated Docker network for service isolation
- Add proper volume management for database persistence
- Add container names for easier management
- Improve volume mounts to only include necessary files
- Add configurable ports through environment variables
- Use service health conditions for proper startup ordering

Addresses issue steve-community#1933 by making the Docker setup more production-ready
and easier to configure.
- Provides template for environment variables
- Documents all configurable options
- Includes security notes about password changes
- Makes Docker setup more user-friendly and configurable

Related to issue steve-community#1933 improvements.
@qodo-free-for-open-source-projects

Review Summary by Qodo

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Upgrade Docker Compose to version 3.8 with production-ready features
• Add health checks for database and application services
• Implement resource limits and dedicated network isolation
• Add environment variable configuration for flexibility
• Create .env.example template for easy setup
Diagram
flowchart LR
  A["docker-compose.yml<br/>v3.0"] -->|"Upgrade to v3.8"| B["Enhanced Configuration"]
  B -->|"Add health checks"| C["Service Reliability"]
  B -->|"Add resource limits"| D["Production Ready"]
  B -->|"Add networking"| E["Service Isolation"]
  B -->|"Env variables"| F["Flexible Setup"]
  G[".env.example<br/>New File"] -->|"Template"| F
Loading

Grey Divider

File Changes

1. docker-compose.yml ✨ Enhancement +62/-13

Production-ready Docker Compose with health checks and resources

• Upgrade compose version from 3.0 to 3.8 for enhanced features
• Add dedicated steve-network bridge network for service isolation
• Add health checks for both MariaDB and application services with configurable timeouts and retries
• Implement resource limits (512M for database, 2G for app) and memory reservations
• Replace hardcoded values with environment variables for database credentials and ports
• Add container names (steve-mariadb, steve-app) for easier management
• Optimize volume mounts to only include necessary files with read-only flags where appropriate
• Replace deprecated links with proper depends_on with health condition checks
• Add explicit environment variables for database connection and Java options

docker-compose.yml


2. .env.example 📝 Documentation +19/-0

Environment configuration template for Docker setup

• Create new template file for environment variable configuration
• Document all configurable options including database credentials, ports, and Java options
• Include security notes about changing default passwords before production deployment
• Provide sensible defaults for all configuration values

.env.example


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Feb 21, 2026

Code Review by Qodo

🐞 Bugs (5) 📘 Rule violations (0) 📎 Requirement gaps (2)

Grey Divider


Action required

1. app uses build: only 📎 Requirement gap ⛯ Reliability
Description
The app service is configured to build locally (via build:) and does not specify an image:, so
the compose setup cannot run purely from a prebuilt image. This violates the requirement to use a
prebuilt application image for usability/consistency.
Code

docker-compose.yml[R46-52]

app:
+    container_name: steve-app
  restart: unless-stopped
-    build: .
-    links:
-      - "db:mariadb"
+    build:
+      context: .
+      dockerfile: Dockerfile
+    environment:
Evidence
PR Compliance ID 7 requires the application service to reference a prebuilt image (via image:) and
not require local builds; the updated compose defines build: for app and does not show any
image: entry for that service in the changed lines.

Docker Compose uses a prebuilt Docker image for the application service
docker-compose.yml[46-52]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `app` service uses `build:` and does not specify an `image:`, which makes the compose setup depend on a local build.
## Issue Context
Compliance requires `docker-compose.yml` to reference a prebuilt application image so users can start the stack without building locally.
## Fix Focus Areas
- docker-compose.yml[46-52]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


✅ 2. MariaDB port published 📎 Requirement gap ⛨ Security
Description
The db service publishes container port 3306 to the host via a ports: mapping, increasing
exposure without an explicit requirement shown in the compose changes. This violates the requirement
to avoid publishing MariaDB to the host unless explicitly required.
Code

docker-compose.yml[R22-23]

  ports:
-      - 3306:3306
+      - "${DB_PORT:-3306}:3306"
Evidence
PR Compliance ID 10 requires MariaDB not to publish its port to the host; the updated compose
explicitly maps host ${DB_PORT:-3306} to container 3306.

MariaDB port is not published to the host unless explicitly required
docker-compose.yml[22-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The MariaDB service publishes `3306` to the host, which is disallowed unless explicitly required.
## Issue Context
The application can reach the database via the internal Docker network; host port exposure should be removed or made an explicit opt-in.
## Fix Focus Areas
- docker-compose.yml[22-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. DB host hardcoded mariadb 🐞 Bug ✓ Correctness
Description
The app container still waits for and connects to host mariadb, but the compose file no longer
provides a mariadb hostname/alias (service is db). This can cause the app to hang/fail during
dockerize -wait and/or fail DB connections.
Code

docker-compose.yml[R52-54]

+    environment:
+      - DB_HOST=db
+      - DB_PORT=3306
Evidence
docker-compose config points the app at db, but the built image and docker profile config still
hardcode mariadb as the DB host, and compose does not define a mariadb network alias.

docker-compose.yml[11-33]
docker-compose.yml[52-55]
Dockerfile[21-25]
src/main/resources/application-docker.properties[7-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`docker-compose.yml` now uses the service name `db` (and sets `DB_HOST=db`), but the image startup logic and docker profile configuration still use `mariadb` as the DB hostname. This breaks service discovery because compose is not providing a `mariadb` DNS name.
### Issue Context
- Dockerfile blocks startup on `dockerize -wait tcp://mariadb:3306`.
- `application-docker.properties` uses `db.ip = mariadb`.
- New compose removes the old `links: db:mariadb` behavior and doesn’t define a network alias.
### Fix Focus Areas
- docker-compose.yml[13-33]
- docker-compose.yml[52-55]
- Dockerfile[21-25]
- src/main/resources/application-docker.properties[7-13]
Suggested implementation directions (choose one):
1) **Add a network alias** so `mariadb` resolves again (minimal change): under `db:` -&amp;amp;gt; `networks:` use expanded syntax and add `aliases: [&amp;amp;quot;mariadb&amp;amp;quot;]`.
2) **Make hostname configurable**: change Dockerfile CMD to wait on `${DB_HOST:-db}` and update `application-docker.properties` default `db.ip` to `db` (or to reference `${DB_HOST}` if you also address build-time filtering noted in another finding).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
✅ 4. DB env vars not effective 🐞 Bug ✓ Correctness
Description
Compose and the new .env.example encourage changing DB_PASSWORD/DB_*, but the build uses Maven
resource filtering to bake db.* values from application-docker.properties into resources. This
makes runtime env-var changes unreliable and can desync app vs DB container credentials when users
follow .env.example.
Code

docker-compose.yml[R24-28]

  environment:
    MYSQL_RANDOM_ROOT_PASSWORD: "yes"
-      MYSQL_DATABASE: stevedb
-      MYSQL_USER: steve
-      MYSQL_PASSWORD: changeme
+      MYSQL_DATABASE: ${DB_NAME:-stevedb}
+      MYSQL_USER: ${DB_USER:-steve}
+      MYSQL_PASSWORD: ${DB_PASSWORD:-changeme}
Evidence
The PR adds DB_* env var configurability in compose/.env, but the repo’s docker build reads
application-docker.properties during Maven initialize and filters application resources, which
bakes DB config at build time. README also states users must edit application-docker.properties
for Docker.

docker-compose.yml[24-28]
docker-compose.yml[55-58]
pom.xml[95-104]
pom.xml[195-213]
src/main/resources/application-docker.properties[9-13]
README.md[110-115]
.env.example[4-9]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`docker-compose.yml` and `.env.example` suggest users can change DB credentials via environment variables, but the Docker build uses Maven resource filtering and reads `application-docker.properties` at build time. This bakes DB settings into the built app, so changing `.env` alone can easily cause the DB container and the app to diverge.
### Issue Context
- Maven resource filtering is enabled for `application.yml` and `application**.properties`.
- Maven reads `application-${envName}.properties` (docker profile -&amp;amp;gt; `application-docker.properties`) during build.
- README currently documents editing `application-docker.properties` for Docker.
- `.env.example` encourages changing only `DB_PASSWORD`, which is likely to break app↔DB auth unless the app is also reconfigured.
### Fix Focus Areas
- docker-compose.yml[24-28]
- docker-compose.yml[52-58]
- .env.example[4-9]
- pom.xml[95-104]
- pom.xml[195-213]
- src/main/resources/application-docker.properties[7-13]
- README.md[110-115]
Suggested implementation directions (pick one cohesive approach):
1) **True runtime env-var configuration (recommended)**
- Adjust Maven resource filtering to avoid replacing Spring `${...}` placeholders (e.g., filter only `@...@` tokens).
- Update `application-docker.properties` to use Spring env placeholders like `db.password=${DB_PASSWORD:changeme}` (and similarly for schema/user/host/port), so compose `.env` changes take effect at runtime.
2) **Keep build-time config, but remove misleading `.env` knobs**
- Remove `DB_NAME/DB_USER/DB_PASSWORD` from the app service env and from `.env.example` (or make `.env.example` explicitly say you must also edit `application-docker.properties`).
- Keep DB container env vars, but document that app config is controlled via `application-docker.properties` during build.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

✅ 5. JAVA_OPTS not applied 🐞 Bug ⛯ Reliability
Description
Compose exports JAVA_OPTS, but the container startup command uses a hardcoded `java
-XX:MaxRAMPercentage=85 ... and never expands JAVA_OPTS. Users configuring .env` will see no
effect.
Code

docker-compose.yml[58]

+      - JAVA_OPTS=${JAVA_OPTS:--XX:MaxRAMPercentage=85}
Evidence
JAVA_OPTS is passed into the container, but the Java process is started with fixed flags that
ignore it.

docker-compose.yml[52-58]
Dockerfile[23-25]
.env.example[14-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`JAVA_OPTS` is advertised/configured via docker-compose and `.env.example`, but the container starts Java with hardcoded flags, so user-provided JVM options are ignored.
### Issue Context
The Dockerfile uses a plain `java -XX:MaxRAMPercentage=85 ...` invocation.
### Fix Focus Areas
- docker-compose.yml[52-58]
- Dockerfile[23-25]
- .env.example[14-16]
Suggested fix:
- Change Dockerfile to run Java as e.g. `java ${JAVA_OPTS:-&amp;amp;quot;-XX:MaxRAMPercentage=85&amp;amp;quot;} -jar target/steve.war` (via `sh -c`), and consider removing the compose-side default to avoid divergence.
- If you need Maven JVM opts separately, consider `MAVEN_OPTS` for the build step rather than overloading `JAVA_OPTS`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Deprecated TLS enabled 🐞 Bug ⛨ Security
Description
.env.example recommends enabling TLSv1/TLSv1.1 via jdk.tls.client.protocols, which weakens
outbound TLS security. Defaulting to deprecated protocols is risky unless explicitly required for
legacy endpoints.
Code

.env.example[15]

+JAVA_OPTS=-XX:MaxRAMPercentage=85 -Djdk.tls.client.protocols=TLSv1,TLSv1.1,TLSv1.2
Evidence
The PR introduces an example JAVA_OPTS that enables deprecated TLS protocols, while the repo’s
server-side TLS config prefers modern TLS versions.

.env.example[14-16]
src/main/resources/application.yml[31-34]
Dockerfile[23-25]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `.env.example` defaults `jdk.tls.client.protocols` to include TLSv1 and TLSv1.1. This lowers outbound TLS security by enabling deprecated protocols.
### Issue Context
- This setting affects **client-side** TLS (outbound HTTPS/TLS connections from the JVM).
- If legacy endpoints require TLSv1/1.1, it should be explicit opt-in rather than the default.
### Fix Focus Areas
- .env.example[14-16]
- Dockerfile[23-25]
Suggested fix:
- Change the example to `-Djdk.tls.client.protocols=TLSv1.2,TLSv1.3` (or omit entirely and rely on JVM defaults).
- If needed, add a comment explaining when to temporarily enable legacy protocols.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

7. deploy.resources likely ignored 🐞 Bug ⛯ Reliability
Description
deploy.resources is set for both services, but these limits are typically not enforced by standard
docker compose up (non-Swarm), which can mislead operators into thinking memory limits are active.
Code

docker-compose.yml[R39-44]

+    deploy:
+      resources:
+        limits:
+          memory: 512M
+        reservations:
+          memory: 256M
Evidence
The compose file uses the Swarm-focused deploy.resources stanza for limits/reservations; in many
common Docker Compose deployments this stanza isn’t applied.

docker-compose.yml[39-44]
docker-compose.yml[80-85]
Best Practice: Docker Compose / Swarm behavior

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`deploy.resources` may not be enforced for the most common usage path (`docker compose up -d`), which can lead to unexpected memory usage despite the file suggesting limits.
### Issue Context
This is deployment-mode dependent (Swarm vs non-Swarm).
### Fix Focus Areas
- docker-compose.yml[39-45]
- docker-compose.yml[80-85]
Suggested fix options:
- If targeting non-Swarm compose: switch to supported resource constraint keys for your compose implementation.
- If targeting Swarm: document clearly in README/.env.example that limits require Swarm mode.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +46 to +52
app:
container_name: steve-app
restart: unless-stopped
build: .
links:
- "db:mariadb"
build:
context: .
dockerfile: Dockerfile
environment:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. app uses build: only 📎 Requirement gap ⛯ Reliability

The app service is configured to build locally (via build:) and does not specify an image:, so
the compose setup cannot run purely from a prebuilt image. This violates the requirement to use a
prebuilt application image for usability/consistency.
Agent Prompt
## Issue description
The `app` service uses `build:` and does not specify an `image:`, which makes the compose setup depend on a local build.

## Issue Context
Compliance requires `docker-compose.yml` to reference a prebuilt application image so users can start the stack without building locally.

## Fix Focus Areas
- docker-compose.yml[46-52]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged. The original compose also uses build-only (no image: tag). Since steve does not currently publish a prebuilt Docker image to any registry, keeping build: is consistent with the project setup. If a published image becomes available in the future, adding an image: field would be a good follow-up.

Comment on lines +22 to +23
ports:
- 3306:3306
- "${DB_PORT:-3306}:3306"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Mariadb port published 📎 Requirement gap ⛨ Security

The db service publishes container port 3306 to the host via a ports: mapping, increasing
exposure without an explicit requirement shown in the compose changes. This violates the requirement
to avoid publishing MariaDB to the host unless explicitly required.
Agent Prompt
## Issue description
The MariaDB service publishes `3306` to the host, which is disallowed unless explicitly required.

## Issue Context
The application can reach the database via the internal Docker network; host port exposure should be removed or made an explicit opt-in.

## Fix Focus Areas
- docker-compose.yml[22-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! Removed the host port mapping for MariaDB in c29fa01. The app connects via the internal Docker network, so there is no need to expose 3306 to the host.

Comment on lines +52 to +54
environment:
- DB_HOST=db
- DB_PORT=3306

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Db host hardcoded mariadb 🐞 Bug ✓ Correctness

The app container still waits for and connects to host mariadb, but the compose file no longer
provides a mariadb hostname/alias (service is db). This can cause the app to hang/fail during
dockerize -wait and/or fail DB connections.
Agent Prompt
### Issue description
`docker-compose.yml` now uses the service name `db` (and sets `DB_HOST=db`), but the image startup logic and docker profile configuration still use `mariadb` as the DB hostname. This breaks service discovery because compose is not providing a `mariadb` DNS name.

### Issue Context
- Dockerfile blocks startup on `dockerize -wait tcp://mariadb:3306`.
- `application-docker.properties` uses `db.ip = mariadb`.
- New compose removes the old `links: db:mariadb` behavior and doesn’t define a network alias.

### Fix Focus Areas
- docker-compose.yml[13-33]
- docker-compose.yml[52-55]
- Dockerfile[21-25]
- src/main/resources/application-docker.properties[7-13]

Suggested implementation directions (choose one):
1) **Add a network alias** so `mariadb` resolves again (minimal change): under `db:` -> `networks:` use expanded syntax and add `aliases: ["mariadb"]`.
2) **Make hostname configurable**: change Dockerfile CMD to wait on `${DB_HOST:-db}` and update `application-docker.properties` default `db.ip` to `db` (or to reference `${DB_HOST}` if you also address build-time filtering noted in another finding).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch! Fixed in c29fa01 — added a network alias so the db service is reachable as mariadb, matching what the Dockerfile and application-docker.properties expect.

Comment on lines +24 to +28
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: stevedb
MYSQL_USER: steve
MYSQL_PASSWORD: changeme
MYSQL_DATABASE: ${DB_NAME:-stevedb}
MYSQL_USER: ${DB_USER:-steve}
MYSQL_PASSWORD: ${DB_PASSWORD:-changeme}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Db env vars not effective 🐞 Bug ✓ Correctness

Compose and the new .env.example encourage changing DB_PASSWORD/DB_*, but the build uses Maven
resource filtering to bake db.* values from application-docker.properties into resources. This
makes runtime env-var changes unreliable and can desync app vs DB container credentials when users
follow .env.example.
Agent Prompt
### Issue description
`docker-compose.yml` and `.env.example` suggest users can change DB credentials via environment variables, but the Docker build uses Maven resource filtering and reads `application-docker.properties` at build time. This bakes DB settings into the built app, so changing `.env` alone can easily cause the DB container and the app to diverge.

### Issue Context
- Maven resource filtering is enabled for `application.yml` and `application**.properties`.
- Maven reads `application-${envName}.properties` (docker profile -> `application-docker.properties`) during build.
- README currently documents editing `application-docker.properties` for Docker.
- `.env.example` encourages changing only `DB_PASSWORD`, which is likely to break app↔DB auth unless the app is also reconfigured.

### Fix Focus Areas
- docker-compose.yml[24-28]
- docker-compose.yml[52-58]
- .env.example[4-9]
- pom.xml[95-104]
- pom.xml[195-213]
- src/main/resources/application-docker.properties[7-13]
- README.md[110-115]

Suggested implementation directions (pick one cohesive approach):
1) **True runtime env-var configuration (recommended)**
   - Adjust Maven resource filtering to avoid replacing Spring `${...}` placeholders (e.g., filter only `@...@` tokens).
   - Update `application-docker.properties` to use Spring env placeholders like `db.password=${DB_PASSWORD:changeme}` (and similarly for schema/user/host/port), so compose `.env` changes take effect at runtime.
2) **Keep build-time config, but remove misleading `.env` knobs**
   - Remove `DB_NAME/DB_USER/DB_PASSWORD` from the app service env and from `.env.example` (or make `.env.example` explicitly say you must also edit `application-docker.properties`).
   - Keep DB container env vars, but document that app config is controlled via `application-docker.properties` during build.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right — since Maven bakes application-docker.properties at build time, the DB_* env vars in compose would not actually reach the app. Fixed in c29fa01 and 99b828f: removed the misleading DB_* vars from the app service and updated .env.example to clearly document that DB credentials are configured in application-docker.properties.

- Add 'mariadb' network alias for db service to maintain hostname
  compatibility with Dockerfile and application-docker.properties
- Remove DB port exposure to host (app connects via internal network)
- Remove misleading DB_* env vars from app service since
  application-docker.properties is baked at Maven build time
- Restore original volume mount (.:/code) since build needs write access
- Keep meaningful improvements: healthcheck, named volumes, resource
  limits, dedicated network, configurable app ports
Remove misleading DB_* variables since application-docker.properties
is baked at build time. Add clear note about where to configure
database credentials.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve the Docker-Compose

1 participant