Skip to content

Commit 9c669fc

Browse files
committed
build: add Docker-based development environment
Dockerfile.dev builds OLR with all optional dependencies (Oracle client, Kafka, Protobuf, Prometheus) and ccache for fast incremental rebuilds. docker-compose.yaml provides olr dev container + Oracle Free for testing. Root Makefile handles build with dynamic uid/gid and buildx layer cache.
1 parent dabeb4b commit 9c669fc

6 files changed

Lines changed: 299 additions & 0 deletions

File tree

.dockerignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.git/
2+
.github/
3+
oracle-rac/
4+
tests/0-inputs/
5+
tests/1-schema/
6+
tests/2-redo/
7+
tests/3-expected/
8+
tests/.work/
9+
tests/scripts/

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
build/
2+
cmake-build-*/
3+
.idea/
4+
.vscode/
5+
*.swp
6+
*~
7+
.DS_Store
8+
tests/.work/
9+
tests/1-schema/
10+
tests/2-redo/
11+
tests/3-expected/

Dockerfile.dev

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# syntax=docker/dockerfile:1
2+
#
3+
# Dockerfile.dev — Optimized for local dev builds
4+
# Splits dependencies into cached layers + uses ccache for incremental compilation.
5+
#
6+
# Usage:
7+
# GIDOLR=$(id -g) UIDOLR=$(id -u) docker compose build olr
8+
9+
ARG IMAGE=debian
10+
ARG VERSION=13.0
11+
FROM ${IMAGE}:${VERSION}
12+
13+
ARG ARCH=x86_64
14+
ARG GIDOLR=1001
15+
ARG UIDOLR=1001
16+
ARG GIDORA=54322
17+
ARG BUILD_TYPE=Debug
18+
ARG WITHKAFKA
19+
ARG WITHPROMETHEUS
20+
ARG WITHORACLE
21+
ARG WITHPROTOBUF
22+
ARG WITHTESTS
23+
24+
ENV LC_ALL=C
25+
ENV LANG=en_US.UTF-8
26+
ENV ORACLE_MAJOR=23
27+
ENV ORACLE_MINOR=26
28+
ENV PROTOBUF_VERSION_DIR=21.12
29+
ENV PROTOBUF_VERSION=3.21.12
30+
ENV RAPIDJSON_VERSION=1.1.0
31+
ENV LIBRDKAFKA_VERSION=2.13.0
32+
ENV PROMETHEUS_VERSION=1.3.0
33+
ENV OPENLOGREPLICATOR_VERSION=local
34+
ENV LD_LIBRARY_PATH=/opt/instantclient_${ORACLE_MAJOR}_${ORACLE_MINOR}:/opt/librdkafka/lib:/opt/prometheus/lib:/opt/protobuf/lib
35+
ENV BUILDARGS="-DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DWITH_RAPIDJSON=/opt/rapidjson -S ../ -B ./"
36+
ENV BUILDARGS="${BUILDARGS}${WITHKAFKA:+ -DWITH_RDKAFKA=/opt/librdkafka}"
37+
ENV BUILDARGS="${BUILDARGS}${WITHPROMETHEUS:+ -DWITH_PROMETHEUS=/opt/prometheus}"
38+
ENV BUILDARGS="${BUILDARGS}${WITHORACLE:+ -DWITH_OCI=/opt/instantclient_${ORACLE_MAJOR}_${ORACLE_MINOR}}"
39+
ENV BUILDARGS="${BUILDARGS}${WITHPROTOBUF:+ -DWITH_PROTOBUF=/opt/protobuf}"
40+
ENV BUILDARGS="${BUILDARGS}${WITHTESTS:+ -DWITH_TESTS=ON}"
41+
ENV COMPILEKAFKA="${WITHKAFKA:+1}"
42+
ENV COMPILEPROMETHEUS="${WITHPROMETHEUS:+1}"
43+
ENV COMPILEORACLE="${WITHORACLE:+1}"
44+
ENV COMPILEPROTOBUF="${WITHPROTOBUF:+1}"
45+
ENV DEBIAN_FRONTEND=noninteractive
46+
47+
COPY scripts/run.sh /opt
48+
49+
# Layer 1: System packages + ccache
50+
RUN set -eu && \
51+
apt-get update && \
52+
apt-get -y install file gcc g++ libaio1t64 libasan8 libubsan1 libtool libz-dev make patch unzip wget cmake git curl ccache && \
53+
ln -s libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1
54+
55+
# Layer 2: RapidJSON
56+
RUN set -eu && \
57+
cd /opt && \
58+
wget -q https://github.com/Tencent/rapidjson/archive/refs/tags/v${RAPIDJSON_VERSION}.tar.gz && \
59+
tar xzf v${RAPIDJSON_VERSION}.tar.gz && \
60+
rm v${RAPIDJSON_VERSION}.tar.gz && \
61+
ln -s rapidjson-${RAPIDJSON_VERSION} rapidjson && \
62+
if [ "${RAPIDJSON_VERSION}" = "1.1.0" ]; then \
63+
cd rapidjson && \
64+
wget -q https://github.com/Tencent/rapidjson/commit/3b2441b87f99ab65f37b141a7b548ebadb607b96.diff && \
65+
patch -p1 < 3b2441b87f99ab65f37b141a7b548ebadb607b96.diff && \
66+
rm 3b2441b87f99ab65f37b141a7b548ebadb607b96.diff ; \
67+
fi
68+
69+
# Layer 3: Oracle Instant Client
70+
RUN set -eu && \
71+
if [ "${COMPILEORACLE}" != "" ]; then \
72+
cd /opt && \
73+
wget -q https://download.oracle.com/otn_software/linux/instantclient/${ORACLE_MAJOR}${ORACLE_MINOR}000/instantclient-basic-linux.x64-${ORACLE_MAJOR}.${ORACLE_MINOR}.0.0.0.zip && \
74+
unzip -o instantclient-basic-linux.x64-${ORACLE_MAJOR}.${ORACLE_MINOR}.0.0.0.zip && \
75+
rm instantclient-basic-linux.x64-${ORACLE_MAJOR}.${ORACLE_MINOR}.0.0.0.zip && \
76+
rm -rf META-INF && \
77+
wget -q https://download.oracle.com/otn_software/linux/instantclient/${ORACLE_MAJOR}${ORACLE_MINOR}000/instantclient-sdk-linux.x64-${ORACLE_MAJOR}.${ORACLE_MINOR}.0.0.0.zip && \
78+
unzip -o instantclient-sdk-linux.x64-${ORACLE_MAJOR}.${ORACLE_MINOR}.0.0.0.zip && \
79+
rm instantclient-sdk-linux.x64-${ORACLE_MAJOR}.${ORACLE_MINOR}.0.0.0.zip && \
80+
rm -rf META-INF ; \
81+
fi
82+
83+
# Layer 4: Protobuf (~5-7 min, cached unless version changes)
84+
RUN set -eu && \
85+
if [ "${COMPILEPROTOBUF}" != "" ]; then \
86+
cd /opt && \
87+
wget -q https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION_DIR}/protobuf-cpp-${PROTOBUF_VERSION}.tar.gz && \
88+
tar xzf protobuf-cpp-${PROTOBUF_VERSION}.tar.gz && \
89+
rm protobuf-cpp-${PROTOBUF_VERSION}.tar.gz && \
90+
cd /opt/protobuf-${PROTOBUF_VERSION} && \
91+
./configure --prefix=/opt/protobuf && \
92+
make && \
93+
make install ; \
94+
fi
95+
96+
# Layer 5: librdkafka (~2-3 min, cached unless version changes)
97+
RUN set -eu && \
98+
if [ "${COMPILEKAFKA}" != "" ]; then \
99+
cd /opt && \
100+
wget -q https://github.com/confluentinc/librdkafka/archive/refs/tags/v${LIBRDKAFKA_VERSION}.tar.gz && \
101+
tar xzf v${LIBRDKAFKA_VERSION}.tar.gz && \
102+
rm v${LIBRDKAFKA_VERSION}.tar.gz && \
103+
cd /opt/librdkafka-${LIBRDKAFKA_VERSION} && \
104+
./configure --prefix=/opt/librdkafka && \
105+
make && \
106+
make install ; \
107+
fi
108+
109+
# Layer 6: Prometheus
110+
RUN set -eu && \
111+
if [ "${COMPILEPROMETHEUS}" != "" ]; then \
112+
cd /opt && \
113+
wget -q https://github.com/jupp0r/prometheus-cpp/releases/download/v${PROMETHEUS_VERSION}/prometheus-cpp-with-submodules.tar.gz && \
114+
tar xzf prometheus-cpp-with-submodules.tar.gz && \
115+
rm prometheus-cpp-with-submodules.tar.gz && \
116+
cd /opt/prometheus-cpp-with-submodules && \
117+
mkdir _build && \
118+
cd _build && \
119+
cmake .. -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX:PATH=/opt/prometheus -DENABLE_PUSH=OFF -DENABLE_COMPRESSION=OFF && \
120+
cmake --build . --parallel 4 && \
121+
ctest -V && \
122+
cmake --install . ; \
123+
fi
124+
125+
# --- Source changes only invalidate from here down ---
126+
COPY . /opt/OpenLogReplicator-local
127+
128+
# Layer 7: Build OLR (ccache persists across rebuilds via BuildKit cache mount)
129+
RUN --mount=type=cache,target=/root/.ccache,id=olr-ccache \
130+
set -eu && \
131+
export CCACHE_DIR=/root/.ccache && \
132+
cd /opt/OpenLogReplicator-local && \
133+
if [ "${COMPILEPROTOBUF}" != "" ]; then \
134+
cd proto && \
135+
/opt/protobuf/bin/protoc OraProtoBuf.proto --cpp_out=. && \
136+
mv OraProtoBuf.pb.cc ../src/common/OraProtoBuf.pb.cpp && \
137+
mv OraProtoBuf.pb.h ../src/common/OraProtoBuf.pb.h && \
138+
cd .. ; \
139+
fi && \
140+
mkdir cmake-build-${BUILD_TYPE}-${ARCH} && \
141+
cd cmake-build-${BUILD_TYPE}-${ARCH} && \
142+
cmake ${BUILDARGS} \
143+
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
144+
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache && \
145+
cmake --build ./ --target OpenLogReplicator -j && \
146+
if [ "${WITHTESTS}" != "" ]; then \
147+
cmake --build ./ --target olr_tests -j ; \
148+
fi && \
149+
mkdir -p /opt/OpenLogReplicator/log /opt/OpenLogReplicator/tmp /opt/OpenLogReplicator/scripts && \
150+
cp ./OpenLogReplicator /opt/OpenLogReplicator && \
151+
cp -p /opt/OpenLogReplicator-local/scripts/gencfg.sql /opt/OpenLogReplicator/scripts/gencfg.sql
152+
153+
# Layer 8: User setup
154+
RUN set -eu && \
155+
mkdir -p /home/user1 && \
156+
groupadd -g ${GIDOLR} user1 && \
157+
if [ "${GIDOLR}" != "${GIDORA}" ]; then \
158+
groupadd -g ${GIDORA} oracle && \
159+
useradd -u ${UIDOLR} user1 -g user1 -G oracle -d /home/user1 ; \
160+
else \
161+
useradd -u ${UIDOLR} user1 -g user1 -d /home/user1 ; \
162+
fi && \
163+
chown -R user1:user1 /home/user1 && \
164+
chown -R user1:user1 /opt/OpenLogReplicator && \
165+
chown -R user1:user1 /opt/OpenLogReplicator-local/cmake-build-*
166+
167+
USER user1:oracle
168+
RUN set -eu && \
169+
export LD_LIBRARY_PATH=/opt/instantclient_${ORACLE_MAJOR}_${ORACLE_MINOR}:/opt/librdkafka/lib:/opt/prometheus/lib:/opt/protobuf/lib && \
170+
/opt/OpenLogReplicator/OpenLogReplicator --version
171+
172+
WORKDIR /opt/OpenLogReplicator
173+
ENTRYPOINT ["/opt/run.sh"]

