ci: publish Docker images to GHCR alongside Docker Hub (#7569)

* ci: publish Docker images to GHCR alongside Docker Hub

Adds ghcr.io/ether/etherpad as a second publish target on release tags,
reusing the existing docker/metadata-action step so the same SemVer tags
(e.g. 2.6.1, 2.6, 2, latest) are pushed to both registries.

Motivation: downstream consumers (Helm charts in particular) hit Docker
Hub anonymous pull rate limits. GHCR has no such limits and the
workflow already runs with GITHUB_TOKEN, so this is additive with no
new secrets required.

Docker Hub remains the primary/canonical source; GHCR is a mirror.

Note: this only affects future release tags. The 2.6.1 tag already on
Docker Hub will need to be mirrored separately (e.g. via skopeo) if
downstream needs it on GHCR before the next release.

* address qodo review: scope packages:write to publish job, document GHCR

Two fixes from the qodo code review on #7569:

1. Overprivileged PR token (security). The original change set
   'packages: write' at workflow level, which meant pull_request runs
   (whose Test step executes PR-controlled code) also inherited push
   access to GHCR. Splits the workflow into two jobs:
     - build-test: runs on pull_request and push with contents:read
       only. Does the single-arch load+test as before.
     - publish: needs build-test, runs only on push with
       packages:write. Does the multi-arch build-and-push, Docker Hub
       description update, and ether-charts bump.
   Docker Hub login is also now gated by job-level 'if' (same effect
   as the previous step-level 'if').

2. Docs miss GHCR option. Updates doc/docker.md and README.md to
   document the GHCR mirror alongside Docker Hub with equivalent pull
   examples, so downstream users discovering via docs can choose the
   mirror to avoid Docker Hub rate limits.
This commit is contained in:
John McLear 2026-04-20 10:19:11 +01:00 committed by GitHub
parent 3ccf0b1c04
commit c2e69388d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 52 additions and 19 deletions

View File

@ -12,12 +12,15 @@ on:
- 'v?[0-9]+.[0-9]+.[0-9]+'
env:
TEST_TAG: etherpad/etherpad:test
permissions:
contents: read
jobs:
docker:
build-test:
runs-on: ubuntu-latest
permissions:
contents: read
env:
PNPM_HOME: ~/.pnpm-store
steps:
@ -26,11 +29,6 @@ jobs:
uses: actions/checkout@v6
with:
path: etherpad
-
name: Set up QEMU
if: github.event_name == 'push'
uses: docker/setup-qemu-action@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
@ -78,13 +76,34 @@ jobs:
done
(cd src && gnpm run test-container)
git clean -dxf .
publish:
needs: build-test
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
-
name: Check out
uses: actions/checkout@v6
with:
path: etherpad
-
name: Set up QEMU
uses: docker/setup-qemu-action@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
-
name: Docker meta
if: github.event_name == 'push'
id: meta
uses: docker/metadata-action@v6
with:
images: etherpad/etherpad
images: |
etherpad/etherpad
ghcr.io/ether/etherpad
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
@ -92,15 +111,20 @@ jobs:
type=semver,pattern={{major}}
-
name: Log in to Docker Hub
if: github.event_name == 'push'
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Build and push
id: build-docker
if: github.event_name == 'push'
uses: docker/build-push-action@v7
with:
context: ./etherpad
@ -109,6 +133,7 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
- name: Update repo description
uses: peter-evans/dockerhub-description@v5
if: github.ref == 'refs/heads/master'
@ -118,8 +143,8 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: etherpad/etherpad
enable-url-completion: true
- name: Check out
if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
- name: Check out ether-charts
if: github.ref == 'refs/heads/develop'
uses: actions/checkout@v6
with:
path: ether-charts

View File

@ -103,11 +103,13 @@ $env:ETHERPAD_RUN=1; irm https://raw.githubusercontent.com/ether/etherpad/master
### Docker-Compose
The official image is published to both Docker Hub (`etherpad/etherpad`) and GitHub Container Registry (`ghcr.io/ether/etherpad`) with identical tags. Use whichever suits your environment; GHCR avoids Docker Hub's anonymous pull rate limits.
```yaml
services:
app:
user: "0:0"
image: etherpad/etherpad:latest
image: etherpad/etherpad:latest # or: ghcr.io/ether/etherpad:latest
tty: true
stdin_open: true
volumes:

View File

@ -1,15 +1,21 @@
# Docker
The official Docker image is available on https://hub.docker.com/r/etherpad/etherpad.
The official Docker image is published to two registries with identical tags:
## Downloading from Docker Hub
If you are ok downloading a [prebuilt image from Docker Hub](https://hub.docker.com/r/etherpad/etherpad), these are the commands:
- Docker Hub (canonical): https://hub.docker.com/r/etherpad/etherpad
- GitHub Container Registry (mirror): https://github.com/ether/etherpad/pkgs/container/etherpad
The GHCR mirror is useful if you are hitting Docker Hub anonymous pull rate limits (for example on Kubernetes clusters).
## Downloading a prebuilt image
```bash
# gets the latest published version
# from Docker Hub
docker pull etherpad/etherpad
# gets a specific version
docker pull etherpad/etherpad:2.6.1
# from GHCR (same image, same tags)
docker pull ghcr.io/ether/etherpad
docker pull ghcr.io/ether/etherpad:2.6.1
```
## Build a personalized container