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.
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:
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:
containers:
- name: operator
image: yolosearch:latest
command: ["/yolosearch-operator"]
args: ["--leader-elect=true"]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:
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.
just build-dual-arch produces statically linked Linux amd64 and arm64
binaries, with receipts, for yolosearch, yolosearch-operator, and
yolosearch-admin:
just build-dual-archThe 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.
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:
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.
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.
| 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.
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.
- Kubernetes — what the operator renders from these images
- Object store — the credentials the container needs
- Sizing — how large the cache mount should be