feat: add slim Docker image variant without embedded postgres#3610
feat: add slim Docker image variant without embedded postgres#3610
Conversation
The existing `tolgee/tolgee` image is based on `postgres` to support `postgres-autostart.mode: EMBEDDED`. For production deployments against an external database, the postgres server binaries and their transitive OS packages aren't used at runtime. Add a slim variant built from `eclipse-temurin:21-jre-alpine` that carries only what the application needs. Published alongside the existing image: - tolgee/tolgee:slim (floating, tracks latest) - tolgee/tolgee:<version>-slim The slim image sets `TOLGEE_POSTGRES_AUTOSTART_ENABLED=false` by default since embedded postgres isn't available in this variant; it must be run against an external database. Revives the approach from PR #3193 (stale). Current Dockerfile and default `tolgee/tolgee` tag are unchanged — this is purely additive. Co-authored-by: Matthew Sekirin <matthew.sekirin@gmail.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughIntroduces a new "slim" Docker image variant for Tolgee by adding Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
gradle/docker.gradle (1)
95-123: Consider extracting shared publish logic to reduce duplication.
dockerPublishSlimis nearly identical todockerPublish— the only differences are the tag mapping and the-f Dockerfile.slimflag. If a third variant is ever added, the duplication will compound. A small helper (e.g., a closure takingdockerfileand atagResolver) would DRY this up without changing behavior.♻️ Sketch
def buildxPublish = { String dockerfile, Closure<String> tagResolver -> def version = System.getenv('VERSION') ?: 'latest' def imageName = System.getenv('DOCKER_IMAGE') ?: 'tolgee/tolgee' def tag = tagResolver(imageName, version) def cacheFrom = System.getenv('DOCKER_CACHE_FROM') def cacheTo = System.getenv('DOCKER_CACHE_TO') def cmd = ["docker", "buildx", "build", "."] if (dockerfile) cmd += ["-f", dockerfile] cmd += ["-t", tag, "--build-arg", "OTEL_AGENT_VERSION=${opentelemetryJavaagentVersion}", "--platform", "linux/arm64,linux/amd64", "--push"] if (cacheFrom) cmd += ["--cache-from", cacheFrom] if (cacheTo) cmd += ["--cache-to", cacheTo] exec { workingDir dockerPath; commandLine cmd } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@gradle/docker.gradle` around lines 95 - 123, dockerPublishSlim duplicates dockerPublish; extract the shared logic into a reusable closure (e.g., buildxPublish) that accepts a dockerfile name and a tag-resolver closure, move the environment reads (VERSION, DOCKER_IMAGE, DOCKER_CACHE_FROM, DOCKER_CACHE_TO) and common args (buildx build, OTEL_AGENT_VERSION build-arg, platforms, push) into that closure, then replace the dockerPublishSlim task body to call buildxPublish("Dockerfile.slim", { imageName, version -> /* slim tag logic */ }) and likewise call it from dockerPublish with the default Dockerfile and tag resolver, preserving the existing tag mapping and cache-from/cache-to handling.docker/app/Dockerfile.slim (1)
34-35: Pin the OTEL agent JAR by checksum (optional hardening).The agent JAR is fetched over HTTPS from GitHub Releases without integrity verification. A checksum check (the project publishes
.sha256/.ascalongside the jar) protects the image build from upstream tampering or transient corruption. Same concern applies to the non-slim Dockerfile; feel free to track separately and apply uniformly.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docker/app/Dockerfile.slim` around lines 34 - 35, The Dockerfile.slim RUN step that downloads opentelemetry-javaagent.jar using OTEL_AGENT_VERSION must be hardened by verifying the artifact checksum: fetch the corresponding .sha256 (or .sha256sum/.asc) published alongside the jar (using the same OTEL_AGENT_VERSION), validate the downloaded /app/opentelemetry-javaagent.jar with sha256sum (or gpg verify if using .asc), and fail the build if the verification fails; update the RUN instruction that does wget to also wget the checksum (or signature) and perform the verification before keeping the jar, and apply the same change to the non-slim Dockerfile equivalent so both images are protected from tampered or corrupted releases.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docker/app/Dockerfile.slim`:
- Around line 1-3: The Dockerfile runs as root by default; create and switch to
a non-root user (e.g., user name "tolgee") by adding a user/group creation step,
ensure ownership of runtime directories like /data is changed (chown) so the new
user can write, copy application files as that non-root user (or adjust
ownership after copy), and set USER tolgee before the ENTRYPOINT to run the
container non-root; update any steps that assume root accordingly.
---
Nitpick comments:
In `@docker/app/Dockerfile.slim`:
- Around line 34-35: The Dockerfile.slim RUN step that downloads
opentelemetry-javaagent.jar using OTEL_AGENT_VERSION must be hardened by
verifying the artifact checksum: fetch the corresponding .sha256 (or
.sha256sum/.asc) published alongside the jar (using the same
OTEL_AGENT_VERSION), validate the downloaded /app/opentelemetry-javaagent.jar
with sha256sum (or gpg verify if using .asc), and fail the build if the
verification fails; update the RUN instruction that does wget to also wget the
checksum (or signature) and perform the verification before keeping the jar, and
apply the same change to the non-slim Dockerfile equivalent so both images are
protected from tampered or corrupted releases.
In `@gradle/docker.gradle`:
- Around line 95-123: dockerPublishSlim duplicates dockerPublish; extract the
shared logic into a reusable closure (e.g., buildxPublish) that accepts a
dockerfile name and a tag-resolver closure, move the environment reads (VERSION,
DOCKER_IMAGE, DOCKER_CACHE_FROM, DOCKER_CACHE_TO) and common args (buildx build,
OTEL_AGENT_VERSION build-arg, platforms, push) into that closure, then replace
the dockerPublishSlim task body to call buildxPublish("Dockerfile.slim", {
imageName, version -> /* slim tag logic */ }) and likewise call it from
dockerPublish with the default Dockerfile and tag resolver, preserving the
existing tag mapping and cache-from/cache-to handling.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bae4c2b4-b78c-46bb-821a-5f6e662feb93
📒 Files selected for processing (3)
.github/workflows/release.ymldocker/app/Dockerfile.slimgradle/docker.gradle
Summary
Adds a new
tolgee/tolgee:slimDocker image variant built oneclipse-temurin:21-jre-alpine, alongside the existingtolgee/tolgeeimage. No breaking changes — the default image and its behavior are untouched.Why: the current
tolgee/tolgeeimage usesFROM postgres:…so thatpostgres-autostart.mode: EMBEDDEDcan spawn a postgres instance inside the container (nice fordocker runevaluations). Production deployments run Tolgee against an external, managed postgres and don't use the embedded server — but still pay the cost of all the postgres binaries and their transitive OS packages in the image. The slim variant carries only what the application actually needs.What ships
tolgee/tolgee:slimtolgee/tolgee:<version>-slim<version>The slim image:
eclipse-temurin:21-jre-alpine(JRE only, no JDK).bash(needed bycmd.sh).TOLGEE_POSTGRES_AUTOSTART_ENABLED=falseby default — slim doesn't bundle postgres, so the autostart machinery would fail; the variant must be run against an external database.cmd.sh, healthcheck, exposed port, and/datavolume as the default image.The default
Dockerfileandtolgee/tolgeetag are unchanged.Changes
docker/app/Dockerfile.slim— new Dockerfile for the slim variant.gradle/docker.gradle— addsdockerSlim(local build) anddockerPublishSlim(multi-arch CI publish)..github/workflows/release.yml— release job now also runsdockerPublishSlimfor both the versioned tag andlatest.Relationship to #3193
This revives the idea from #3193 (stale). That PR initially swapped the default image to non-postgres, then (per review feedback) switched to an additive
Dockerfile.lite. This PR takes the additive approach through to the finish line — adds the CI plumbing, aligns with the OTEL changes made since that PR was opened, and usesslim(standard Docker-world naming) instead oflite.Thanks to @transparentChange for the original work. Leaving #3193 open for now so the discussion there remains linked.
Test plan
./gradlew dockerSlimbuilds the image locally.docker run --rm -e SPRING_DATASOURCE_URL=... tolgee/tolgee:slimstarts the app against an external postgres./actuator/health.OTEL_JAVAAGENT_ENABLED=true.:${version}-slimand:slimtags.tolgee/tolgeeimage continues to build and publish unchanged.Follow-ups (out of scope)
🤖 Generated with Claude Code