Container image
Omniglass ships as a single container image. The operator console is compiled
into the binary (-tags web plus go:embed), so one image is the whole app:
every run mode (server, node run, migrate, bootstrap, token) is the same
binary with a different first argument. The final image is distroless and runs
as an unprivileged user; the binary is statically linked (CGO disabled), so the
image is a few tens of megabytes with no shell or libc.
The published tag is a multi-arch manifest covering linux/amd64 and
linux/arm64; a host pulls the variant that matches its architecture
automatically. See Platforms for how that is built.
Where it ships
Section titled “Where it ships”The image workflow builds and pushes to the GitHub Container Registry on every
push to main and every same-repo pull request. A fork PR builds the image but
does not push it (a fork run has no registry credential), so a fork branch never
gets a published tag:
ghcr.io/hyperscaleav/omniglassTags:
| Tag | When | Mutable? |
|-----|------|----------|
| latest | push to main | yes |
| sha-<full sha> | every build | no, pins an exact commit |
| pr-<n> | head of open PR #n | yes, moves on each push |
The sha tag carries the full 40-character commit sha (type=sha,format=long).
The preview pipeline pins a deploy to sha-<full sha> so a rollout follows the
exact build.
Platforms
Section titled “Platforms”The image is published for linux/amd64 and linux/arm64 (Graviton, Ampere,
Apple silicon, Raspberry Pi class hardware). Both come from one cross-compile,
not native arm64 runners: because the binary is pure Go with CGO disabled, the
build stages run on the native CI host and go build retargets the arch with a
GOARCH switch, no emulation and no C toolchain. The arch-independent SPA
bundle is built once and embedded in both variants. The distroless base is
itself a multi-arch manifest, so the runtime layer resolves per target.
Cross-compiled artifacts get one emulated check before they ship: CI builds the
arm64 image, loads it under QEMU, and boots the binary (--help), so a broken
arm64 build fails the workflow before the manifest is pushed. There is no native
arm64 hardware in the loop; this boot test is the substitute.
Configuration
Section titled “Configuration”The binary is configured by environment, BYO Postgres. The table renders from the declared
environment registry (make gen), which the binary itself reads through, so a variable cannot
exist without appearing here:
| Variable | Default | Purpose |
|---|---|---|
OMNIGLASS_DSN | local dev DSN | Postgres connection string the Storage Gateway dials; wins over DATABASE_URL when both are set |
DATABASE_URL | (none) | conventional DSN fallback, used when OMNIGLASS_DSN is unset |
OMNIGLASS_ADDR | :8080 | HTTP listen address |
OMNIGLASS_SECURE_COOKIES | off | set true behind TLS to mark the session cookie Secure (https only) |
OMNIGLASS_NATS_ADDR | 127.0.0.1:4222 | listen address (host:port) of the embedded NATS server |
OMNIGLASS_NATS_STORE_DIR | temp dir | JetStream store directory |
OMNIGLASS_NATS_URL | nats://127.0.0.1:4222 | bus URL the node-claim exchange advertises to nodes |
OMNIGLASS_DATA_DIR | .omniglass | local non-Postgres server state (notably the fallback secret key) |
OMNIGLASS_SETTINGS_FILE | (none) | optional operator settings file (JSON or YAML), the layer between code defaults and the DB override |
OMNIGLASS_SECRET_KEY | (none) | base64 32-byte key-encryption key for secrets at rest; wins over the key file |
OMNIGLASS_SECRET_KEY_FILE | (none) | path to the key-encryption key; the intended production source (the generated fallback under the data dir is convenience, not security) |
The node process reads its own small set (the CLI-scope variables surface through the CLI reference instead):
| Variable | Default | Purpose |
|---|---|---|
OMNIGLASS_NODE_NAME | (none) | the node's registered name, the --name default for omniglass node run |
OMNIGLASS_NODE_TOKEN | (none) | the node's enrollment token, the --token default for omniglass node run |
Running it
Section titled “Running it”Apply the schema once, then run the server. (The server also applies pending
migrations itself on boot, so the separate migrate run is optional; it is
still useful to surface a schema problem before the server starts.)
DSN='postgres://user:pass@host:5432/omniglass?sslmode=require'
docker run --rm -e OMNIGLASS_DSN="$DSN" \ ghcr.io/hyperscaleav/omniglass:latest migrate
docker run -d -p 8080:8080 -e OMNIGLASS_DSN="$DSN" \ ghcr.io/hyperscaleav/omniglass:latest serverThe console is then at http://localhost:8080/web, and GET /api/v1/healthz
reports status: ok once the database leg passes. To sign in, mint an owner and
a token:
docker run --rm -e OMNIGLASS_DSN="$DSN" \ ghcr.io/hyperscaleav/omniglass:latest bootstrap alicedocker run --rm -e OMNIGLASS_DSN="$DSN" \ ghcr.io/hyperscaleav/omniglass:latest token alice --description "alice laptop"Building it locally
Section titled “Building it locally”make image builds the image for your host architecture only:
make image # omniglass:dev, VERSION = short commit shamake image TAG=v1 IMAGE=ghcr.io/hyperscaleav/omniglassTo reproduce the published multi-arch manifest, drive buildx directly (a
docker-container builder is required, since the default driver cannot emit a
manifest list). A manifest list cannot be --loaded into the local daemon, so
build with --push to a registry, or with --platform linux/arm64 --load to
inspect a single foreign arch:
docker buildx create --use --name omni # oncedocker buildx build --platform linux/amd64,linux/arm64 \ -t ghcr.io/hyperscaleav/omniglass:dev --push .Where this fits
Section titled “Where this fits”This image is the unit the Helm chart and the per-PR preview environments deploy. See Scaling and deployment for the deployment shape.