Skip to content

feat: add multi-stage production Dockerfile#20

Merged
rophy merged 2 commits intomasterfrom
feat/dockerfile-release
Apr 11, 2026
Merged

feat: add multi-stage production Dockerfile#20
rophy merged 2 commits intomasterfrom
feat/dockerfile-release

Conversation

@rophy
Copy link
Copy Markdown
Owner

@rophy rophy commented Apr 11, 2026

Summary

  • Add Dockerfile.release for minimal production images using multi-stage build
    • Stage 1 (builder): compiles OLR with all optional deps (Oracle, Kafka, Protobuf, Prometheus)
    • Stage 2 (runtime): copies only binary + runtime shared libs into clean Debian image
    • Defaults to BUILD_TYPE=Release
    • Image size: 1.48 GB (down from 6.55 GB dev image)
  • Fix missing VM_HOST env var in tests/dbz-twin/rac/docker-compose.yaml (broken since 7696dfc)

Test plan

  • Built image locally: docker buildx build -f Dockerfile.release with all modules enabled
  • Verified binary runs: --version prints correct build info (Release, all modules)
  • Transferred to RAC VM via docker save / podman load (339 MB compressed)
  • Ran dbz-twin RAC test with release image — OLR captured events correctly, matched LogMiner output

Summary by CodeRabbit

  • Chores
    • Added a new multi-stage container build that optionally includes select components and produces a minimized runtime image for more efficient deployments.
    • Runtime image now runs under a non-root user with required runtime libraries staged for startup and performs basic executable validation during build.
    • Test compose configuration now requires a VM_HOST environment variable for relevant services to ensure correct runtime networking.

Add Dockerfile.release for minimal production images. Uses multi-stage
build: compile in full builder, copy only binary + runtime shared libs
into clean Debian image. Defaults to Release build type.

Also fix missing VM_HOST env var in dbz-twin RAC docker-compose.yaml,
broken since 7696dfc.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f46f819c-b8b7-45a5-a7ce-5cd722fa0697

📥 Commits

Reviewing files that changed from the base of the PR and between c261bf9 and 8b67af9.

📒 Files selected for processing (1)
  • Dockerfile.release
🚧 Files skipped from review as they are similar to previous changes (1)
  • Dockerfile.release

📝 Walkthrough

Walkthrough

Adds Dockerfile.release implementing a two-stage build that conditionally compiles optional components (Oracle, Protobuf, librdkafka, prometheus-cpp) and stages runtime libs; also updates a docker-compose file to require VM_HOST for two services.

Changes

Cohort / File(s) Summary
New Production Dockerfile
Dockerfile.release
Adds two-stage multi-stage build. Builder stage installs build tools, conditionally fetches/builds third-party deps, generates Protobuf sources, runs CMake to build OpenLogReplicator, stages selected shared libs to /opt/runtime-libs, and runs OpenLogReplicator --version. Runtime stage installs minimal runtime packages, creates parameterized user/group (UIDOLR/GIDOLR, optional GIDORA), copies binary, scripts and staged libs into /opt/, sets LD_LIBRARY_PATH, creates runtime directories, switches to non-root user, runs OpenLogReplicator --version, sets WORKDIR, and sets ENTRYPOINT ["/opt/run.sh"]. Exposes build-time ARGs: IMAGE, VERSION, ARCH, BUILD_TYPE, feature toggles WITHORACLE, WITHKAFKA, WITHPROTOBUF, WITHPROMETHEUS, and IDs GIDOLR, UIDOLR, GIDORA.
Docker Compose Configuration
tests/dbz-twin/rac/docker-compose.yaml
Adds mandatory VM_HOST environment variable to dbz-logminer and dbz-olr services using ${VM_HOST:?VM_HOST is required}.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant CI as CI / Developer
participant Builder as Builder Image
participant Ext as External Package Sources
participant CMake as CMake/Build System
participant Runtime as Runtime Image / Container

CI->>Builder: build with ARGs (WITHORACLE, WITHKAFKA, WITHPROTOBUF, WITHPROMETHEUS, UIDOLR/GIDOLR...)
Builder->>Ext: download headers/libs (RapidJSON, Protobuf, librdkafka, prometheus-cpp, Oracle)
Builder->>CMake: configure with generated BUILDARGS
CMake->>Builder: build OpenLogReplicator and shared libs
Builder->>Builder: stage selected libs to /opt/runtime-libs
Builder->>Runtime: copy binary, scripts, and staged libs into image
Runtime->>Runtime: install minimal runtime deps, create user/group, set LD_LIBRARY_PATH
Runtime->>Runtime: run OpenLogReplicator --version (sanity check)
CI->>Runtime: run container (ENTRYPOINT /opt/run.sh)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through builds and fetched each lib,
Staged tiny runtimes, kept the image sib,
Protobuf and Oracle danced in the night,
Now runtime wakes, lean, ready to flight. ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a multi-stage production Dockerfile that produces a minimal container image.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/dockerfile-release

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
Dockerfile.release (3)

50-54: Consider adding --no-install-recommends for faster builds.

While this builder stage is discarded, using --no-install-recommends would reduce build time and layer size during the build process.

♻️ Proposed fix
 RUN set -eu && \
     apt-get update && \
