diff --git a/.woodpecker.yml b/.woodpecker.yml index ae9aece..52afb0f 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -26,6 +26,6 @@ steps: from_secret: kubeconfig commands: - mkdir -p /root/.kube && echo "$KUBECONFIG_DATA" | base64 -d > /root/.kube/config - - kubectl set image deployment/stemedb-api stemedb-api=registry.threesix.ai/stemedb-api:${CI_COMMIT_SHA:0:8} -n stemedb - - kubectl rollout status deployment/stemedb-api -n stemedb --timeout=300s + - kubectl set image statefulset/stemedb stemedb=registry.threesix.ai/stemedb-api:${CI_COMMIT_SHA:0:8} -n stemedb + - kubectl rollout status statefulset/stemedb -n stemedb --timeout=300s depends_on: [build] diff --git a/Dockerfile b/Dockerfile index 6de5923..ea8208b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,9 +42,9 @@ RUN cargo chef cook --release --recipe-path recipe.json # Inherits compiled deps from cacher; only workspace source is compiled here. FROM cacher AS builder COPY . . -RUN cargo build --release -p stemedb-api +RUN cargo build --release -p stemedb-api -p stemedb-cluster # Strip debug symbols before copying to runtime image -RUN strip target/release/stemedb-api +RUN strip target/release/stemedb-api target/release/stemedb-node # Stage 4: Runtime — minimal production image FROM debian:bookworm-slim AS runtime @@ -59,19 +59,22 @@ RUN apt-get update && \ RUN useradd --system --no-create-home --shell /bin/false stemedb COPY --from=builder /app/target/release/stemedb-api /usr/local/bin/stemedb-api +COPY --from=builder /app/target/release/stemedb-node /usr/local/bin/stemedb-node +COPY scripts/entrypoint.sh /usr/local/bin/entrypoint.sh -RUN mkdir -p /data/wal /data/db && chown -R stemedb:stemedb /data +RUN chmod +x /usr/local/bin/entrypoint.sh && \ + mkdir -p /data/wal /data/db && chown -R stemedb:stemedb /data USER stemedb ENV STEMEDB_WAL_DIR=/data/wal \ STEMEDB_DB_DIR=/data/db \ STEMEDB_BIND_ADDR=0.0.0.0:18180 \ - RUST_LOG=stemedb_api=info + RUST_LOG=stemedb_api=info,stemedb_cluster=info -EXPOSE 18180 +EXPOSE 18180 18181 18182 18183 -HEALTHCHECK --interval=5s --timeout=3s --start-period=10s --retries=3 \ +HEALTHCHECK --interval=5s --timeout=3s --start-period=15s --retries=3 \ CMD curl -f http://localhost:18180/v1/health || exit 1 -CMD ["stemedb-api"] +ENTRYPOINT ["entrypoint.sh"] diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh new file mode 100644 index 0000000..a02d74e --- /dev/null +++ b/scripts/entrypoint.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# StemeDB cluster entrypoint — runs both stemedb-api (storage) and stemedb-node (gateway/SWIM). +# +# In single-node mode (STEMEDB_CLUSTER_MODE unset or "false"), only stemedb-api runs. +# In cluster mode (STEMEDB_CLUSTER_MODE=true), both binaries run side-by-side. + +set -e + +CLUSTER_MODE="${STEMEDB_CLUSTER_MODE:-false}" + +if [ "$CLUSTER_MODE" = "true" ] || [ "$CLUSTER_MODE" = "1" ]; then + echo "Starting StemeDB in cluster mode" + + # Start stemedb-api in background (storage engine on :18180) + stemedb-api & + API_PID=$! + + # Wait briefly for API to bind before starting the gateway + sleep 1 + + # Start stemedb-node in foreground (gateway :18181, gRPC :18182, SWIM :18183) + stemedb-node & + NODE_PID=$! + + # Trap signals to shut down both processes + trap 'kill $API_PID $NODE_PID 2>/dev/null; wait' TERM INT + + # Wait for either process to exit — if one dies, kill both + wait -n $API_PID $NODE_PID 2>/dev/null || true + EXIT_CODE=$? + kill $API_PID $NODE_PID 2>/dev/null || true + wait + exit $EXIT_CODE +else + echo "Starting StemeDB in single-node mode" + exec stemedb-api "$@" +fi