Makefile

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
OLR_IMAGE ?= olr-dev:latest
2+
CACHE_IMAGE ?= ghcr.io/bersler/openlogreplicator:ci
3+
BUILD_TYPE ?= Debug
4+
OLR_BUILD_DIR ?= /opt/OpenLogReplicator-local/cmake-build-$(BUILD_TYPE)-x86_64
5+
SCENARIO ?=
6+
7+
.PHONY: build up down test testdata clean
8+
9+
build:
10+
docker buildx build \
11+
--build-arg BUILD_TYPE=$(BUILD_TYPE) \
12+
--build-arg UIDOLR=$$(id -u) \
13+
--build-arg GIDOLR=$$(id -g) \
14+
--build-arg GIDORA=54322 \
15+
--build-arg WITHORACLE=1 \
16+
--build-arg WITHKAFKA=1 \
17+
--build-arg WITHPROTOBUF=1 \
18+
--build-arg WITHPROMETHEUS=1 \
19+
--build-arg WITHTESTS=1 \
20+
--cache-from type=registry,ref=$(CACHE_IMAGE) \
21+
-t $(OLR_IMAGE) \
22+
--load \
23+
-f Dockerfile.dev .
24+
25+
up:
26+
docker compose up -d --wait
27+
28+
down:
29+
docker compose down
30+
31+
test:
32+
docker compose exec olr ctest --test-dir $(OLR_BUILD_DIR) --output-on-failure
33+
34+
testdata:
35+
ifdef SCENARIO
36+
tests/scripts/generate.sh $(SCENARIO)
37+
else
38+
@for sql in tests/0-inputs/*.sql; do \
39+
name=$$(basename "$$sql" .sql); \
40+
echo "=== Generating: $$name ==="; \
41+
tests/scripts/generate.sh "$$name" || exit 1; \
42+
done
43+
endif
44+
45+
clean:
46+
rm -rf tests/1-schema tests/2-redo tests/3-expected tests/.work

docker-compose.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
services:
2+
olr:
3+
image: olr-dev:${OLR_IMAGE_TAG:-latest}
4+
entrypoint: []
5+
command: ["sleep", "infinity"]
6+
volumes:
7+
- ./tests:/opt/OpenLogReplicator-local/tests
8+
9+
oracle:
10+
image: gvenzl/oracle-free:23-slim-faststart
11+
container_name: oracle
12+
ports:
13+
- "1521:1521"
14+
environment:
15+
ORACLE_PASSWORD: oracle
16+
APP_USER: olr_test
17+
APP_USER_PASSWORD: olr_test
18+
volumes:
19+
- ./tests/scripts/oracle-init:/container-entrypoint-initdb.d
20+
healthcheck:
21+
test: ["CMD", "healthcheck.sh"]
22+
interval: 10s
23+
timeout: 5s
24+
retries: 30

scripts/run.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/sh
2+
# Start script for Docker
3+
# Copyright (C) 2018-2026 Adam Leszczynski (aleszczynski@bersler.com)
4+
#
5+
# This file is part of OpenLogReplicator
6+
#
7+
# Open Log Replicator is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License as published
9+
# by the Free Software Foundation; either version 3, or (at your option)
10+
# any later version.
11+
#
12+
# Open Log Replicator is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15+
# Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with Open Log Replicator; see the file LICENSE.txt If not see
19+
# <http://www.gnu.org/licenses/>.
20+
21+
cd /opt/OpenLogReplicator
22+
FLAG_FILE=/opt/OpenLogReplicator/log/.olr_started.flag
23+
if [ -x /opt/bin/OpenLogReplicator ]; then
24+
OLR_EXEC=/opt/bin/OpenLogReplicator
25+
else
26+
OLR_EXEC=./OpenLogReplicator
27+
fi
28+
29+
if [ ! -f "$FLAG_FILE" ]; then
30+
# first execution, provided arguments for startup
31+
touch "$FLAG_FILE"
32+
${OLR_EXEC} "$@" 2>&1 | tee -a /opt/OpenLogReplicator/log/OpenLogReplicator.err
33+
else
34+
# subsequent execution, start normally
35+
${OLR_EXEC} 2>&1 | tee -a /opt/OpenLogReplicator/log/OpenLogReplicator.err
36+
fi

0 commit comments

Comments
 (0)