Build an image in GitHub Actions and publish it to GHCR
Build your Dockerfile in GitHub Actions, publish the image to GHCR for the architecture of your cluster and deploy each new version.
Why build outside Tenkai
With a Git source, Tenkai builds on your cluster, with the CPU and memory of your servers, and the repository must be public today. Building in GitHub Actions moves the build to GitHub, and Tenkai pulls the image from the GitHub Container Registry, GHCR. This works for private code too.
You need a repository with a working Dockerfile, such as the one of the Node.js or PHP guide, and the CPU architecture of your cluster: x86-64 or arm64.
Add the workflow
Create .github/workflows/publish-image.yml:
name: Publish image
on:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v7
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=sha
- uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
Each push to main publishes the image as ghcr.io/<owner>/<repository>, tagged main, which moves to each build, and sha- followed by the short commit SHA. You create no token: packages: write lets the workflow's GITHUB_TOKEN publish.
Push the workflow and follow the run in the Actions tab. The image then appears under Packages on the repository page.
Build for the architecture of your cluster
Tenkai refuses an image without a variant for the CPU architecture of your servers. The workflow above builds for x86-64. For an arm64 cluster, change two lines:
runs-on: ubuntu-24.04-arm
platforms: linux/arm64
Building arm64 on an x86-64 runner works through emulation, but several times slower.
Let Tenkai pull the image
GitHub makes a new package private, even for a public repository. Either:
- Make the package public. Open the package, then Package settings, Change visibility and Public. Anyone can then pull it, so check that the image holds no secrets. A public package of an organization cannot become private again.
- Keep it private. Create a personal access token (classic) with only the
read:packagesscope, and add it as a GHCR credential in your account. GHCR does not accept fine-grained tokens. Pull a private GHCR image explains which account should own it.
Create the resource
- In the project, choose Add resource, then Application.
- Choose Web application and Container image as the build source.
- Enter the image reference with its moving tag, such as
ghcr.io/acme/hello:main. - For a private package, choose a GHCR credential that Can pull it.
- Create the resource.
Set the variables your application needs, then choose Deploy. Wait for an active release and open its default route.
Deploy a new version
Push to main, wait for the workflow to finish, then choose Deploy on the resource. A deployment started earlier deploys the previous image. To deploy from the workflow, call the deploy hook of the resource in a last step.
Each deployment records the digest that main pointed to, so a rollback brings back that exact image. To pin a resource to one build, use its digest as the image reference, such as ghcr.io/acme/hello@sha256:….
If the deployment fails
Read the message of the failed deployment on the resource's overview tab.
- The tag does not exist: check that the workflow succeeded and that the reference uses the lowercase name of the package.
- The image has no variant for the architecture of the server: build for it.
- Tenkai cannot pull the image: make the package public, or link a GHCR credential that can pull it from Image access in Configuration.
Troubleshooting lists the other source checks.