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
9 changes: 5 additions & 4 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,10 @@ alias fresh="deno run -A -r jsr:@fresh/init"
alias dev="bash /workspaces/zig-directory/.devcontainer/run.sh dev"
alias prod="bash /workspaces/zig-directory/.devcontainer/run.sh prod"

# Docker shortcuts
alias db="docker build -t dmozdb ."
alias dr="docker run --rm -p 8080:8080 dmozdb"
# Docker shortcuts (split images: backend = Zig, web = Deno/Fresh)
alias db="docker build -f Dockerfile.backend -t dmozdb-backend ."
alias dbw="docker build -f Dockerfile.web -t dmozdb-web ."
alias dr="docker run --rm -p 8080:8080 dmozdb-backend"

# Load testing
alias loadtest="wrk -t4 -c100 -d30s http://localhost:8080/"
Expand All @@ -112,4 +113,4 @@ ALIASES
echo ""
echo "=== Setup complete ==="
echo "Run 'zig build' to compile, 'zig build test' to test, 'zig build run' to run."
echo "Run 'db' to docker build, 'dr' to docker run, 'loadtest' for wrk load test."
echo "Run 'db'/'dbw' to docker build backend/web, 'dr' to docker run backend, 'loadtest' for wrk load test."
41 changes: 33 additions & 8 deletions .github/workflows/cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ on:
branches:
- main
- master
# PRs build + push the images (so a controlled manual cutover can use them)
# but do NOT deploy — the cd job is gated to push events below.
pull_request:
branches:
- main

permissions:
contents: write
Expand All @@ -22,7 +27,7 @@ jobs:
# backend and runs a Vite build, both of which crawl under QEMU emulation.
# The OKE nodes are Ampere A1 (arm64), so this also matches the target arch.
runs-on: ubuntu-24.04-arm
name: Build & Push Docker Image
name: Build & Push Docker Images
outputs:
REPO_PATH: ${{ steps.get-ocir-repository.outputs.repo_path }}
steps:
Expand All @@ -45,20 +50,38 @@ jobs:
with:
auth_token: ${{ secrets.OCI_AUTH_TOKEN }}

# One combined image: the Zig backend and the Deno/Fresh frontend. The
# OKE nodes are Ampere A1 (arm64), so the build targets linux/arm64.
- name: Build and push
# Two images sharing one OCIR repo, distinguished by tag suffix: the Zig
# backend and the Deno/Fresh frontend now run as separate OKE workloads.
# Both target linux/arm64 (the OKE Ampere A1 nodes); separate gha cache
# scopes keep the two builds from evicting each other.
- name: Build and push backend
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile.backend
platforms: linux/arm64
push: true
tags: "${{ steps.get-ocir-repository.outputs.repo_path }}:${{ github.event.pull_request.head.sha || github.sha }}-backend"
cache-from: type=gha,scope=backend
cache-to: type=gha,mode=max,scope=backend

- name: Build and push web
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile.web
platforms: linux/arm64
push: true
tags: "${{ steps.get-ocir-repository.outputs.repo_path }}:${{ github.sha }}"
cache-from: type=gha
cache-to: type=gha,mode=max
tags: "${{ steps.get-ocir-repository.outputs.repo_path }}:${{ github.event.pull_request.head.sha || github.sha }}-web"
cache-from: type=gha,scope=web
cache-to: type=gha,mode=max,scope=web

cd:
needs: ci
# Deploy only on a real push to main/master — never on a PR build. The first
# split cutover is done manually (the StatefulSet needs a one-time
# --cascade=orphan recreate); after that, push-to-main applies normally.
if: github.event_name == 'push'
runs-on: ubuntu-24.04
name: Deploy
steps:
Expand Down Expand Up @@ -94,7 +117,9 @@ jobs:
run: |
cd deployment/overlays/main

kustomize edit set image dmozdb=$REPO_PATH:$SHA
kustomize edit set image \
dmozdb-backend=$REPO_PATH:$SHA-backend \
dmozdb-web=$REPO_PATH:$SHA-web

# Record the resolved tag back to the branch — best-effort only. A
# re-run of an already-deployed SHA produces no diff (empty commit
Expand Down
86 changes: 0 additions & 86 deletions Dockerfile

This file was deleted.

55 changes: 55 additions & 0 deletions Dockerfile.backend
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ============================================================
# dmozdb backend — Zig binary only (no Deno)
# ============================================================
# Split out of the former combined image so the backend runs as its
# own OKE workload. It listens on the pod network (DMOZDB_BIND set by
# the manifest) and trusts the cluster's pod + node CIDRs via
# DMOZDB_TRUSTED; the Deno frontend reaches it over a ClusterIP service.
#
# Build: docker build -f Dockerfile.backend --platform linux/arm64 -t dmozdb-backend .
# ============================================================

# ── Stage 1: build the dmozdb backend ──────────────────────
FROM ubuntu:24.04 AS zig-builder

RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends \
curl xz-utils ca-certificates && \
rm -rf /var/lib/apt/lists/*

ARG ZIG_VERSION=0.15.2
RUN ZIG_ARCH="$(uname -m)" && \
curl -sL "https://ziglang.org/download/${ZIG_VERSION}/zig-${ZIG_ARCH}-linux-${ZIG_VERSION}.tar.xz" \
| tar -xJ -C /usr/local && \
ln -s /usr/local/zig-${ZIG_ARCH}-linux-${ZIG_VERSION}/zig /usr/local/bin/zig

WORKDIR /build
COPY build.zig ./
COPY src/ src/
# -Dcpu=baseline: the CI builder and the OKE Ampere A1 nodes are different arm64
# microarchitectures. A default (native-CPU) build emits instructions the build
# host supports but Ampere may not, crashing the pod with SIGILL. Baseline armv8-a
# runs on every arm64 target.
RUN zig build -Doptimize=ReleaseSafe -Dcpu=baseline

# ── Stage 2: runtime ───────────────────────────────────────
FROM ubuntu:24.04

RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends \
tini ca-certificates && \
rm -rf /var/lib/apt/lists/*

COPY --from=zig-builder /build/zig-out/bin/dmozdb /usr/local/bin/dmozdb
COPY entrypoint.backend.sh /usr/local/bin/entrypoint.backend.sh
RUN chmod +x /usr/local/bin/entrypoint.backend.sh

ENV DMOZDB_BIND=0.0.0.0
ENV DMOZDB_PORT=8080
ENV DMOZDB_DATA_DIR=/var/lib/dmozdb
ENV DMOZDB_CACHE_SIZE_MB=256

EXPOSE 8080
VOLUME ["/var/lib/dmozdb"]

# tini as PID 1 reaps zombies and forwards SIGTERM to dmozdb (via the
# exec in the entrypoint), which drains its WAL / snapshots before exit.
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint.backend.sh"]
44 changes: 44 additions & 0 deletions Dockerfile.web
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# ============================================================
# dmozdb web frontend — Deno/Fresh SSR only (no Zig backend)
# ============================================================
# Split out of the former combined image so the frontend runs as its own
# horizontally-scaled OKE Deployment. It reaches the backend over a
# ClusterIP service (DMOZDB_HOST/DMOZDB_PORT) and stores users/sessions in
# the shared denokv service (KV_PATH + DENO_KV_ACCESS_TOKEN) — both injected
# by the Deployment manifest, not baked here.
#
# Build: docker build -f Dockerfile.web --platform linux/arm64 -t dmozdb-web .
# ============================================================

# ── Stage 1: build the Deno/Fresh web frontend ─────────────
FROM denoland/deno:2.8.1 AS web-builder

WORKDIR /web

# Resolve dependencies first so the layer caches across source edits.
# nodeModulesDir is "manual", so deno install populates node_modules from
# the lockfile; vite (run by `deno task build`) needs it present.
COPY web/deno.json web/deno.lock ./
RUN deno install

COPY web/ ./
RUN deno task build

# ── Stage 2: runtime ───────────────────────────────────────
FROM denoland/deno:2.8.1

WORKDIR /web

# The built Fresh SSR bundle (_fresh/server.js) is self-contained — vite inlines
# its deps, so node_modules is NOT shipped at runtime. Ship the bundle, the
# static assets, and the import map / lockfile the entry resolves.
COPY --from=web-builder /web/_fresh ./_fresh
COPY --from=web-builder /web/static ./static
COPY --from=web-builder /web/deno.json /web/deno.lock ./

EXPOSE 8000

# tini (shipped in the deno base image at /tini) as PID 1 reaps zombies and
# forwards SIGTERM to the Deno server for a clean shutdown. --unstable-kv is
# required for Deno.openKv against the remote denokv service.
ENTRYPOINT ["/tini", "--", "deno", "serve", "-A", "--unstable-kv", "--port", "8000", "/web/_fresh/server.js"]
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,16 +153,29 @@ DMOZDB_PORT=8080 DMOZDB_DATA_DIR=./data ./zig-out/bin/dmozdb

### Run with Docker

The backend (Zig) and the web frontend (Deno/Fresh) build as two separate images.

```bash
# Build the Docker image
docker build -t dmozdb:latest .
# Build the backend image
docker build -f Dockerfile.backend -t dmozdb-backend:latest .

# Run the container
# Run the backend (binary protocol on 8080)
docker run -d \
--name dmozdb \
-p 8080:8080 \
-v dmozdb-data:/var/lib/dmozdb \
dmozdb:latest
dmozdb-backend:latest

# Build the web frontend image
docker build -f Dockerfile.web -t dmozdb-web:latest .

# Run the web frontend (point it at the backend + a denokv instance)
docker run -d \
--name dmozdb-web \
-p 8000:8000 \
-e DMOZDB_HOST=host.docker.internal -e DMOZDB_PORT=8080 \
-e KV_PATH=http://host.docker.internal:4512 -e DENO_KV_ACCESS_TOKEN=dev-token \
dmozdb-web:latest
```

### Development Container
Expand All @@ -180,8 +193,9 @@ The project includes a full [Dev Container](.devcontainer/devcontainer.json) con
| `zt` | `zig build test` | Run all tests |
| `zr` | `zig build run` | Run the server |
| `zfmt` | `zig fmt src/` | Format all source files |
| `db` | `docker build -t dmozdb .` | Build Docker image |
| `dr` | `docker run --rm -p 8080:8080 dmozdb` | Run Docker container |
| `db` | `docker build -f Dockerfile.backend -t dmozdb-backend .` | Build backend image |
| `dbw` | `docker build -f Dockerfile.web -t dmozdb-web .` | Build web image |
| `dr` | `docker run --rm -p 8080:8080 dmozdb-backend` | Run backend container |

---

Expand Down Expand Up @@ -486,7 +500,8 @@ zig-directory/
├── .devcontainer/ Dev Container configuration
├── build.zig Zig build configuration
├── bench_binary.zig Binary protocol benchmark tool
└── Dockerfile Alpine-based container image
├── Dockerfile.backend Backend (Zig) container image
└── Dockerfile.web Web frontend (Deno/Fresh) container image
```

---
Expand Down
Loading
Loading