Skip to content

Publish multi-arch (amd64 + arm64) images to GHCR #32

Description

@jason-shen

Problem

There is a working Dockerfile, and .github/workflows/deploy-server.yml builds an image on every push to main — but it pushes to a private Artifact Registry behind Workload Identity Federation, gated on four repo secrets (GCP_PROJECT_ID, GCP_REGION, GCP_SERVICE_ACCOUNT, GCP_WORKLOAD_IDENTITY_PROVIDER). That's the maintainer's deployment pipeline, not a distribution channel.

So there is no image anyone else can pull. To try StreamCore you must clone the repo, install Go, and build — even though the README's own quick start is otherwise a copy-paste affair and a docker-compose.yml exists at the root of the parent project. For a media server whose runtime already needs Node and Python present for plugins, "docker run and go" is a materially lower barrier than "get a Go toolchain".

The image is also linux/amd64 only. A large share of the likely audience is developing on Apple Silicon, where an amd64 image runs under emulation — for a latency-sensitive audio path that's not a reasonable way to evaluate the project.

Proposed change

Add .github/workflows/publish-image.yml publishing to GHCR (ghcr.io/streamcoreai/streamcore-server). GHCR needs no external account setup — GITHUB_TOKEN with packages: write is sufficient, which keeps this independent of the GCP credentials the deploy workflow uses.

  • Trigger on release/tag publication, and on push to main for a :main floating tag. Do not touch deploy-server.yml — the deployment path should keep working exactly as it does.
  • Build linux/amd64 and linux/arm64 via docker/setup-qemu-action + docker/setup-buildx-action, which docker/build-push-action@v6 (already in use in the deploy workflow) handles natively.
  • Tag with docker/metadata-action: semver on tags, main, and the commit SHA.
  • Enable GitHub Actions cache (cache-from: type=gha) — the runtime stage does npm install -g tsx, creates a Python venv, and loops npm install over every plugin directory. Uncached, that's slow; on emulated arm64 it's very slow. Expect the first arm64 build to be the long pole and check the wall time before merging.
  • Add a "Run with Docker" section to the README quick start with the pull command and the config mount.

The build stage is already CGO_ENABLED=0 (the Opus codec runs as WebAssembly through wazero, per the Dockerfile comment), so the Go side cross-compiles cleanly. The runtime stage is node:22-bookworm-slim, which publishes arm64 — no base image change needed.

Worth confirming

Whether the plugin pip install / npm install steps in the runtime stage succeed under arm64 emulation. If some plugin dependency has no arm64 wheel, note it on the issue — that's useful information regardless of how this lands.

Acceptance criteria

  • docker pull ghcr.io/streamcoreai/streamcore-server:main works for an anonymous user.
  • docker manifest inspect shows both linux/amd64 and linux/arm64.
  • The image runs on Apple Silicon natively and serves /health.
  • README documents pulling and running with a mounted config.toml.
  • deploy-server.yml is unchanged and still green.

Pointers

  • Dockerfile — two-stage build; note the port exposures, including the TURN relay range 50001-60000/udp, which the README run instructions must account for
  • .github/workflows/deploy-server.yml — existing build-push-action usage to mirror

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedMaintainers would welcome an outside contributor here

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions