Skip to content

Commit cfe39c0

Browse files
committed
build(supabase): build a custom supabase/postgres:17.6.1.071 docker image to be used from the supabase start stack
1 parent bb92d2c commit cfe39c0

File tree

4 files changed

+215
-73
lines changed

4 files changed

+215
-73
lines changed

docker/Makefile.postgresql

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ PG_EXTENSION_CONTROL = docker/postgresql/$(EXTENSION).control
5555
.PHONY: postgres-check postgres-build postgres-install postgres-clean postgres-test \
5656
postgres-docker-build postgres-docker-build-asan postgres-docker-run postgres-docker-run-asan postgres-docker-stop postgres-docker-rebuild \
5757
postgres-docker-debug-build postgres-docker-debug-run postgres-docker-debug-rebuild \
58-
postgres-docker-shell postgres-dev-rebuild postgres-help unittest-pg
58+
postgres-docker-shell postgres-dev-rebuild postgres-help unittest-pg \
59+
postgres-supabase-build postgres-supabase-rebuild postgres-supabase-run-smoke-test \
60+
postgres-docker-run-smoke-test
5961

6062
# Check if PostgreSQL is available
6163
postgres-check:
@@ -119,6 +121,18 @@ postgres-test: postgres-install
119121
DOCKER_IMAGE = sqliteai/sqlite-sync-pg
120122
DOCKER_TAG ?= latest
121123
DOCKER_BUILD_ARGS ?=
124+
SUPABASE_CLI_IMAGE ?= $(shell docker ps --format '{{.Image}} {{.Names}}' | awk '/supabase_db/ {print $$1; exit}')
125+
SUPABASE_CLI_DOCKERFILE ?= docker/postgresql/Dockerfile.supabase
126+
SUPABASE_WORKDIR ?=
127+
SUPABASE_WORKDIR_ARG = $(if $(SUPABASE_WORKDIR),--workdir $(SUPABASE_WORKDIR),)
128+
SUPABASE_DB_HOST ?= 127.0.0.1
129+
SUPABASE_DB_PORT ?= 54322
130+
SUPABASE_DB_PASSWORD ?= postgres
131+
PG_DOCKER_DB_HOST ?= localhost
132+
PG_DOCKER_DB_PORT ?= 5432
133+
PG_DOCKER_DB_NAME ?= cloudsync_test
134+
PG_DOCKER_DB_USER ?= postgres
135+
PG_DOCKER_DB_PASSWORD ?= postgres
122136

123137
# Build Docker image with pre-installed extension
124138
postgres-docker-build:
@@ -220,6 +234,58 @@ postgres-docker-shell:
220234
@echo "Opening shell in PostgreSQL container..."
221235
docker exec -it cloudsync-postgres bash
222236

