Skip to content

Deploy

Container image

Image contents, supported Linux architectures, writable mounts, and container commands.


YoloSearch ships as a FROM scratch image. There is no shell, no libc, no package manager, no writable home directory, and no implicit /tmp. The image contains the statically linked binaries and a CA bundle, and nothing else.

With a read-only root filesystem, deployments must mount each writable path used for caches, ingest, or temporary files.

What is in the image

Containerfile builds the data-plane image. It copies the CA certificate bundle out of a Debian stage and then puts two binaries into an empty image:

dockerfile
ARG TARGETARCH
FROM docker.io/library/debian:bookworm-slim AS certs
RUN apt-get update \
    && apt-get install -y --no-install-recommends ca-certificates \
    && rm -rf /var/lib/apt/lists/*

FROM scratch
ARG TARGETARCH
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY dist/yolosearch-linux-${TARGETARCH} /yolosearch
COPY dist/yolosearch-operator-linux-${TARGETARCH} /yolosearch-operator
USER 65532:65532
ENTRYPOINT ["/yolosearch"]
Path Binary Used by
/yolosearch The data plane and CLI serve, node, and every client verb; the image entrypoint
/yolosearch-operator The Kubernetes operator The operator Deployment, via an explicit command
/etc/ssl/certs/ca-certificates.crt — TLS to an S3 endpoint

One image carries both binaries. The operator Deployment in deploy/operator/operator.yaml overrides the entrypoint:

yaml
containers:
- name: operator
  image: yolosearch:latest
  command: ["/yolosearch-operator"]
  args: ["--leader-elect=true"]

The admin console image

The admin console is a separate process and a separate image. Containerfile.admin contains one binary and nothing else — not even the CA bundle, because the console never dials an object store:

dockerfile
ARG TARGETARCH
FROM scratch
ARG TARGETARCH
COPY dist/yolosearch-admin-linux-${TARGETARCH} /yolosearch-admin
USER 65532:65532
EXPOSE 8787
ENTRYPOINT ["/yolosearch-admin"]

The console reaches an index only through the generated Connect services. It receives no object-store credentials and no Kubernetes service-account token. See the admin console guide for what it can and cannot do.

Both architectures

just build-dual-arch produces statically linked Linux amd64 and arm64 binaries, with receipts, for yolosearch, yolosearch-operator, and yolosearch-admin:

zsh
just build-dual-arch

The Forgejo build-container workflow cross-compiles both architectures in a pinned builder image, assembles the scratch layers, and refuses to publish a manifest unless both the linux/amd64 and linux/arm64 descriptors are present. Publication targets the internal registry tcr.teixos.net; there is no public image to pull today, so a deployment builds its own or mirrors from that registry.

Running it

The image runs as USER 65532:65532 with no writable filesystem of its own, so every path YoloSearch writes to must be mounted. For a single-process server that is the data directory:

zsh
docker run --rm \
  --user 65532:65532 \
  --read-only \
  --tmpfs /tmp \
  -v "$PWD/ys-data:/var/lib/yolosearch" \
  -p 9500:9500 -p 9550:9550 \
  yolosearch:latest \
  serve --data-dir /var/lib/yolosearch --listen :9500

--data-dir derives the object, cache, ingest, and model directories beneath one path, which is why a single mount is enough here. A fleet role splits those paths across separate volumes; see the mount table below.

The mounts a deployment must supply

These are the paths the operator mounts into every role pod. A hand-written deployment needs the same set.

Mount path Setting that points at it Contents Disposable
/tmp — Scratch Yes
/var/lib/yolosearch/cache cache.dir Full-segment and decoded-block caches Yes
/var/lib/yolosearch/ingest ingest.dir Spooled batches awaiting a seal No, while a build is open
— object.dir or the object.s3.* keys Authoritative published objects Never

Everything under cache.dir is content-addressed and verified on use. Losing it makes the next request cold; it cannot lose an indexed document. The ingest spool is different: a sealed-but-unpublished spool is retried, so deleting it loses the documents it held.

Ports

Port Protocol Purpose Setting
9500 gRPC The data-plane API and the gRPC health service server.listen
9550 HTTP Prometheus exposition at /metrics observability.metrics_listen
8787 HTTP The admin console's default listen address (127.0.0.1:8787), in its own image --listen on yolosearch-admin

Under the operator the console is told --listen 0.0.0.0:8080 instead, and its Service publishes port 8080. The image's EXPOSE 8787 reflects the binary's default, not the port a Kubernetes deployment uses.

The gRPC server registers the standard grpc.health.v1.Health service, which is what the operator's startup, readiness, and liveness probes check. There is no HTTP health endpoint on a data-plane process.

Development images

Two more Containerfiles exist and are not for deployment. Containerfile.dev is the Apple Container development image used by just container-dev <task>, and Containerfile.ci is the pinned build-only toolchain the Forgejo workflows run inside. Neither is a runtime artifact.

Next

  • Kubernetes — what the operator renders from these images
  • Object store — the credentials the container needs
  • Sizing — how large the cache mount should be