Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 54 additions & 5 deletions .github/workflows/publish-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,18 +86,67 @@ jobs:
docker push "${image}:latest"
fi

- name: Report pinned digest
# Docker Hub is the primary public distribution channel (anonymous pulls
# for deployments). Skipped when the DOCKERHUB_* secrets are not
# configured, so forks and the GHCR-only path keep working. With an org
# access token, DOCKERHUB_USERNAME is the ORG name — which is also the
# image namespace.
# continue-on-error so a Hub failure can't suppress the digest summary
# for the already-pushed GHCR image; the fail-gate step below still
# fails the run afterwards.
- name: Push to Docker Hub
id: dockerhub
continue-on-error: true
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
run: |
if [[ -z "${DOCKERHUB_USERNAME}" || -z "${DOCKERHUB_TOKEN}" ]]; then
echo "DOCKERHUB_* secrets not configured; skipping Docker Hub publish."
exit 0
fi
owner="${GITHUB_REPOSITORY_OWNER,,}"
ghcr_image="ghcr.io/${owner}/omnigraph-server"
hub_image="docker.io/${DOCKERHUB_USERNAME}/omnigraph-server"

echo "${DOCKERHUB_TOKEN}" \
| docker login docker.io --username "${DOCKERHUB_USERNAME}" --password-stdin

docker tag "${ghcr_image}:${RELEASE_TAG}" "${hub_image}:${RELEASE_TAG}"
docker push "${hub_image}:${RELEASE_TAG}"

# Same `latest` policy as GHCR: real tag pushes only, never backfills.
if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
docker tag "${ghcr_image}:${RELEASE_TAG}" "${hub_image}:latest"
docker push "${hub_image}:latest"
fi
Comment thread
aaltshuler marked this conversation as resolved.

- name: Report pinned digests
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
run: |
owner="${GITHUB_REPOSITORY_OWNER,,}"
image="ghcr.io/${owner}/omnigraph-server"
digest=$(docker inspect --format='{{index .RepoDigests 0}}' "${image}:${RELEASE_TAG}")
{
echo "## Container image published"
echo
echo '```'
echo "${image}:${RELEASE_TAG}"
echo "${digest}"
for image in "ghcr.io/${owner}/omnigraph-server" \
${DOCKERHUB_USERNAME:+"docker.io/${DOCKERHUB_USERNAME}/omnigraph-server"}; do
echo "${image}:${RELEASE_TAG}"
# RepoDigests may store Hub images with or without the
# docker.io/ prefix depending on the Docker version.
docker inspect --format='{{range .RepoDigests}}{{.}}{{"\n"}}{{end}}' \
"${image}:${RELEASE_TAG}" | grep -E "^(docker\.io/)?${image#docker.io/}@" || true
done
echo '```'
echo
echo "Pin deployments to the digest form."
} >> "$GITHUB_STEP_SUMMARY"

# The summary above always runs; a Docker Hub failure still fails the
# run here so operators notice.
- name: Fail if Docker Hub push failed
if: steps.dockerhub.outcome == 'failure'
run: |
echo "Docker Hub push failed (GHCR image was pushed; see summary)." >&2
exit 1
2 changes: 1 addition & 1 deletion docs/dev/ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
- **release-edge.yml**: on every push to main, retags `edge`, builds Linux x86_64 / Linux arm64 / macOS arm64 archives and Windows x86_64 zip + sha256, publishes a rolling prerelease, then smoke-tests the Windows PowerShell installer against `edge`.
- **release.yml**: on `v*` tags, builds the Linux x86_64 / Linux arm64 / macOS arm64 archives and Windows x86_64 zip release matrix, updates the Homebrew tap (`scripts/update-homebrew-formula.sh`) by pushing the regenerated formula to `ModernRelay/homebrew-tap`, and smoke-tests the Windows PowerShell installer against the tag.
- **package.yml**: manual ECR image build; emits two image tags per commit (`<sha>`, `<sha>-aws`) via CodeBuild.
- **publish-image.yml**: builds and pushes the public `omnigraph-server` container image to GHCR (`ghcr.io/modernrelay/omnigraph-server:<tag>`) on `v*` tag pushes, plus manual `workflow_dispatch` with an explicit existing `v*` tag to backfill an image for a past release. Compiles the binaries inside a `rust:1-bookworm` builder container to match the Dockerfile's bookworm-slim runtime glibc (host-built ubuntu binaries do not run there), builds with `--features omnigraph-server/aws`, and moves `latest` only on real tag pushes — never on backfill dispatches. Separate from release.yml so an image-publish failure cannot block the binary release / Homebrew chain.
- **publish-image.yml**: builds and pushes the public `omnigraph-server` container image to GHCR (`ghcr.io/modernrelay/omnigraph-server:<tag>`) and to Docker Hub (`docker.io/modernrelay/omnigraph-server:<tag>`, the primary anonymous-pull channel; skipped when the `DOCKERHUB_*` secrets are unset) on `v*` tag pushes, plus manual `workflow_dispatch` with an explicit existing `v*` tag to backfill an image for a past release. Compiles the binaries inside a `rust:1-bookworm` builder container to match the Dockerfile's bookworm-slim runtime glibc (host-built ubuntu binaries do not run there), builds with `--features omnigraph-server/aws`, and moves `latest` only on real tag pushes — never on backfill dispatches. Separate from release.yml so an image-publish failure cannot block the binary release / Homebrew chain.
5 changes: 3 additions & 2 deletions docs/user/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,12 @@ endpoint and credentials. CI exercises this path against containerized RustFS.

## Container Deployment

Pull the prebuilt public image (published to GHCR for every `v*` release by
Pull the prebuilt public image (published for every `v*` release by
`publish-image.yml`; built with the `aws` feature, linux/amd64):

```bash
docker pull ghcr.io/modernrelay/omnigraph-server:v0.8.1
docker pull modernrelay/omnigraph-server:v0.8.1 # Docker Hub
# or: docker pull ghcr.io/modernrelay/omnigraph-server:v0.8.1
```

Or build it yourself:
Expand Down