Skip to content

Deployment

Reference deployment artifacts for running the CAMBER read-only API over a Parquet store. These are starting points, not turnkey infra, and nothing here publishes anything.

The API serves GET only (/about /health /sites /points /history) and never writes to the BAS/OT. Keep it behind the cluster boundary or an authenticating ingress — see SECURITY.md.

Runtime topology: a separate writer populates the store out-of-band; the API pods only read.

flowchart LR
  writer["Batch writer (analysis + ParquetStore)"] -- "populates out-of-band" --> store["Parquet store (ReadOnlyMany PVC / object store)"]
  img["ghcr.io/yroussev/camber image"] -- "runs" --> api["Read-only API (2 non-root replicas)"]
  store -- "read-only mount" --> api
  ingress["Authenticating ingress"] -- "GET requests" --> api
  api -- "serves /about /health /sites /points /history" --> ingress
  api -. "never writes to BAS/OT" .-> bas["BAS / OT"]

Docker / Compose

The primary path. See ../DOCKER.md: docker compose up api serves the API over ./data/store; the multi-arch image is at ghcr.io/yroussev/camber.

Kubernetes

deploy/k8s/camber-api.yaml — a namespace, a read-only PVC for the store, a 2-replica non-root Deployment (readiness/liveness on /health, resource limits, read-only root FS), and a ClusterIP Service.

kubectl apply -f deploy/k8s/camber-api.yaml
# populate the PVC out-of-band (the API only reads); front the Service with an auth ingress.

The store is a ReadOnlyMany PVC: a separate writer (a batch job running the analysis + ParquetStore) populates it; the API pods mount it read-only.

conda-forge

deploy/conda/recipe.yaml is the source-of-truth recipe in the v1 recipe.yaml format (rattler-build; conda-forge deprecated the v0 meta.yaml): noarch: python, the runtime deps (matplotlib-base is the conda-forge name), the camber entry point, license_file: [LICENSE, NOTICE], and a tests block that imports the package, pip checks the deps, and runs camber --help against both the minimum and latest Python. It deliberately omits run_constrained (several optional extras aren't packaged on conda-forge, which would fail lint) — those can be added in a follow-up feedstock PR.

Validate it locally before submitting: conda-smithy lint recipes/camber-toolkit and a full rattler-build build --recipe recipe.yaml -c conda-forge (downloads the sdist, verifies the sha256, resolves deps, runs the test block). To retarget a new release, bump context.version and refresh the sdist sha256 for that version so the pair matches:

curl -sL https://pypi.org/pypi/camber-toolkit/<version>/json \
  | jq -r '.urls[] | select(.packagetype=="sdist") | .digests.sha256'

Submit via conda-forge/staged-recipes: fork it, drop this file at recipes/camber-toolkit/recipe.yaml, and open a PR (this creates the feedstock — the listed recipe-maintainers handle must comment agreeing to maintain). Once the feedstock exists, regro-cf-autotick-bot opens version-bump PRs automatically on each PyPI release. Until then, install from PyPI: pip install camber-toolkit.

Docs site (GitHub Pages)

.github/workflows/pages.yml builds the MkDocs site (mkdocs build) and deploys it to GitHub Pages, on every push to main that touches docs/, mkdocs.yml or the workflow itself, plus a manual workflow_dispatch. The site is live at https://yroussev.github.io/camber/. Build locally with pip install -e .[docs] && mkdocs serve.

Enabling Pages on a fork or a new repo is a one-time action, and enablement: true on actions/configure-pages is not reliably enough on its own: the workflow's GITHUB_TOKEN is often refused with Create Pages site failed. Error: Resource not accessible by integration, which is what happened here. Enable it with a credential that can, then run the workflow:

gh api -X POST repos/:owner/:repo/pages -f build_type=workflow   # or: Settings → Pages → Source: GitHub Actions
gh workflow run pages.yml

Hosted demo

The site can carry a self-contained demo — the runnable examples on public CC-BY datasets (examples/lbnl_fdd, examples/bdg2) plus a rendered site report — as static Pages content, needing no infrastructure beyond the Pages deploy above.

Community (repo-owner actions)

  • Enable GitHub Discussions (Settings → Features → Discussions).
  • Confirm the issue/PR templates surface; set repo topics/description.
  • Track the PEP-541 request to reclaim the bare camber PyPI name (camber-toolkit remains the permanent distribution name regardless).