Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions .github/workflows/build-test-push-synvya.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,23 @@ jobs:
exit 1
fi
git pull --ff-only origin synvya-staging
bash scripts/ec2-prepare-host.sh
bash scripts/load-secrets.sh staging
if [ -n "${{ vars.DISABLE_EMAILS }}" ]; then
echo "DISABLE_EMAILS=${{ vars.DISABLE_EMAILS }}" >> /opt/synvya/.env
fi
docker system df || true
docker builder prune -af || true
docker image prune -af || true
# Light cleanup: drop dangling images and unreferenced build
# cache only. `-a` would wipe referenced layers and force a
# cold cargo build of all dependencies on every deploy.
docker image prune -f || true
docker builder prune -f || true
# Force BuildKit so the Dockerfile's --mount=type=cache works.
# Compose v2 enables it by default, but be explicit.
export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
docker compose -f docker-compose.synvya.yml --env-file /opt/synvya/.env \
build postgres redis migrate keycast
build --build-arg CARGO_BUILD_JOBS=2 postgres redis migrate keycast
docker compose -f docker-compose.synvya.yml --env-file /opt/synvya/.env \
up -d postgres redis migrate keycast
sleep 10
Expand Down Expand Up @@ -182,15 +190,23 @@ jobs:
exit 1
fi
git pull --ff-only origin synvya
bash scripts/ec2-prepare-host.sh
bash scripts/load-secrets.sh production
if [ -n "${{ vars.DISABLE_EMAILS }}" ]; then
echo "DISABLE_EMAILS=${{ vars.DISABLE_EMAILS }}" >> /opt/synvya/.env
fi
docker system df || true
docker builder prune -af || true
docker image prune -af || true
# Light cleanup: drop dangling images and unreferenced build
# cache only. `-a` would wipe referenced layers and force a
# cold cargo build of all dependencies on every deploy.
docker image prune -f || true
docker builder prune -f || true
# Force BuildKit so the Dockerfile's --mount=type=cache works.
# Compose v2 enables it by default, but be explicit.
export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
docker compose -f docker-compose.synvya.yml --env-file /opt/synvya/.env \
build postgres redis migrate keycast
build --build-arg CARGO_BUILD_JOBS=2 postgres redis migrate keycast
docker compose -f docker-compose.synvya.yml --env-file /opt/synvya/.env \
up -d postgres redis migrate keycast
sleep 10
Expand Down Expand Up @@ -223,6 +239,9 @@ jobs:
fi
source "$HOME/.cargo/env"

# Ensure swap + cargo jobs limit are in place for the QA build
bash /opt/synvya/keycast/scripts/ec2-prepare-host.sh

# Load env for POSTGRES_PASSWORD
set -a
source /opt/synvya/.env 2>/dev/null || true
Expand Down Expand Up @@ -301,6 +320,9 @@ jobs:
fi
source "$HOME/.cargo/env"

# Ensure swap + cargo jobs limit are in place for the QA build
bash /opt/synvya/keycast/scripts/ec2-prepare-host.sh

# Load env for POSTGRES_PASSWORD
set -a
source /opt/synvya/.env 2>/dev/null || true
Expand Down
30 changes: 24 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# syntax=docker/dockerfile:1.4
# Build stage for Rust API
FROM rust:1.93-slim AS rust-builder

Expand All @@ -18,12 +19,27 @@ COPY ./Cargo.toml ./Cargo.toml
COPY ./Cargo.lock ./Cargo.lock

ARG CARGO_FEATURES=""
RUN if [ -n "$CARGO_FEATURES" ]; then \
ARG CARGO_BUILD_JOBS=""
ENV CARGO_BUILD_JOBS=${CARGO_BUILD_JOBS}