237+
# Build CloudSync into the Supabase CLI postgres image tag
238+
postgres-supabase-build:
239+
@echo "Building CloudSync image for Supabase CLI..."
240+
@if [ -z "$(SUPABASE_CLI_IMAGE)" ]; then \
241+
echo "Error: Supabase CLI postgres image not found."; \
242+
echo "Run 'supabase start' first, or set SUPABASE_CLI_IMAGE=public.ecr.aws/supabase/postgres:<tag>."; \
243+
exit 1; \
244+
fi
245+
@tmp_dockerfile="$$(mktemp /tmp/cloudsync-supabase-cli.XXXXXX)"; \
246+
src_dockerfile="$(SUPABASE_CLI_DOCKERFILE)"; \
247+
if [ ! -f "$$src_dockerfile" ]; then \
248+
if [ -f "docker/postgresql/Dockerfile.supabase" ]; then \
249+
src_dockerfile="docker/postgresql/Dockerfile.supabase"; \
250+
else \
251+
echo "Error: Supabase Dockerfile not found (expected $$src_dockerfile)."; \
252+
rm -f "$$tmp_dockerfile"; \
253+
exit 1; \
254+
fi; \
255+
fi; \
256+
sed -e "s|^FROM supabase/postgres:[^ ]*|FROM $(SUPABASE_CLI_IMAGE)|" \
257+
-e "s|^FROM public.ecr.aws/supabase/postgres:[^ ]*|FROM $(SUPABASE_CLI_IMAGE)|" \
258+
"$$src_dockerfile" > "$$tmp_dockerfile"; \
259+
if [ ! -s "$$tmp_dockerfile" ]; then \
260+
echo "Error: Generated Dockerfile is empty."; \
261+
rm -f "$$tmp_dockerfile"; \
262+
exit 1; \
263+
fi; \
264+
echo "Using base image: $(SUPABASE_CLI_IMAGE)"; \
265+
docker build -f "$$tmp_dockerfile" -t "$(SUPABASE_CLI_IMAGE)" .; \
266+
rm -f "$$tmp_dockerfile"; \
267+
echo "Build complete: $(SUPABASE_CLI_IMAGE)"
268+
269+
# Rebuild CloudSync image and restart Supabase CLI stack
270+
postgres-supabase-rebuild: postgres-supabase-build
271+
@echo "Restarting Supabase CLI stack..."
272+
@command -v supabase >/dev/null 2>&1 || (echo "Error: supabase CLI not found in PATH." && exit 1)
273+
@supabase stop $(SUPABASE_WORKDIR_ARG)
274+
@supabase start $(SUPABASE_WORKDIR_ARG)
275+
@echo "Supabase CLI stack restarted."
276+
277+
# Run smoke test against Supabase CLI local database
278+
postgres-supabase-run-smoke-test:
279+
@echo "Running Supabase CLI smoke test..."
280+
@PGPASSWORD="$(SUPABASE_DB_PASSWORD)" psql postgresql://supabase_admin@$(SUPABASE_DB_HOST):$(SUPABASE_DB_PORT)/postgres -f docker/postgresql/smoke_test.sql
281+
@echo "Smoke test completed."
282+
283+
# Run smoke test against Docker standalone database
284+
postgres-docker-run-smoke-test:
285+
@echo "Running Docker smoke test..."
286+
@PGPASSWORD="$(PG_DOCKER_DB_PASSWORD)" psql postgresql://$(PG_DOCKER_DB_USER)@$(PG_DOCKER_DB_HOST):$(PG_DOCKER_DB_PORT)/$(PG_DOCKER_DB_NAME) -f docker/postgresql/smoke_test.sql
287+
@echo "Smoke test completed."
288+
223289
# ============================================================================
224290
# Development Workflow Targets
225291
# ============================================================================
@@ -259,6 +325,10 @@ postgres-help:
259325
@echo " postgres-docker-stop - Stop PostgreSQL container"
260326
@echo " postgres-docker-rebuild - Rebuild image and restart container"
261327
@echo " postgres-docker-shell - Open bash shell in running container"
328+
@echo " postgres-supabase-build - Build CloudSync into Supabase CLI postgres image"
329+
@echo " postgres-supabase-rebuild - Build CloudSync image and restart Supabase CLI stack"
330+
@echo " postgres-supabase-run-smoke-test - Run smoke test against Supabase CLI database"
331+
@echo " postgres-docker-run-smoke-test - Run smoke test against Docker database"
262332
@echo ""
263333
@echo "Development:"
264334
@echo " postgres-dev-rebuild - Rebuild extension in running container (fast)"