-    apt-get -y install file gcc g++ libaio1t64 libasan8 libubsan1 libtool libz-dev make patch unzip wget cmake git curl && \
+    apt-get -y install --no-install-recommends file gcc g++ libaio1t64 libasan8 libubsan1 libtool libz-dev make patch unzip wget cmake git curl && \
     ln -s libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile.release` around lines 50 - 54, The apt-get install command in the
RUN step that installs system packages should use the --no-install-recommends
flag to avoid pulling unnecessary recommended packages and speed up builds;
update the RUN command that calls apt-get -y install (the line installing file
gcc g++ libaio1t64 libasan8 libubsan1 libtool libz-dev make patch unzip wget
cmake git curl and the ln -s step) to include --no-install-recommends (and
optionally follow with apt-get clean && rm -rf /var/lib/apt/lists/* in the same
RUN to reduce image layer size).

93-94: Consider parallel builds for faster compilation.

The protobuf make runs single-threaded while prometheus (line 121) uses --parallel 4. Using make -j$(nproc) would speed up builds significantly.

♻️ Proposed fix for protobuf
     ./configure --prefix=/opt/protobuf && \
-    make && \
+    make -j$(nproc) && \
     make install ; \

Same applies to librdkafka at lines 106-107.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile.release` around lines 93 - 94, Replace the single-threaded build
invocations for protobuf and librdkafka by running make with parallelism;
specifically update the occurrences of "make && \ make install ; \" (the
protobuf build block) and the librdkafka "make && make install" invocations to
use "make -j$(nproc)" (or another parallel flag) so compilation uses all
available CPUs and matches the existing prometheus "--parallel 4" approach.

56-82: Future consideration: consolidate duplicated build logic with Dockerfile.dev.

The RapidJSON and Oracle Instant Client build steps are nearly identical to Dockerfile.dev (context snippets show ~100% duplication). Consider extracting shared build scripts or using a common builder base image to reduce maintenance burden.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile.release` around lines 56 - 82, The RapidJSON and Oracle Instant
Client RUN blocks duplicate logic from Dockerfile.dev; extract those steps into
shared artifacts and replace the inline blocks with simple invocations: either
move the RapidJSON and Oracle install commands (the RUN sequences using
RAPIDJSON_VERSION, the rapidjson patch step, and the
COMPILEORACLE/ORACLE_MAJOR/ORACLE_MINOR instantclient logic) into reusable shell
scripts (e.g., scripts/install_rapidjson.sh and scripts/install_oracle.sh) and
call them from both Dockerfiles, or create a common builder/base image that
performs those installs and then FROM that image in both Dockerfile.release and
Dockerfile.dev; ensure ARGs (RAPIDJSON_VERSION, COMPILEORACLE, ORACLE_MAJOR,
ORACLE_MINOR) are preserved and the rapidjson patch step is kept when
RAPIDJSON_VERSION == "1.1.0".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Dockerfile.release`:
- Line 222: The Dockerfile unconditionally sets USER user1:oracle which fails
when GIDOLR == GIDORA because the oracle group isn't created; either make the
USER fallback to user1 (no group) when the oracle group wasn't created or ensure
the oracle group is always created when creating user1. Locate the USER
user1:oracle statement and change the logic so it checks whether the oracle
group was actually created (based on the GIDOLR vs GIDORA condition) and only
uses user1:oracle when the group exists, otherwise use just user1; alternatively
modify the earlier group-creation branch (the code that handles GIDOLR/GIDORA)
to always create the oracle group so USER user1:oracle is safe.

---

Nitpick comments:
In `@Dockerfile.release`:
- Around line 50-54: The apt-get install command in the RUN step that installs
system packages should use the --no-install-recommends flag to avoid pulling
unnecessary recommended packages and speed up builds; update the RUN command
that calls apt-get -y install (the line installing file gcc g++ libaio1t64
libasan8 libubsan1 libtool libz-dev make patch unzip wget cmake git curl and the
ln -s step) to include --no-install-recommends (and optionally follow with
apt-get clean && rm -rf /var/lib/apt/lists/* in the same RUN to reduce image
layer size).
- Around line 93-94: Replace the single-threaded build invocations for protobuf
and librdkafka by running make with parallelism; specifically update the
occurrences of "make && \ make install ; \" (the protobuf build block) and the
librdkafka "make && make install" invocations to use "make -j$(nproc)" (or
another parallel flag) so compilation uses all available CPUs and matches the
existing prometheus "--parallel 4" approach.
- Around line 56-82: The RapidJSON and Oracle Instant Client RUN blocks
duplicate logic from Dockerfile.dev; extract those steps into shared artifacts
and replace the inline blocks with simple invocations: either move the RapidJSON
and Oracle install commands (the RUN sequences using RAPIDJSON_VERSION, the
rapidjson patch step, and the COMPILEORACLE/ORACLE_MAJOR/ORACLE_MINOR
instantclient logic) into reusable shell scripts (e.g.,
scripts/install_rapidjson.sh and scripts/install_oracle.sh) and call them from
both Dockerfiles, or create a common builder/base image that performs those
installs and then FROM that image in both Dockerfile.release and Dockerfile.dev;
ensure ARGs (RAPIDJSON_VERSION, COMPILEORACLE, ORACLE_MAJOR, ORACLE_MINOR) are
preserved and the rapidjson patch step is kept when RAPIDJSON_VERSION ==
"1.1.0".
🪄 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: e8d2a558-5705-460d-8706-a114e0cf0dfb

📥 Commits

Reviewing files that changed from the base of the PR and between b9f7e48 and c261bf9.

📒 Files selected for processing (2)
  • Dockerfile.release
  • tests/dbz-twin/rac/docker-compose.yaml

Comment thread Dockerfile.release Outdated
- Fix USER directive: use 'user1' instead of 'user1:oracle' since the
  oracle group is not created when GIDOLR == GIDORA
- Add --no-install-recommends to builder apt-get
@rophy rophy merged commit da2d6d8 into master Apr 11, 2026
2 checks passed
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.

1 participant