Docs · Registry
UpdatedPush images from GitHub Actions
Build in your pipeline and push to your workspace’s private registry with a robot account: a credential that can push to the repositories you name, and nothing else.
Before you start
Images live at registry.subnomic.com/<workspace>/<repository>:<tag>. The examples below use the workspace acme and the repository api.
Create the repository
A first push creates a repository on its own, but a robot can only be limited to a repository that already exists. So create it first: Registry → Repositories → New repository.
Create a robot account
Under Registry → Robots → New robot:
- Name — for example
github-ci. Its username becomesrobot$github-ci. - Repositories — pick
api, with pull and push. Leave delete off: a build has no reason to remove images. All repositories works too, but a credential that can push everywhere can overwrite everything. - Expiry — in days, or 0 for none. An expired robot cannot sign in.
The secret is shown once, with the username and a ready docker login line; only a hash of it is kept. In GitHub, add both under Settings → Secrets and variables → Actions, as SUBNOMIC_REGISTRY_USER and SUBNOMIC_REGISTRY_SECRET.
The workflow
Save this as .github/workflows/image.yml. It pushes every commit to main as its commit SHA, and every v* tag under its own name.
name: Image
on:
push:
branches: [main]
tags: ['v*']
permissions:
contents: read
jobs:
image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
registry: registry.subnomic.com
username: ${{ secrets.SUBNOMIC_REGISTRY_USER }}
password: ${{ secrets.SUBNOMIC_REGISTRY_SECRET }}
- uses: docker/build-push-action@v7
with:
push: true
tags: |
registry.subnomic.com/acme/api:${{ github.sha }}
registry.subnomic.com/acme/api:${{ github.ref_name }}
What happens on a push
- The secret buys a short-lived token. The login trades the robot’s secret for a registry token that lasts minutes; that token is what the push carries.
- Only new layers travel. Docker asks before it uploads each layer, and a layer the registry already stores is skipped.
- Every tagged push is scanned, in the background. A finding never blocks the push; it shows on the tag with the version that fixes it. See Image security.
- An immutable tag stays put. If the repository marks tags immutable, pushing different content to an existing tag is refused with
409 DENIED— another reason to tag by commit SHA.
Multi-architecture images
The registry takes OCI image indexes and Docker manifest lists, so one tag can carry several platforms. Add them to the build step:
- uses: docker/build-push-action@v7
with:
push: true
platforms: linux/amd64,linux/arm64
tags: registry.subnomic.com/acme/api:${{ github.sha }}
Building for a platform other than the runner’s needs emulation (QEMU) or a runner of that platform.
Pulling where you deploy
Give the deploying side a robot of its own, with pull only: a server that can pull cannot push a replacement.
echo "$SUBNOMIC_REGISTRY_SECRET" | docker login registry.subnomic.com -u 'robot$deployer' --password-stdin docker pull registry.subnomic.com/acme/api:<commit sha>
Single-quote the username in a shell. Unquoted, $deployer is read as a variable and the login sends robot.
Rotating and revoking
On the robot’s row you can disable it, rotate its secret or delete it. Each stops it signing in at once. A token it already holds keeps working until that token expires, minutes later, so a push already under way can finish.
When it fails
| You see | What it means |
|---|---|
docker login fails with 401 | The secret is wrong, rotated or deleted, or the robot is disabled or expired. |
| The push to another repository is refused | The robot is limited to the repositories it was given. Add the repository to it, or use a robot made for that one. |
403 DENIED, storage or repository quota exceeded | The workspace has reached a limit its operators set. Layers it already stores still go through. |
409 DENIED on a tag that exists | The tag is immutable. Push a new tag. |
Repositories, tags and retention are in Container registry. Deploying a static site from the same pipeline is in Deploy from GitHub Actions.