Skip to content

Commit 8bcdd26

Browse files
danolivoclaude
andcommitted
Add multi-node Spock cluster setup with automated testing
- Enable TCP/IP connections (listen_addresses, pg_hba.conf) - Implement sequential startup: n2/n3 depend on n1 health - Use Z0DAN spock.add_node() for n2/n3 cluster joining - Add exception log and conflict resolution tests - Integrate spockbench 3-node testing framework Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 064127a commit 8bcdd26

File tree

3 files changed

+396
-166
lines changed

3 files changed

+396
-166
lines changed

tests/docker/Dockerfile-step-1.el9

Lines changed: 190 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,162 @@
1-
FROM ghcr.io/pgedge/base-test-image:latest
1+
# syntax=docker/dockerfile:1
22

3-
# Base image ends as USER pgedge, but we need root for installation
4-
USER root
3+
# ==============================================================================
4+
# PostgreSQL + Spock + Spockbench
5+
# ==============================================================================
6+
#
7+
# Description:
8+
# Builds PostgreSQL from source with Spock-specific patches, compiles
9+
# the Spock logical replication extension for testing and development,
10+
# installs spockbench.
11+
# Source and installation paths declared in the ${HOME}/.bashrc
12+
#
13+
# Versions:
14+
# - Postgres version to be used is identified by the PGVER variable.
15+
# - Spockbench is built from the top commit on the 'master' branch.
16+
# - Spock code comes from the parent docker directory
17+
#
18+
# Base Image:
19+
# Defined by the BASE_IMAGE environment variable.
20+
#
21+
# Build Arguments (defaults aligned with the pgedge.env file):
22+
# BASE_IMAGE - Base image to use
23+
# PGVER - PostgreSQL major version
24+
# DBUSER - PostgreSQL superuser name
25+
# DBPASSWD - PostgreSQL superuser password
26+
# DBNAME - Default database name
27+
# DBPORT - PostgreSQL port
28+
# MAKE_JOBS - Parallel make jobs
29+
#
30+
# Runtime:
31+
# Runs entrypoint.sh which initializes PostgreSQL and loads environment
32+
# variables from /home/pgedge/.bashrc. On restart, entrypoint runs again
33+
# but skips initialization if PGDATA already exists.
34+
#
35+
# References:
36+
# See Dockerfile-base.el9, docker-compose.yml, and cache-base-image.yml for
37+
# further details.
38+
# ==============================================================================
39+
40+
ARG BASE_IMAGE=base-test-image:latest
41+
FROM ${BASE_IMAGE}
42+
43+
# ==============================================================================
44+
# Build Arguments and Environment Variables
45+
# ==============================================================================
546

6-
ARG PGVER
47+
ARG PGVER=17
48+
ARG DBUSER=admin
49+
ARG DBPASSWD=testpass
50+
ARG DBNAME=demo
51+
ARG DBPORT=5432
752
ARG MAKE_JOBS=4
853

9-
ENV PGVER=$PGVER
10-
ENV PATH="/home/pgedge/pgedge/pg${PGVER}/bin:${PATH}"
11-
ENV LD_LIBRARY_PATH="/home/pgedge/pgedge/pg${PGVER}/lib:${LD_LIBRARY_PATH}"
12-
ENV PG_CONFIG="/home/pgedge/pgedge/pg${PGVER}/bin/pg_config"
54+
# Export as environment variables for build-time and runtime
55+
ENV PGVER=${PGVER} \
56+
DBUSER=${DBUSER} \
57+
DBPASSWD=${DBPASSWD} \
58+
DBNAME=${DBNAME} \
59+
DBPORT=${DBPORT}
60+
61+
# PostgreSQL paths
62+
ENV PATH="/home/pgedge/pgedge:/home/pgedge/pgedge/pg${PGVER}/bin:${PATH}" \
63+
LD_LIBRARY_PATH="/home/pgedge/pgedge/pg${PGVER}/lib" \
64+
PG_CONFIG="/home/pgedge/pgedge/pg${PGVER}/bin/pg_config" \
65+
PGDATA="/home/pgedge/pgedge/data/pg${PGVER}"
66+
67+
# Document exposed port
68+
EXPOSE 5432
69+
70+
# ==============================================================================
71+
# User Configuration and Source Code Setup
72+
# ==============================================================================
73+
74+
USER root
75+
76+
# Write PostgreSQL environment to .bashrc for interactive shells and entrypoint
77+
RUN set -eux && \
78+
{ \
79+
echo "# PostgreSQL Environment"; \
80+
echo "export PGVER=${PGVER}"; \
81+
echo "export PGUSER=${DBUSER}"; \
82+
echo "export PGPASSWORD=${DBPASSWD}"; \
83+
echo "export PGDATABASE=${DBNAME}"; \
84+
echo "export PGPORT=${DBPORT}"; \
85+
echo "export PG_CONFIG=${PG_CONFIG}"; \
86+
echo "export PATH=${PATH}"; \
87+
echo "export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"; \
88+
echo "export PGDATA=${PGDATA}"; \
89+
} >> /home/pgedge/.bashrc
1390