docker/README.md

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ docker/
1111
│ ├── docker-compose.yml
1212
│ ├── init.sql # CloudSync metadata tables
1313
│ └── cloudsync.control
14-
└── supabase/ # Supabase integration
15-
└── docker-compose.yml
1614
```
1715

1816
## Option 1: Standalone PostgreSQL
@@ -105,78 +103,100 @@ Run and Debug -> `Attach to Postgres (gdb)` -> pick the PID from step 4 -> Conti
105103
6) Trigger your breakpoint
106104
Run the SQL that exercises the code path. If `psql` blocks, the backend is paused at a breakpoint; continue in the debugger.
107105

108-
## Option 2: Supabase Integration
106+
## Option 2: Supabase Integration (cli)
109107

110-
Use this for testing CloudSync with Supabase's full stack (auth, realtime, storage, etc.).
108+
Use this when you're running `supabase start` and want CloudSync inside the local stack.
109+
The Supabase CLI uses a bundled PostgreSQL image (for example,
110+
`public.ecr.aws/supabase/postgres:17.6.1.071`). Build a matching image that
111+
includes CloudSync, then tag it with the same name so the CLI reuses it. This
112+
keeps your local Supabase stack intact (auth, realtime, storage, etc.) while
113+
enabling the extension in the CLI-managed Postgres container.
111114

112115
### Prerequisites
113116

114-
Ensure you have both repositories cloned side-by-side:
115-
116-
```bash
117-
parent-directory/
118-
├── supabase/
119-
└── sqlite-sync/
120-
```
117+
- Supabase CLI installed (`supabase start` works)
118+
- Docker running
121119

122120
### Setup
123121

124-
1. Clone the Supabase repository:
122+
1. Initialize a Supabase project (use a separate workdir to keep generated files
123+
out of the repo):
125124
```bash
126-
git clone --depth 1 https://github.com/supabase/supabase
127-
cd supabase/docker
125+
mkdir -p ~/supabase-local
126+
supabase init --workdir ~/supabase-local
128127
```
129128

130-
2. Copy CloudSync override configuration:
129+
2. Start Supabase once so the CLI pulls the Postgres image:
131130
```bash
132-
cp ../../sqlite-sync/docker/supabase/docker-compose.yml docker-compose.override.yml
131+
supabase start --workdir ~/supabase-local
133132
```
134133

135-
3. Copy the `.env` file and configure it:
134+
3. Build and tag a CloudSync image using the same tag as the running CLI stack:
136135
```bash
137-
cp .env.example .env
138-
# Edit .env with your preferred settings
136+
make postgres-supabase-build
137+
```
138+
This auto-detects the running `supabase_db` image tag and rebuilds it with
139+
CloudSync installed. If you need to override the tag, set
140+
`SUPABASE_CLI_IMAGE=public.ecr.aws/supabase/postgres:<tag>`.
141+
Example:
142+
```bash
143+
SUPABASE_CLI_IMAGE=public.ecr.aws/supabase/postgres:17.6.1.071 make postgres-supabase-build
139144
```
140145

141-
### Starting Supabase with CloudSync
146+
4. Restart the stack:
147+
```bash
148+
supabase stop --workdir ~/supabase-local
149+
supabase start --workdir ~/supabase-local
150+
```
151+
152+
### Using the CloudSync Extension
142153

143-
The override file will automatically build the custom PostgreSQL image:
154+
You can load the extension automatically from a migration, or enable it
155+
manually.
144156

157+
Migration-based (notes for CLI): Supabase CLI migrations run as the `postgres`
158+
role, which cannot create C extensions by default. Use manual enable or grant
159+
`USAGE` on language `c` once, then migrations will work.
160+
161+
If you still want a migration file, add:
145162
```bash
146-
cd supabase/docker
147-
docker-compose up -d
163+
~/supabase-local/supabase/migrations/00000000000000_cloudsync.sql
164+
```
165+
Contents:
166+
```sql
167+
CREATE EXTENSION IF NOT EXISTS cloudsync;
148168
```
149169

150-
This will:
151-
- Build the CloudSync-enabled PostgreSQL image (first time only)
152-
- Start all Supabase services with CloudSync support
153-
- Initialize CloudSync metadata tables alongside Supabase tables
154-
155-
Access Supabase Studio at http://localhost:3000
170+
Then either:
171+
- run `GRANT USAGE ON LANGUAGE c TO postgres;` once as `supabase_admin`, or
172+
- skip the migration and enable the extension manually after `supabase db reset`.
156173

157-
### Using the CloudSync Extension
174+
Manual enable (no reset required):
158175

159-
Connect to the database and enable the extension:
176+
Connect as the Supabase superuser (C extensions require superuser or language
177+
privileges), then enable the extension:
160178

161179
```bash
162-
psql postgresql://postgres:postgres@localhost:5432/postgres
180+
psql postgresql://supabase_admin:postgres@127.0.0.1:54322/postgres
163181
```
164182

165183
```sql
166184
CREATE EXTENSION cloudsync;
167-
168-
-- Verify installation
169185
SELECT cloudsync_version();
170186
```
171187

188+
If you want to use the `postgres` role instead:
189+
190+
```sql
191+
GRANT USAGE ON LANGUAGE c TO postgres;
192+
```
193+
172194
### Rebuilding After Changes
173195

174-
If you modify the CloudSync source code, rebuild the image:
196+
If you modify the CloudSync source code, rebuild the CLI image and restart:
175197

176198
```bash
177-
cd supabase/docker
178-
docker-compose build db
179-
docker-compose up -d
199+
make postgres-supabase-rebuild SUPABASE_WORKDIR=~/supabase-local
180200
```
181201

182202
## Development Workflow
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Build stage for CloudSync extension (match Supabase runtime)
2+
FROM public.ecr.aws/supabase/postgres:17.6.1.071 AS cloudsync-builder
3+
4+
# Install build dependencies
5+
RUN apt-get update && apt-get install -y \
6+
build-essential \
7+
ca-certificates \
8+
git \
9+
make \
10+
&& rm -rf /var/lib/apt/lists/*
11+
12+
# Create directory for extension source
13+
WORKDIR /tmp/cloudsync
14+
15+
# Copy entire source tree (needed for includes and makefiles)
16+
COPY src/ ./src/
17+
COPY docker/ ./docker/
18+
COPY Makefile .
19+
20+
# Build the CloudSync extension using Supabase's pg_config
21+
ENV CLOUDSYNC_PG_CONFIG=/root/.nix-profile/bin/pg_config
22+
RUN if [ ! -x "$CLOUDSYNC_PG_CONFIG" ]; then \
23+
echo "Error: pg_config not found at $CLOUDSYNC_PG_CONFIG."; \
24+
exit 1; \
25+
fi; \
26+
make postgres-build PG_CONFIG="$CLOUDSYNC_PG_CONFIG"
27+
28+
# Collect build artifacts (avoid installing into the Nix store)
29+
RUN mkdir -p /tmp/cloudsync-artifacts/lib /tmp/cloudsync-artifacts/extension && \
30+
cp /tmp/cloudsync/cloudsync.so /tmp/cloudsync-artifacts/lib/ && \
31+
cp /tmp/cloudsync/src/postgresql/cloudsync--1.0.sql /tmp/cloudsync-artifacts/extension/ && \
32+
cp /tmp/cloudsync/docker/postgresql/cloudsync.control /tmp/cloudsync-artifacts/extension/
33+
34+
# Runtime image based on Supabase Postgres
35+
FROM public.ecr.aws/supabase/postgres:17.6.1.071
36+
37+
# Match builder pg_config path
38+
ENV CLOUDSYNC_PG_CONFIG=/root/.nix-profile/bin/pg_config
39+
40+
# Install CloudSync extension artifacts
41+
COPY --from=cloudsync-builder /tmp/cloudsync-artifacts/ /tmp/cloudsync-artifacts/
42+
RUN if [ ! -x "$CLOUDSYNC_PG_CONFIG" ]; then \
43+
echo "Error: pg_config not found at $CLOUDSYNC_PG_CONFIG."; \
44+
exit 1; \
45+
fi; \
46+
PKGLIBDIR="`$CLOUDSYNC_PG_CONFIG --pkglibdir`"; \
47+
# Supabase wraps postgres and overrides libdir via NIX_PGLIBDIR.
48+
NIX_PGLIBDIR="`grep -E \"^export NIX_PGLIBDIR\" /usr/bin/postgres | sed -E \"s/.*'([^']+)'.*/\\1/\"`"; \
49+
if [ -n "$NIX_PGLIBDIR" ]; then PKGLIBDIR="$NIX_PGLIBDIR"; fi; \
50+
SHAREDIR_PGCONFIG="`$CLOUDSYNC_PG_CONFIG --sharedir`"; \
51+
SHAREDIR_STD="/usr/share/postgresql"; \
52+
install -d "$PKGLIBDIR" "$SHAREDIR_PGCONFIG/extension" && \
53+
install -m 755 /tmp/cloudsync-artifacts/lib/cloudsync.so "$PKGLIBDIR/" && \
54+
install -m 644 /tmp/cloudsync-artifacts/extension/cloudsync* "$SHAREDIR_PGCONFIG/extension/"; \
55+
if [ "$SHAREDIR_STD" != "$SHAREDIR_PGCONFIG" ]; then \
56+
install -d "$SHAREDIR_STD/extension" && \
57+
install -m 644 /tmp/cloudsync-artifacts/extension/cloudsync* "$SHAREDIR_STD/extension/"; \
58+
fi
59+
60+
# Verify installation
61+
RUN if [ ! -x "$CLOUDSYNC_PG_CONFIG" ]; then \
62+
echo "Error: pg_config not found at $CLOUDSYNC_PG_CONFIG."; \
63+
exit 1; \
64+
fi; \
65+
NIX_PGLIBDIR="`grep -E \"^export NIX_PGLIBDIR\" /usr/bin/postgres | sed -E \"s/.*'([^']+)'.*/\\1/\"`"; \
66+
echo "Verifying CloudSync extension installation..." && \
67+
if [ -n "$NIX_PGLIBDIR" ]; then \
68+
ls -la "$NIX_PGLIBDIR/cloudsync.so"; \
69+
else \
70+
ls -la "`$CLOUDSYNC_PG_CONFIG --pkglibdir`/cloudsync.so"; \
71+
fi && \
72+
ls -la "`$CLOUDSYNC_PG_CONFIG --sharedir`/extension/cloudsync"* && \
73+
if [ -d "/usr/share/postgresql/extension" ]; then \
74+
ls -la /usr/share/postgresql/extension/cloudsync*; \
75+
fi && \
76+
echo "CloudSync extension installed successfully"
77+
78+
# Expose PostgreSQL port
79+
EXPOSE 5432
80+
81+
# Return to root directory
82+
WORKDIR /
83+
84+
# Add label with extension version
85+
LABEL org.sqliteai.cloudsync.version="1.0" \
86+
org.sqliteai.cloudsync.description="PostgreSQL with CloudSync CRDT extension"

docker/supabase/docker-compose.yml

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)