# BuildKit cache mounts persist the cargo registry/git index and the
# target/ directory across builds on the same host. Unchanged crates
# stay compiled, so warm builds skip the ~400-crate dependency build.
# Artifacts must be copied out of target/ before the RUN ends because
# cache mounts are not part of the resulting image layer.
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
--mount=type=cache,target=/usr/local/cargo/git,sharing=locked \
--mount=type=cache,target=/app/target,sharing=locked \
set -e; \
if [ -n "$CARGO_FEATURES" ]; then \
cargo build --release --bin keycast --features "$CARGO_FEATURES"; \
else \
cargo build --release --bin keycast; \
fi
RUN cargo build --release --example migrate-vine-users
fi; \
cargo build --release --example migrate-vine-users; \
mkdir -p /artifacts; \
cp target/release/keycast /artifacts/keycast; \
cp target/release/examples/migrate-vine-users /artifacts/migrate-vine-users

# Build stage for Bun frontend
FROM oven/bun:1 AS web-builder
Expand Down Expand Up @@ -109,9 +125,11 @@ RUN curl -fsSL https://bun.sh/install | bash
# Create necessary directories
RUN mkdir -p /app/database /data

# Copy built artifacts - keycast binary and migration tool
COPY --from=rust-builder /app/target/release/keycast ./
COPY --from=rust-builder /app/target/release/examples/migrate-vine-users ./
# Copy built artifacts - keycast binary and migration tool.
# Sources are /artifacts/ (not target/) because target/ is a BuildKit
# cache mount in rust-builder and is not present in its image layer.
COPY --from=rust-builder /artifacts/keycast ./
COPY --from=rust-builder /artifacts/migrate-vine-users ./
COPY --from=web-builder /app/web/build ./web
COPY --from=web-builder /app/web/package.json ./
COPY --from=web-builder /app/web/node_modules ./node_modules
Expand Down
43 changes: 43 additions & 0 deletions scripts/ec2-prepare-host.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Idempotent host prep for low-memory EC2 instances (e.g. t3.medium).
# Ensures enough swap to survive Rust release builds and constrains host-side
# cargo to a safe job count. Safe to run on every deploy.
set -euo pipefail

SWAPFILE="${SWAPFILE:-/swapfile}"
SWAP_SIZE="${SWAP_SIZE:-4G}"
CARGO_JOBS="${CARGO_JOBS:-2}"

echo "=== ec2-prepare-host: ensure swap (${SWAP_SIZE} at ${SWAPFILE}) ==="
if swapon --show=NAME --noheadings | grep -qx "${SWAPFILE}"; then
echo "swap already active at ${SWAPFILE}"
else
if [ ! -f "${SWAPFILE}" ]; then
sudo fallocate -l "${SWAP_SIZE}" "${SWAPFILE}" || \
sudo dd if=/dev/zero of="${SWAPFILE}" bs=1M count=$((${SWAP_SIZE%G} * 1024))
sudo chmod 600 "${SWAPFILE}"
sudo mkswap "${SWAPFILE}"
fi
sudo swapon "${SWAPFILE}"
if ! grep -qE "^${SWAPFILE}\s" /etc/fstab; then
echo "${SWAPFILE} none swap sw 0 0" | sudo tee -a /etc/fstab >/dev/null
fi
echo "swap enabled at ${SWAPFILE}"
fi

echo "=== ec2-prepare-host: ensure ~/.cargo/config.toml jobs=${CARGO_JOBS} ==="
mkdir -p "${HOME}/.cargo"
CARGO_CFG="${HOME}/.cargo/config.toml"
if [ ! -f "${CARGO_CFG}" ] || ! grep -qE '^\[build\]' "${CARGO_CFG}"; then
cat >> "${CARGO_CFG}" <<EOF

[build]
jobs = ${CARGO_JOBS}
EOF
echo "wrote [build] jobs=${CARGO_JOBS} to ${CARGO_CFG}"
else
echo "${CARGO_CFG} already has [build] section, leaving as-is"
fi

echo "=== ec2-prepare-host: memory snapshot ==="
free -h
Loading