14-
# Copy spock source code and set proper ownership
91+
# Copy Spock source code and test scripts
1592
COPY . /home/pgedge/spock
16-
RUN chown -R pgedge:pgedge /home/pgedge/spock
93+
COPY --chmod=755 tests/docker/*.sh /home/pgedge/
94+
95+
# Set proper ownership
96+
RUN chown -R pgedge:pgedge /home/pgedge/
1797

98+
# ==============================================================================
99+
# Switch to Non-Root User for Builds
100+
# ==============================================================================
101+
102+
USER pgedge
18103
WORKDIR /home/pgedge
19104

20-
# Determine PostgreSQL version and clone repository
21-
RUN LATEST_TAG=$(git ls-remote --tags https://github.com/postgres/postgres.git | \
22-
grep "refs/tags/REL_${PGVER}_" | \
23-
sed 's|.*refs/tags/||' | \
24-
tr '_' '.' | \
25-
sort -V | \
26-
tail -n 1 | \
27-
tr '.' '_') && \
28-
echo "Using PostgreSQL tag: $LATEST_TAG" && \
29-
git clone --branch $LATEST_TAG --depth 1 https://github.com/postgres/postgres /home/pgedge/postgres && \
30-
chmod -R a+w /home/pgedge/postgres
31-
32-
# Install pgedge (run as pgedge user, not root)
33-
RUN echo "Setting up pgedge..." && \
34-
curl -fsSL https://pgedge-download.s3.amazonaws.com/REPO/install.py -o /home/pgedge/install.py && \
35-
chown pgedge:pgedge /home/pgedge/install.py && \
36-
su - pgedge -c "python3 /home/pgedge/install.py"
105+
# ==============================================================================
106+
# Clone PostgreSQL Source
107+
# ==============================================================================
108+
109+
# Determine the latest stable tag for the requested PostgreSQL major version
110+
RUN set -eux && \
111+
LATEST_TAG=$(git ls-remote --tags https://github.com/postgres/postgres.git | \
112+
grep "refs/tags/REL_${PGVER}_" | \
113+
sed 's|.*refs/tags/||' | \
114+
tr '_' '.' | \
115+
sort -V | \
116+
tail -n 1 | \
117+
tr '.' '_') && \
118+
echo "Cloning PostgreSQL tag: ${LATEST_TAG}" && \
119+
git clone --branch "${LATEST_TAG}" --depth 1 \
120+
https://github.com/postgres/postgres.git /home/pgedge/postgres
121+
122+
# ==============================================================================
123+
# Clone Spockbench Testing Framework
124+
# ==============================================================================
125+
126+
# Clone spockbench for testing workloads
127+
# TODO: Pin to specific tag/commit for reproducibility
128+
RUN set -eux && \
129+
git clone --branch master --depth 1 \
130+
https://github.com/pgEdge/spockbench.git /home/pgedge/spockbench && \
131+
echo "export SPOCKBENCH_SOURCE_DIR=/home/pgedge/spockbench" >> /home/pgedge/.bashrc
132+
133+
# ==============================================================================
134+
# Apply Spock Patches to PostgreSQL
135+
# ==============================================================================
37136

38137
WORKDIR /home/pgedge/postgres
39138

40-
RUN for patchfile in /home/pgedge/spock/patches/${PGVER}/*; do \
41-
patch -p1 --verbose < $patchfile; \
42-
done
139+
RUN set -eux && \
140+
PATCH_DIR="/home/pgedge/spock/patches/${PGVER}" && \
141+
if [ -d "${PATCH_DIR}" ] && [ -n "$(ls -A "${PATCH_DIR}" 2>/dev/null)" ]; then \
142+
echo "Applying Spock patches for PostgreSQL ${PGVER}:"; \
143+
for patchfile in "${PATCH_DIR}"/*; do \
144+
echo " - $(basename "${patchfile}")"; \
145+
patch -p1 --verbose < "${patchfile}"; \
146+
done; \
147+
echo "All patches applied successfully"; \
148+
else \
149+
echo "No patches found for PostgreSQL ${PGVER}, continuing with vanilla source"; \
150+
fi
43151

44-
# Compile PostgreSQL
45-
RUN echo "==========Compiling Modified PostgreSQL==========" && \
152+
# ==============================================================================
153+
# Compile and Install PostgreSQL
154+
# ==============================================================================
155+
156+
RUN set -eux && \
157+
echo "========================================" && \
158+
echo "Configuring PostgreSQL ${PGVER}" && \
159+
echo "========================================" && \
46160
./configure \
47161
--prefix="/home/pgedge/pgedge/pg${PGVER}" \
48162
--disable-rpath \
@@ -55,36 +169,62 @@ RUN echo "==========Compiling Modified PostgreSQL==========" && \
55169
--with-gssapi \
56170
--with-ldap \
57171
--with-pam \
58-
--enable-debug \
59-
--enable-dtrace \
60-
--with-llvm \
61172
--with-openssl \
62173
--with-systemd \
63-
--enable-tap-tests \
174+
--with-llvm \
64175
--with-python \
176+
--enable-debug \
177+
--enable-dtrace \
65178
--enable-cassert \
66-
PYTHON=/usr/bin/python3.9 \
67-
BITCODE_CFLAGS="-gdwarf-5 -O0 -fforce-dwarf-frame" \
68-
CFLAGS="-g -O0" && \
179+
--enable-tap-tests \
180+
PYTHON=/usr/bin/python3 \
181+
CFLAGS="-g -O0" \
182+
BITCODE_CFLAGS="-gdwarf-5 -O0 -fforce-dwarf-frame" && \
183+
echo "========================================" && \
184+
echo "Building PostgreSQL (${MAKE_JOBS} jobs)" && \
185+
echo "========================================" && \
69186
make -j${MAKE_JOBS} && \
70187
make -C contrib -j${MAKE_JOBS} && \
188+
echo "========================================" && \
189+
echo "Installing PostgreSQL" && \
190+
echo "========================================" && \
71191
make install && \
72-
make -C contrib install
192+
make -C contrib install && \
193+
echo "PostgreSQL installation complete"
194+
195+
# ==============================================================================
196+
# Compile and Install Spock Extension
197+
# ==============================================================================
73198

74-
# Compile Spock
75199
WORKDIR /home/pgedge/spock
76-
RUN echo "==========Compiling Spock==========" && \
200+
201+
RUN set -eux && \
202+
echo "========================================" && \
203+
echo "Building Spock Extension" && \
204+
echo "========================================" && \
77205
make clean && \
78206
make -j${MAKE_JOBS} && \
79207
make install && \
80-
echo "==========Spock build complete=========="
208+
echo "export SPOCK_SOURCE_DIR=/home/pgedge/spock" >> /home/pgedge/.bashrc && \
209+
echo "Spock installation complete"
81210

82-
#-----------------------------------------
83-
# Copy test scripts and switch to pgedge user for runtime
84-
COPY --chmod=755 tests/docker/*.sh /home/pgedge/
211+
# ==============================================================================
212+
# Install spockbench
213+
# ==============================================================================
85214

86-
WORKDIR /home/pgedge/
87-
# Switch back to pgedge user for container runtime (testing, etc.)
88-
USER pgedge
215+
RUN set -eux && \
216+
cd /home/pgedge/spockbench && \
217+
python3 setup.py install --user && \
218+
echo "Spockbench installation complete"
219+
220+
# ==============================================================================
221+
# Runtime Configuration
222+
# ==============================================================================
223+
224+
WORKDIR /home/pgedge
89225

90-
CMD ["/home/pgedge/entrypoint.sh"]
226+
# Container initialization and startup:
227+
# 1. entrypoint.sh initializes PostgreSQL cluster and creates Spock nodes
228+
# 2. After entrypoint completes, postgres runs in foreground as PID 1
229+
# This makes the container lifecycle tied to PostgreSQL - if postgres crashes, container stops
230+
CMD ["/bin/bash", "-c", "/home/pgedge/entrypoint.sh && exec postgres -D $PGDATA -k /tmp"]

tests/docker/docker-compose.yml

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ services:
44
hostname: n1
55
image: spock
66
build:
7-
context: .
8-
dockerfile: Dockerfile-step-1.el9
7+
context: ../..
8+
dockerfile: tests/docker/Dockerfile-step-1.el9
9+
args:
10+
- PGVER=${PGVER:-17}
11+
- MAKE_JOBS=${MAKE_JOBS:-4}
12+
- BASE_IMAGE=${BASE_IMAGE:-base-test-image:latest}
913
environment:
1014
- HOSTNAME=n1
1115
- PEER_NAMES=n2,n3
@@ -14,15 +18,38 @@ services:
1418
- pgedge.env
1519
ports:
1620
- '15432:5432'
21+
# Enable core dumps for crash debugging
22+
cap_add:
23+
- SYS_PTRACE # Required for debugging with gdb
24+
- SYS_ADMIN # Required to set /proc/sys/kernel/core_pattern
25+
ulimits:
26+
core:
27+
soft: -1
28+
hard: -1
29+
# Mount volume for core dumps (persists across container restarts)
1730
volumes:
18-
- '${GITHUB_WORKSPACE}:/home/pgedge/spock'
19-
- '${GITHUB_WORKSPACE}/spockbench:/home/pgedge/spockbench'
20-
- './lib-list.txt:/home/pgedge/lib-list.txt'
31+
- ./cores/n1:/cores
32+
healthcheck:
33+
test: ["CMD", "pg_isready", "-h", "/tmp", "-U", "admin"]
34+
interval: 10s
35+
timeout: 5s
36+
retries: 5
37+
start_period: 60s
2138

2239
pgedge-n2:
2340
container_name: n2
2441
hostname: n2
2542
image: spock
43+
depends_on:
44+
pgedge-n1:
45+
condition: service_healthy
46+
build:
47+
context: ../..
48+
dockerfile: tests/docker/Dockerfile-step-1.el9
49+
args:
50+
- PGVER=${PGVER:-17}
51+
- MAKE_JOBS=${MAKE_JOBS:-4}
52+
- BASE_IMAGE=${BASE_IMAGE:-base-test-image:latest}
2653
environment:
2754
- HOSTNAME=n2
2855
- PEER_NAMES=n1,n3
@@ -31,15 +58,38 @@ services:
3158
- pgedge.env
3259
ports:
3360
- '15433:5432'
61+
# Enable core dumps for crash debugging
62+
cap_add:
63+
- SYS_PTRACE # Required for debugging with gdb
64+
- SYS_ADMIN # Required to set /proc/sys/kernel/core_pattern
65+
ulimits:
66+
core:
67+
soft: -1
68+
hard: -1
69+
# Mount volume for core dumps (persists across container restarts)
3470
volumes:
35-
- '${GITHUB_WORKSPACE}:/home/pgedge/spock'
36-
- '${GITHUB_WORKSPACE}/spockbench:/home/pgedge/spockbench'
37-
- './lib-list.txt:/home/pgedge/lib-list.txt'
71+
- ./cores/n2:/cores
72+
healthcheck:
73+
test: ["CMD", "pg_isready", "-h", "/tmp", "-U", "admin"]
74+
interval: 10s
75+
timeout: 5s
76+
retries: 5
77+
start_period: 60s
3878

3979
pgedge-n3:
4080
container_name: n3
4181
hostname: n3
4282
image: spock
83+
depends_on:
84+
pgedge-n2:
85+
condition: service_healthy
86+
build:
87+
context: ../..
88+
dockerfile: tests/docker/Dockerfile-step-1.el9
89+
args:
90+
- PGVER=${PGVER:-17}
91+
- MAKE_JOBS=${MAKE_JOBS:-4}
92+
- BASE_IMAGE=${BASE_IMAGE:-base-test-image:latest}
4393
environment:
4494
- HOSTNAME=n3
4595
- PEER_NAMES=n1,n2
@@ -48,7 +98,20 @@ services:
4898
- pgedge.env
4999
ports:
50100
- '15434:5432'
101+
# Enable core dumps for crash debugging
102+
cap_add:
103+
- SYS_PTRACE # Required for debugging with gdb
104+
- SYS_ADMIN # Required to set /proc/sys/kernel/core_pattern
105+
ulimits:
106+
core:
107+
soft: -1
108+
hard: -1
109+
# Mount volume for core dumps (persists across container restarts)
51110
volumes:
52-
- '${GITHUB_WORKSPACE}:/home/pgedge/spock'
53-
- '${GITHUB_WORKSPACE}/spockbench:/home/pgedge/spockbench'
54-
- './lib-list.txt:/home/pgedge/lib-list.txt'
111+
- ./cores/n3:/cores
112+
healthcheck:
113+
test: ["CMD", "pg_isready", "-h", "/tmp", "-U", "admin"]
114+
interval: 10s
115+
timeout: 5s
116+
retries: 5
117+
start_period: 60s

0 commit comments

Comments
 (0)