From 55852a9efb0a4fd425efc1527a4e81bca58235da Mon Sep 17 00:00:00 2001 From: ZDDC Date: Fri, 8 May 2026 08:33:01 -0500 Subject: [PATCH] helm: add zddc-server-cache example chart + ZDDC_NO_AUTH on prod/dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New chart helm/zddc-server-cache/ deploys zddc-server in client mode against an upstream master. Mirrors the prod chart's source-build-via- init-container pattern but with: - ZDDC_UPSTREAM, ZDDC_MODE, ZDDC_BEARER_FILE, ZDDC_NO_AUTH, ZDDC_SKIP_TLS_VERIFY, ZDDC_MIRROR_SUBTREE, ZDDC_MIRROR_MIN_INTERVAL wired from values.yaml. Mirror-only env vars conditionally rendered (only when mode=mirror) to keep the rendered manifest minimal. - Bearer token mounted from a separately-created Kubernetes Secret (defaultMode 0400) at /etc/zddc/bearer/token. values.yaml.example documents the secret-creation flow but contains no token. Secret reference can be set to "" to disable bearer auth (only valid for upstreams running --no-auth). - Recreate strategy + replicaCount: 1 (multiple replicas would race the cache directory and double the upstream walker traffic). - TCP-socket probes instead of HTTP — HTTP probes against / would fail when both upstream is unreachable AND the cache is empty (the cache layer returns 503 + offline header in that state), causing crashloops. TCP verifies process liveness without depending on upstream reachability or cache contents. - Mounts a separate cache PVC (operator-provided, like the master's data PVC). Sized to the working set you expect to mirror; can be much smaller than the master's data volume. Existing prod and dev charts gain optional ZDDC_NO_AUTH wired from zddc.env.noAuth (default false → no change to existing rendered manifests). Useful for trusted-LAN or genuinely-public master deployments. Updated docs: helm/README.md gains the cache row in the chart table, the cache-install quickstart with the secret-creation flow, and the cache-specific structural notes (Recreate / TCP probes / single- instance). CLAUDE.md and ARCHITECTURE.md updated to reflect three charts instead of two. Verified with helm template rendering: ZDDC_NO_AUTH only renders when noAuth: true; ZDDC_MIRROR_SUBTREE / ZDDC_MIRROR_MIN_INTERVAL only render when mode: mirror; bearer volume + ZDDC_BEARER_FILE only render when bearer.secretName is non-empty. Co-Authored-By: Claude Opus 4.7 (1M context) --- ARCHITECTURE.md | 2 +- CLAUDE.md | 2 +- helm/README.md | 46 ++++- helm/zddc-server-cache/Chart.yaml | 32 ++++ helm/zddc-server-cache/templates/_helpers.tpl | 33 ++++ .../templates/deployment.yaml | 162 ++++++++++++++++++ helm/zddc-server-cache/templates/ingress.yaml | 29 ++++ helm/zddc-server-cache/templates/service.yaml | 15 ++ helm/zddc-server-cache/values.yaml.example | 150 ++++++++++++++++ .../zddc-server-dev/templates/deployment.yaml | 4 + helm/zddc-server-dev/values.yaml.example | 9 + .../templates/deployment.yaml | 4 + helm/zddc-server-prod/values.yaml.example | 17 ++ 13 files changed, 498 insertions(+), 7 deletions(-) create mode 100644 helm/zddc-server-cache/Chart.yaml create mode 100644 helm/zddc-server-cache/templates/_helpers.tpl create mode 100644 helm/zddc-server-cache/templates/deployment.yaml create mode 100644 helm/zddc-server-cache/templates/ingress.yaml create mode 100644 helm/zddc-server-cache/templates/service.yaml create mode 100644 helm/zddc-server-cache/values.yaml.example diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index ac9f112..7ff13f6 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -66,7 +66,7 @@ Website files (what `zddc.varasys.io` serves) live on a **separate Codeberg repo Every URL under `/releases/` resolves directly via the symlink chain — no `manifest.json`, no Caddy regex-rewrite, no JavaScript indirection, no third-party mirror. Caddy serves these as plain static files. The Docker-tag pattern: `:1.2.3` is pinned, `:1.2` floats, `:1` floats further, `:stable` floats furthest, and `:beta` / `:alpha` are mutable channel mirrors that overwrite in place. -**zddc-server binaries are reproducible from a tag, not in git** — `./build alpha|beta|release` cross-compiles them into `dist/release-output/`, `./deploy` rsyncs them to `/srv/zddc/releases/`, Caddy serves from there. Older versions: `git checkout zddc-server-v0.0.8 && ./build release 0.0.8`. The `helm/zddc-server-{prod,dev}/` charts build from source via init container, but operators who want a prebuilt binary just `curl -O https://zddc.varasys.io/releases/zddc-server_stable_linux-amd64`. The single cell link per release points at `zddc-server_.html`, a small generated stub that surfaces all four platform downloads. +**zddc-server binaries are reproducible from a tag, not in git** — `./build alpha|beta|release` cross-compiles them into `dist/release-output/`, `./deploy` rsyncs them to `/srv/zddc/releases/`, Caddy serves from there. Older versions: `git checkout zddc-server-v0.0.8 && ./build release 0.0.8`. The `helm/zddc-server-{prod,dev,cache}/` charts build from source via init container, but operators who want a prebuilt binary just `curl -O https://zddc.varasys.io/releases/zddc-server_stable_linux-amd64`. The single cell link per release points at `zddc-server_.html`, a small generated stub that surfaces all four platform downloads. To preview a build locally, open `dist/tool.html` directly via the dev server. To publish on `zddc.varasys.io`, cut a release with `./build alpha|beta|release` and then `./deploy`. diff --git a/CLAUDE.md b/CLAUDE.md index 5a1c6b1..c3c4538 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,7 +25,7 @@ This is a **monorepo of independent tools**, not one application: - `zddc/` — Go HTTP server (separate sub-project; Go 1.24+). Two deployment shapes from the same binary: (1) **master** — owns a file tree under `ZDDC_ROOT`, applies `.zddc` ACL cascades, serves files / app HTML / archive listings. Two auth paths on master: `Authorization: Bearer ` validated against self-issued tokens at `/.zddc.d/tokens/` for CLI/scripted callers, or `X-Auth-Request-Email` injected by an upstream proxy for browser sessions. Self-service token UI at `/.tokens` + JSON API at `/.api/tokens`. (2) **client** — when `--upstream ` is set, the binary becomes a downstream proxy/cache/mirror (`zddc/internal/cache/`); master-side machinery is bypassed and `--root` becomes the cache directory. Three sub-modes via `--mode proxy|cache|mirror` (mirror is phase 3). Cache layout is a normal ZDDC root, so the cache dir can be served as a plain master if you unset `--upstream`. Marker file `.zddc-upstream` records provenance. `--no-auth` skips ACL enforcement entirely on this instance (distinct from `--insecure` which only relaxes the no-root-`.zddc` startup check); `--skip-tls-verify` is a separate flag for self-signed upstream certs. Cross-compiled binaries are produced by `./build` and live in `dist/release-output/` (gitignored); `./deploy` rsyncs them to `/srv/zddc/releases/` on the deploy host (Caddy serves them at `https://zddc.varasys.io/releases/`). The `helm/` charts in this repo build from source at deploy time. - `shared/` — `base.css` plus shared JS modules (`zddc.js`, `hash.js`, `zddc-filter.js`, `theme.js`, `help.js`) included by every tool's build, and `build-lib.sh` (POSIX sh helpers sourced by every tool's `build.sh` AND by the top-level `build` for lockstep release helpers). - **Two-repo + deploy-host model.** Source code lives here (`codeberg.org/VARASYS/ZDDC`). Hand-edited website content lives in a separate repo (`codeberg.org/VARASYS/ZDDC-website`, typically cloned at `~/src/zddc-website/` — just `index.html`, `reference.html`, `css/`, `js/`, `img/`; no releases, no LFS). The live site at `zddc.varasys.io` is served from `/srv/zddc/` on the deploy host: Caddy bind-mounts that path, and it's populated by `./deploy` from this repo's `dist/release-output/` plus `~/src/zddc-website/`. **Releases are NOT in any git history** — they're reproducible from this repo's `-vX.Y.Z` tags by checking out the tag and running `./build release X.Y.Z`. Per-version files (`_v.html`) are immutable; partial-version pins (`_v.html`, `_v.html`) and channel mirrors (`_{stable,beta,alpha}.html`) are symlinks; zddc-server has analogous `zddc-server_v_` per-version binaries plus channel/partial-version symlinks plus `zddc-server_.html` stub pages that fan out the four-platform download in one cell. **Install model:** local use is a download from `/releases/`. Server use is `zddc-server`, which has the current-stable build of all six tools baked in via `//go:embed` (compile-time default). Tools auto-served at folder-name-driven paths: `archive` everywhere, `classifier` in `Incoming`/`Working`/`Staging` subtrees, `mdedit` in `Working` subtrees, `transmittal` in `Staging` subtrees, `landing` only at root. Override via `.zddc apps:` cascade entry (channel/version/URL/path) — fetched once, cached at `/_app/`. Drop a real `.html` file at any path to override. -- `helm/` — example Helm charts for zddc-server (`zddc-server-prod/`, `zddc-server-dev/`). Both compile from source via init container. Operators copy `values.yaml.example` and customize. No secrets in repo. +- `helm/` — example Helm charts for zddc-server. Three flavors: `zddc-server-prod/` (production master), `zddc-server-dev/` (development master with OverlayFS isolation), `zddc-server-cache/` (downstream client running in proxy/cache/mirror mode against an upstream master, with bearer token from a Kubernetes Secret). All compile from source via init container. Operators copy `values.yaml.example` and customize. No secrets in repo — the cache chart references a separately-created Secret for the bearer token. - `tests/` — Playwright specs (Chromium only, requires File System Access API). `tests/schema.spec.js` validates `transmittal.schema.json` against canonical fixtures via `ajv` (only dev dep besides Playwright) ## Most-used commands diff --git a/helm/README.md b/helm/README.md index 3b58d7a..3a51543 100644 --- a/helm/README.md +++ b/helm/README.md @@ -1,7 +1,7 @@ # Helm charts -Two example charts for deploying [zddc-server](../zddc/) on Kubernetes. -Both compile zddc-server from source via an init container — no +Three example charts for deploying [zddc-server](../zddc/) on Kubernetes. +All compile zddc-server from source via an init container — no container image needs to be pulled from a registry, and no binary needs to be built ahead of time. The init container clones the repo at a configured git ref and runs `go build`; the main container is plain @@ -11,16 +11,24 @@ alpine + the freshly built static binary. | Chart | When to use | |---|---| -| **`zddc-server-prod/`** | Production. Pin `zddc.gitRef` to a stable tag (`zddc-server-vX.Y.Z`). Slower probe cadence; image-pull policy `IfNotPresent`. Mounts the data PVC directly RW at `ZDDC_ROOT`. | -| **`zddc-server-dev/`** | Development / soak. Tracks `main` by default; `helm upgrade` triggers a pod recreate so each rollout pulls the latest commit. Faster probes; debug-level logging (request headers logged — sensitive). Wraps the data PVC in **OverlayFS** (lower = PVC mounted RO, upper = ephemeral `emptyDir`) so dev-side writes never mutate the underlying store. Use this shape when the dev replica points at the same data as prod. | +| **`zddc-server-prod/`** | Production **master**. Pin `zddc.gitRef` to a stable tag (`zddc-server-vX.Y.Z`). Slower probe cadence; image-pull policy `IfNotPresent`. Mounts the data PVC directly RW at `ZDDC_ROOT`. The token system is enabled automatically (tokens persist on the data PVC at `/.zddc.d/tokens/`); operators visit `/.tokens` to issue them. | +| **`zddc-server-dev/`** | Development / soak **master**. Tracks `main` by default; `helm upgrade` triggers a pod recreate so each rollout pulls the latest commit. Faster probes; debug-level logging (request headers logged — sensitive). Wraps the data PVC in **OverlayFS** (lower = PVC mounted RO, upper = ephemeral `emptyDir`) so dev-side writes never mutate the underlying store. Use this shape when the dev replica points at the same data as prod. | +| **`zddc-server-cache/`** | Downstream **client** (proxy / cache / mirror) of an upstream master. Set `zddc.upstream.url` + `zddc.upstream.mode`; the binary skips master-side machinery and forwards all requests to the master, persisting responses under the cache PVC (in cache or mirror modes). Bearer auth via a separately-created Kubernetes Secret. Use cases: corporate-master → DR-mirror, vendor-scoped mirror in a vendor's own cluster, regional edge cache, dev environment that mirrors prod read-only. Mirror mode adds an access-triggered subtree walker. | -The chart values are nearly identical between the two; the differences +The prod and dev chart values are nearly identical; the differences are encoded as defaults in each chart's `values.yaml.example`. The dev chart's overlay-isolation layer is a structural difference, not a values-level toggle — see `zddc-server-dev/templates/deployment.yaml` for the privileged init container and the `data-readonly` / `overlay-scratch` / `data` volume sandwich. +The cache chart shares the same source-build pattern but adds +client-mode env wiring (`ZDDC_UPSTREAM`, `ZDDC_MODE`, `ZDDC_BEARER_FILE`, +`ZDDC_NO_AUTH`, `ZDDC_SKIP_TLS_VERIFY`, mirror-mode subtree config), +a Recreate strategy (single-instance — multiple replicas would race +the cache directory), and TCP-socket probes (HTTP probes against `/` +would fail when both upstream is down AND the cache is empty). + ## Quick start ```sh @@ -48,6 +56,30 @@ helm install zddc-server-dev helm/zddc-server-dev/ -f my-dev-values.yaml # Trigger a rebuild from latest main HEAD (dev chart) helm upgrade zddc-server-dev helm/zddc-server-dev/ -f my-dev-values.yaml + +# Cache install (downstream client of an upstream master) +# +# 1) Issue a bearer token on the master at https:///.tokens +# 2) Create the Secret (do NOT put the token in values.yaml): +kubectl create secret generic zddc-cache-bearer \ + --from-literal=token= + +# 3) Create a cache PVC (separate from the master's data PVC; can +# be smaller — sized to the working set you expect to mirror): +kubectl apply -f - <<'PVC' +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: { name: zddc-cache } +spec: + accessModes: [ReadWriteOnce] + resources: { requests: { storage: 50Gi } } + storageClassName: your-block-storage +PVC + +# 4) Install the chart, pointing at your master: +cp helm/zddc-server-cache/values.yaml.example my-cache-values.yaml +$EDITOR my-cache-values.yaml # set zddc.upstream.url, mode, etc. +helm install zddc-server-cache helm/zddc-server-cache/ -f my-cache-values.yaml ``` ## What the chart does and doesn't do @@ -107,8 +139,12 @@ for tracking-main convenience). ```sh helm lint helm/zddc-server-prod/ helm lint helm/zddc-server-dev/ +helm lint helm/zddc-server-cache/ # Render to inspect (uses default values from values.yaml.example): helm template test-prod helm/zddc-server-prod/ \ --values helm/zddc-server-prod/values.yaml.example + +helm template test-cache helm/zddc-server-cache/ \ + --values helm/zddc-server-cache/values.yaml.example ``` diff --git a/helm/zddc-server-cache/Chart.yaml b/helm/zddc-server-cache/Chart.yaml new file mode 100644 index 0000000..a89bfef --- /dev/null +++ b/helm/zddc-server-cache/Chart.yaml @@ -0,0 +1,32 @@ +apiVersion: v2 +name: zddc-server-cache +description: | + Downstream cache / mirror deployment of zddc-server. Compiles from + source via an init container at deploy time (no image pull from a + registry); the main container is alpine + the freshly-built binary. + Runs in client mode against an upstream zddc-server master, caching + every accessed file (and, in mirror mode, proactively walking + configured subtrees). + + Use cases: corporate-master → DR-mirror, vendor-scoped mirror in a + vendor's own cluster, regional edge cache, dev/staging environment + that mirrors prod. Distinct from `zddc-server-prod` (which IS a + master) and `zddc-server-dev` (a master with overlay isolation). + + TLS upstream is verified by default (set --skip-tls-verify only for + self-signed dev masters or internal CAs you haven't yet added to + the trust store). +type: application +version: 0.1.0 +appVersion: "0.0.7" # zddc-server git tag this chart was last verified against +home: https://zddc.varasys.io/ +sources: + - https://codeberg.org/VARASYS/ZDDC +maintainers: + - name: VARASYS +keywords: + - zddc + - cache + - mirror + - file-server + - document-control diff --git a/helm/zddc-server-cache/templates/_helpers.tpl b/helm/zddc-server-cache/templates/_helpers.tpl new file mode 100644 index 0000000..eaeaa72 --- /dev/null +++ b/helm/zddc-server-cache/templates/_helpers.tpl @@ -0,0 +1,33 @@ +{{/* +Common labels and the fullname helper. Stays minimal; chart consumers +who want richer labels can override via metadata.labels in their +values.yaml or post-render kustomize. +*/}} + +{{- define "zddc-server.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "zddc-server.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{- define "zddc-server.labels" -}} +app.kubernetes.io/name: {{ include "zddc-server.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/version: {{ .Values.zddc.gitRef | quote }} +app.kubernetes.io/component: cache +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" }} +{{- end -}} + +{{- define "zddc-server.selectorLabels" -}} +app.kubernetes.io/name: {{ include "zddc-server.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/component: cache +{{- end -}} diff --git a/helm/zddc-server-cache/templates/deployment.yaml b/helm/zddc-server-cache/templates/deployment.yaml new file mode 100644 index 0000000..cc6c87b --- /dev/null +++ b/helm/zddc-server-cache/templates/deployment.yaml @@ -0,0 +1,162 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "zddc-server.fullname" . }} + labels: + {{- include "zddc-server.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + # Cache writes serialize through the local filesystem; running two + # replicas would race the cache directory + double the upstream + # walker traffic. Recreate strategy ensures only one pod holds the + # cache PVC at a time. + strategy: + type: Recreate + selector: + matchLabels: + {{- include "zddc-server.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "zddc-server.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: zddc-bin + emptyDir: {} + - name: data + persistentVolumeClaim: + claimName: {{ .Values.data.pvcName }} + {{- if .Values.bearer.secretName }} + - name: bearer + secret: + secretName: {{ .Values.bearer.secretName | quote }} + defaultMode: 0400 + items: + - key: {{ .Values.bearer.secretKey | quote }} + path: token + {{- end }} + initContainers: + # Build zddc-server from the pinned git ref. Same flow as the + # master charts — the binary is the same; client mode is + # selected at runtime via ZDDC_UPSTREAM. + - name: build-zddc-server + image: {{ printf "%s:%s" .Values.buildImage.repository .Values.buildImage.tag | quote }} + imagePullPolicy: IfNotPresent + command: ["/bin/sh", "-c"] + args: + - | + set -eu + apk add --no-cache git + git clone --depth 1 --branch "$GIT_REF" "$GIT_REPO" /workspace + cd /workspace/zddc + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ + go build -trimpath \ + -ldflags="-s -w -X main.version=$GIT_REF" \ + -o /out/zddc-server \ + ./cmd/zddc-server + echo "built /out/zddc-server from $GIT_REF" + env: + - name: GIT_REPO + value: {{ .Values.zddc.gitRepo | quote }} + - name: GIT_REF + value: {{ .Values.zddc.gitRef | quote }} + volumeMounts: + - name: zddc-bin + mountPath: /out + resources: + requests: + cpu: 200m + memory: 256Mi + limits: + cpu: 1000m + memory: 512Mi + containers: + - name: zddc-server + image: {{ printf "%s:%s" .Values.runtimeImage.repository .Values.runtimeImage.tag | quote }} + imagePullPolicy: IfNotPresent + command: ["/zddc/zddc-server"] + ports: + - name: http + containerPort: 8080 + protocol: TCP + env: + - name: ZDDC_ROOT + value: {{ .Values.zddc.env.rootPath | quote }} + - name: ZDDC_ADDR + value: {{ .Values.zddc.env.addr | quote }} + - name: ZDDC_TLS_CERT + value: "none" + - name: ZDDC_INSECURE_DIRECT + value: "1" + - name: ZDDC_EMAIL_HEADER + value: {{ .Values.zddc.env.emailHeader | quote }} + - name: ZDDC_CORS_ORIGIN + value: {{ .Values.zddc.env.corsOrigin | quote }} + - name: ZDDC_LOG_LEVEL + value: {{ .Values.zddc.env.logLevel | quote }} + - name: ZDDC_INDEX_PATH + value: {{ .Values.zddc.env.indexPath | quote }} + {{- if .Values.zddc.env.noAuth }} + - name: ZDDC_NO_AUTH + value: "1" + {{- end }} + # Client-mode flags. ZDDC_UPSTREAM activates client mode + # in cmd/zddc-server/main.go's runClient short-circuit. + - name: ZDDC_UPSTREAM + value: {{ .Values.zddc.upstream.url | quote }} + - name: ZDDC_MODE + value: {{ .Values.zddc.upstream.mode | quote }} + {{- if .Values.zddc.upstream.skipTLSVerify }} + - name: ZDDC_SKIP_TLS_VERIFY + value: "1" + {{- end }} + {{- if .Values.bearer.secretName }} + - name: ZDDC_BEARER_FILE + value: "/etc/zddc/bearer/token" + {{- end }} + {{- if eq .Values.zddc.upstream.mode "mirror" }} + {{- with .Values.zddc.upstream.mirrorSubtree }} + - name: ZDDC_MIRROR_SUBTREE + value: {{ . | quote }} + {{- end }} + {{- with .Values.zddc.upstream.mirrorMinInterval }} + - name: ZDDC_MIRROR_MIN_INTERVAL + value: {{ . | quote }} + {{- end }} + {{- end }} + volumeMounts: + - name: zddc-bin + mountPath: /zddc + - name: data + mountPath: {{ .Values.zddc.env.rootPath }} + {{- with .Values.data.subPath }} + subPath: {{ . | quote }} + {{- end }} + {{- if .Values.bearer.secretName }} + - name: bearer + mountPath: /etc/zddc/bearer + readOnly: true + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + # TCP-socket probes only — HTTP probes against `/` would + # fail when both upstream is unreachable AND the cache is + # empty (the cache layer returns 503 in that state). TCP + # probes verify the server process is alive without + # depending on upstream reachability or cache contents. + livenessProbe: + tcpSocket: + port: http + initialDelaySeconds: 5 + periodSeconds: 30 + timeoutSeconds: 5 + readinessProbe: + tcpSocket: + port: http + initialDelaySeconds: 2 + periodSeconds: 10 + timeoutSeconds: 3 diff --git a/helm/zddc-server-cache/templates/ingress.yaml b/helm/zddc-server-cache/templates/ingress.yaml new file mode 100644 index 0000000..bcd3d72 --- /dev/null +++ b/helm/zddc-server-cache/templates/ingress.yaml @@ -0,0 +1,29 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "zddc-server.fullname" . }} + labels: + {{- include "zddc-server.labels" . | nindent 4 }} +spec: + {{- with .Values.ingress.className }} + ingressClassName: {{ . }} + {{- end }} + {{- if .Values.ingress.tls.enabled }} + tls: + - hosts: + - {{ .Values.ingress.host }} + secretName: {{ .Values.ingress.tls.secretName }} + {{- end }} + rules: + - host: {{ .Values.ingress.host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "zddc-server.fullname" . }} + port: + number: {{ .Values.service.port }} +{{- end }} diff --git a/helm/zddc-server-cache/templates/service.yaml b/helm/zddc-server-cache/templates/service.yaml new file mode 100644 index 0000000..8ded8b6 --- /dev/null +++ b/helm/zddc-server-cache/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "zddc-server.fullname" . }} + labels: + {{- include "zddc-server.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - name: http + port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + selector: + {{- include "zddc-server.selectorLabels" . | nindent 4 }} diff --git a/helm/zddc-server-cache/values.yaml.example b/helm/zddc-server-cache/values.yaml.example new file mode 100644 index 0000000..67ee218 --- /dev/null +++ b/helm/zddc-server-cache/values.yaml.example @@ -0,0 +1,150 @@ +# values.yaml.example — zddc-server-cache +# +# Copy to values.yaml (or pass via --values) and customize for your +# environment. Contains NO secrets — the upstream bearer token MUST be +# provided via a separately-created Kubernetes Secret (see `bearer:` +# below). Do not paste the token value here. + +# Source-build configuration. The init container clones the repo at +# `gitRef` and compiles cmd/zddc-server. Pin gitRef to a stable tag +# (zddc-server-vX.Y.Z) for production caches; tracking main is fine +# for dev mirrors. +zddc: + gitRepo: https://codeberg.org/VARASYS/ZDDC.git + gitRef: zddc-server-v0.0.7 # pin to a stable tag + + # ZDDC environment-variable contract — see zddc/README.md "Client mode". + env: + # Local cache directory (mounted from the cache PVC; see `data:` + # below). The cache layer writes files here as they're fetched. + rootPath: /srv + + # Listening address for incoming requests to this cache instance. + # Plain HTTP — ingress / mesh terminates TLS upstream of the pod. + addr: ":8080" + + # Email-header convention from your authenticating reverse proxy. + # Used for AccessLog only in client mode (auth flows to upstream + # as a bearer; the cache layer doesn't enforce ACL locally when + # noAuth: true). + emailHeader: X-Auth-Request-Email + + # CORS allowlist for the local instance. Same semantics as the + # master chart — empty disables CORS, which is the right default + # for embedded-tools / same-origin browsing. + corsOrigin: "" + + # info / warn / error / debug. + logLevel: info + + indexPath: ".archive" + + # Skip ACL enforcement on incoming requests. Almost always true + # for a personal/field-engineer cache (the laptop is single-user- + # trust and the upstream master already filtered). Set to false + # only if you've put your own auth proxy in front of this cache + # AND want it to re-evaluate ACLs against cached `.zddc` files. + noAuth: true + + # Upstream master configuration. + upstream: + # The master URL. Required. Don't include a trailing slash. + url: "https://zddc.example.com" + + # proxy / cache / mirror. + # proxy — forward live, no disk persistence + # cache — persist responses on access (default; field-engineer use) + # mirror — cache + access-triggered subtree warmer (vendor / + # backup / complete-offline use) + mode: cache + + # Accept self-signed / untrusted upstream TLS certs. Distinct from + # noAuth. Use only for dev masters with self-signed certs or for + # internal CAs your cluster's trust store doesn't yet have. + skipTLSVerify: false + + # Mirror-mode only. Comma-separated URL subtrees the access- + # triggered walker keeps current. Empty + mode=mirror = full + # mirror ("/"). Ignored when mode != mirror. + mirrorSubtree: "" + + # Mirror-mode only. Min gap between walks of the same subtree. + # Idle subtrees generate zero upstream traffic until next access. + # Default 1h. + mirrorMinInterval: 1h + +# Bearer token — required when the upstream master enforces auth. +# Create a Secret separately (do NOT paste the token here): +# +# 1. On the master, sign in via your auth proxy and visit +# https:///.tokens to issue a token. +# 2. Wrap it in a Kubernetes Secret: +# +# kubectl create secret generic zddc-cache-bearer \ +# --from-literal=token= +# +# 3. Reference the Secret here. +# +# Set `secretName: ""` to disable bearer auth (only valid when the +# upstream is `--no-auth` or behind your own auth proxy that doesn't +# require bearer auth from internal callers). +bearer: + secretName: zddc-cache-bearer + secretKey: token + +# Cache-storage PVC. Sized for the working set you expect to mirror — +# can be smaller than the master's data volume since only accessed +# files (or, in mirror mode, files under configured subtrees) get +# cached. Operators provision the PVC themselves; this chart only +# references it by name. ReadWriteOnce is fine — the cache is single- +# instance by design. +data: + pvcName: zddc-cache # name of an existing PersistentVolumeClaim + subPath: "" + +# Service exposure. The cache listens on a plain HTTP port; ingress +# (or mesh sidecar) terminates TLS and forwards to this service. +service: + type: ClusterIP + port: 8080 + +# Ingress is optional — disabled by default since most cache +# deployments wire into an existing ingress / auth-proxy stack. +ingress: + enabled: false + className: "" + host: zddc-cache.example.com + tls: + enabled: false + secretName: zddc-cache-tls + +# Pod resource limits. Cache instances are mostly I/O bound; the +# defaults below suit a small mirror (~1k files in working set). +# Bump cpu/memory for mirror mode against larger trees. +resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + +# Replicas. Cache instances are single-instance by design — multiple +# replicas would race on writes to the same cache directory and +# duplicate the upstream walker traffic. Use a separate cache +# deployment per region/tenant if you need fan-out. +replicaCount: 1 + +# Build-stage Go image (init container). +buildImage: + repository: docker.io/golang + tag: 1.24-alpine + +# Runtime image (main container). +runtimeImage: + repository: docker.io/alpine + tag: "3.19" + +# Image pull credentials, if your registry requires them. +imagePullSecrets: [] +# - name: regcred diff --git a/helm/zddc-server-dev/templates/deployment.yaml b/helm/zddc-server-dev/templates/deployment.yaml index bbd3d67..63b2033 100644 --- a/helm/zddc-server-dev/templates/deployment.yaml +++ b/helm/zddc-server-dev/templates/deployment.yaml @@ -147,6 +147,10 @@ spec: value: {{ .Values.zddc.env.logLevel | quote }} - name: ZDDC_INDEX_PATH value: {{ .Values.zddc.env.indexPath | quote }} + {{- if .Values.zddc.env.noAuth }} + - name: ZDDC_NO_AUTH + value: "1" + {{- end }} volumeMounts: - name: zddc-bin mountPath: /zddc diff --git a/helm/zddc-server-dev/values.yaml.example b/helm/zddc-server-dev/values.yaml.example index 7e27ea8..83702a5 100644 --- a/helm/zddc-server-dev/values.yaml.example +++ b/helm/zddc-server-dev/values.yaml.example @@ -30,6 +30,15 @@ zddc: logLevel: debug # full request headers logged; sensitive! indexPath: ".archive" + # Skip ACL enforcement entirely. Useful in trusted-LAN dev clusters + # where authentication isn't needed and you want to iterate without + # configuring an upstream auth proxy. Default false. + noAuth: false + + # Token system: enabled automatically — tokens persist at + # /.zddc.d/tokens/ on the data PVC. Sign in via your + # cluster's auth proxy and visit /.tokens to issue one. + data: pvcName: zddc-root-dev # name of an existing PVC in your dev namespace subPath: "" diff --git a/helm/zddc-server-prod/templates/deployment.yaml b/helm/zddc-server-prod/templates/deployment.yaml index 6872432..10221c0 100644 --- a/helm/zddc-server-prod/templates/deployment.yaml +++ b/helm/zddc-server-prod/templates/deployment.yaml @@ -86,6 +86,10 @@ spec: value: {{ .Values.zddc.env.logLevel | quote }} - name: ZDDC_INDEX_PATH value: {{ .Values.zddc.env.indexPath | quote }} + {{- if .Values.zddc.env.noAuth }} + - name: ZDDC_NO_AUTH + value: "1" + {{- end }} volumeMounts: - name: zddc-bin mountPath: /zddc diff --git a/helm/zddc-server-prod/values.yaml.example b/helm/zddc-server-prod/values.yaml.example index 4d8dd67..ea0bf0e 100644 --- a/helm/zddc-server-prod/values.yaml.example +++ b/helm/zddc-server-prod/values.yaml.example @@ -44,6 +44,23 @@ zddc: # collision with a real directory named ".archive". indexPath: ".archive" + # Skip ACL enforcement entirely on this instance. Anyone hitting + # the port reads everything in scope. Only enable for genuinely- + # public archives (and even then, only behind an authenticating + # ingress that doesn't gate on identity for /). Distinct from + # --insecure (which gates the startup check requiring a root .zddc). + # Default false. + noAuth: false + + # Bearer-token system. Master automatically self-issues tokens via + # /.tokens (browser) and /.api/tokens (JSON). The token store lives + # at /.zddc.d/tokens/ on the data PVC; no Helm + # configuration required. Operators sign in via the upstream auth + # proxy, visit /.tokens, copy the displayed token into a 0600 file, + # and pass --bearer-file to any CLI / cache / mirror that needs to + # authenticate against this master. See zddc/README.md "Bearer + # tokens" for the full lifecycle. + # Persistent storage for ZDDC_ROOT. Operators provide their own PVC, # typically backed by a shared filesystem (NFS, CephFS, SMB) so multiple # replicas of zddc-server (and your sync tooling) see the same tree.