9.6 KiB
Using the Clang 22 + Vulkan Gitea Actions CI Image
This guide explains how to build, publish, and use the prepared Docker image for Gitea Actions.
The prepared files are:
ci/Dockerfile
ci/README.md
ci/USE_CI_IMAGE.md
.dockerignore
.gitea/workflows/build-ci-image.yml
.gitea/workflows/build.yml
The image extends:
catthehacker/ubuntu:act-latest
It includes:
- Clang/LLVM 22
clang-format-22clang-tidy-22lld-22lldb-22- Meson
- Ninja
- Python 3 / pip / venv
- Vulkan development packages/tools
- Mesa Vulkan software/runtime drivers
build-essentialpkg-config- Git
- Gitea/act-compatible tooling inherited from the base image
1. Decide your image name
Pick a container image path in your Gitea registry.
Example Gitea host:
git.neosisyphus.com
Organization:
evol3d
Image path:
git.neosisyphus.com/evol3d/evol-testbed
The pushed tag will be:
git.neosisyphus.com/evol3d/evol-testbed:latest
2. Commit the prepared files
From the repository root:
git add ci/Dockerfile ci/README.md ci/USE_CI_IMAGE.md .dockerignore .gitea/workflows/build-ci-image.yml .gitea/workflows/build.yml
git commit -m "Add reusable Clang 22 Vulkan CI image"
git push
3. Create a Gitea access token
In the Gitea web UI:
- Open your user menu.
- Go to Settings.
- Go to Applications.
- Create a new access token.
- Give it package/container registry write permissions.
Depending on your Gitea version, the permission may be named one of:
package
packages
write:package
write:packages
Copy the token. It will be used as the registry password.
4. Add Gitea Actions variables
In your repository:
- Go to Settings.
- Go to Actions.
- Go to Variables.
- Add these variables:
REGISTRY_HOST=git.neosisyphus.com
REGISTRY_IMAGE=git.neosisyphus.com/evol3d/evol-testbed
CI_IMAGE=git.neosisyphus.com/evol3d/evol-testbed
Use your actual values.
REGISTRY_HOST
Only the hostname:
git.neosisyphus.com
Do not include https://.
Correct:
git.neosisyphus.com
Wrong:
https://git.neosisyphus.com
REGISTRY_IMAGE
The full image path without a tag:
git.neosisyphus.com/evol3d/evol-testbed
CI_IMAGE
Usually the same as REGISTRY_IMAGE:
git.neosisyphus.com/evol3d/evol-testbed
This is used by the normal build workflow.
5. Add Gitea Actions secrets
In your repository:
- Go to Settings.
- Go to Actions.
- Go to Secrets.
- Add this required secret:
REGISTRY_PASSWORD
Example:
REGISTRY_PASSWORD=<your-gitea-access-token>
Use the token from step 3 for REGISTRY_PASSWORD.
Optional: add this secret if your registry username is different from the Gitea Actions actor:
REGISTRY_USERNAME=myusername
If REGISTRY_USERNAME is not set, the workflow uses $GITHUB_ACTOR.
6. Check the image build workflow
The image build workflow is:
.gitea/workflows/build-ci-image.yml
It logs into your registry, builds the image, and pushes this tag:
latest
The important commands are:
- name: Build CI image
run: |
docker build \
--build-arg BASE_IMAGE=catthehacker/ubuntu:act-latest \
--build-arg LLVM_VERSION=22 \
--build-arg MESON_VERSION=latest \
-t "${{ vars.REGISTRY_IMAGE }}:latest" \
-f ci/Dockerfile .
- name: Push CI image
run: |
docker push "${{ vars.REGISTRY_IMAGE }}:latest"
7. Make sure your runner can build Docker images
The image-building workflow needs Docker.
On the runner host, check:
docker version
If that works, the host has Docker.
Your Gitea runner still needs permission to access Docker.
Option A: act_runner runs directly on the host
If your runner runs directly on the machine, make sure the runner user can use Docker.
Check the runner user, then add it to the Docker group if needed:
sudo usermod -aG docker <runner-user>
sudo systemctl restart act_runner
Test as that user:
docker ps
Option B: act_runner runs inside Docker
If act_runner itself runs inside a container, it needs the host Docker socket mounted:
-v /var/run/docker.sock:/var/run/docker.sock
Example:
docker run -d \
--name gitea-act-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /opt/act-runner/config.yaml:/config.yaml \
-v /opt/act-runner/data:/data \
gitea/act_runner:latest
Without the socket mount, the workflow cannot run docker build.
8. Run the image build workflow
There are two ways.
Method 1: push changes
The workflow triggers when these files change:
ci/Dockerfile
.dockerignore
.gitea/workflows/build-ci-image.yml
So this is enough:
git push
Method 2: manual workflow dispatch
If your Gitea version supports workflow_dispatch:
- Go to your repository.
- Open Actions.
- Select build-ci-image.
- Click Run workflow.
9. Confirm the image was pushed
In Gitea:
- Open the repository or organization.
- Go to Packages.
- Look for:
evol-testbed
Confirm this tag exists:
latest
10. Use the image in your normal build workflow
The prepared normal workflow is:
.gitea/workflows/build.yml
It uses:
container:
image: ${{ vars.CI_IMAGE }}:latest
If you set:
CI_IMAGE=git.neosisyphus.com/evol3d/evol-testbed
then the workflow uses:
git.neosisyphus.com/evol3d/evol-testbed:latest
The key workflow shape is:
name: build
on:
push:
pull_request:
jobs:
linux:
runs-on: ubuntu-latest
container:
image: ${{ vars.CI_IMAGE }}:latest
steps:
- uses: actions/checkout@v4
- name: Check CI toolchain
run: |
clang --version
clang++ --version
meson --version
ninja --version
python3 --version
vulkaninfo --summary || true
- name: Configure
run: |
meson setup build
- name: Build
run: |
meson compile -C build
Commit and push:
git add .gitea/workflows/build.yml
git commit -m "Use Clang 22 Vulkan CI image"
git push
11. If vars.CI_IMAGE does not work in container.image
Some Gitea/act versions may not expand variables in container.image.
If the build fails because the image name is invalid, replace this:
container:
image: ${{ vars.CI_IMAGE }}:latest
with the literal image name:
container:
image: git.neosisyphus.com/evol3d/evol-testbed:latest
Then commit and push:
git add .gitea/workflows/build.yml
git commit -m "Use literal CI image path"
git push
12. If the image is private
Your runner must be able to pull it.
Log in on the runner host:
docker login git.neosisyphus.com
Use your Gitea username and token.
If act_runner runs as a system service, log in as the same user that runs act_runner, or configure Docker credentials for that user.
Then restart the runner:
sudo systemctl restart act_runner
If your runner itself is Dockerized, make sure Docker credentials are available to the runner setup.
13. Test the image manually on the runner
On the runner host:
docker pull git.neosisyphus.com/evol3d/evol-testbed:latest
Run it:
docker run --rm -it git.neosisyphus.com/evol3d/evol-testbed:latest bash
Inside the container:
clang --version
clang++ --version
meson --version
ninja --version
python3 --version
vulkaninfo --summary
Expected results:
clangshould be version 22.mesonshould print a version.ninjashould print a version.vulkaninfo --summaryshould usually find Mesa's software Vulkan driver. It may still fail on unusual container/runner setups; that is okay for compile-only CI as long as Vulkan headers/tools are installed.
Exit:
exit
14. Use it in other projects
Once the image exists, any project can use it:
name: build
on:
push:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
container:
image: git.neosisyphus.com/evol3d/evol-testbed:latest
steps:
- uses: actions/checkout@v4
- run: |
meson setup build
meson compile -C build
No more installing LLVM/Vulkan/Meson every CI run.
15. Updating the image later
Edit:
ci/Dockerfile
Then:
git add ci/Dockerfile
git commit -m "Update CI image"
git push
The image workflow will rebuild and push:
latest
Your normal builds will use the updated image next time they run.
16. Recommended: version image tags
Instead of only using:
latest
consider immutable tags:
v1
v2
v2026-05
Example build command tag:
-t "${{ vars.REGISTRY_IMAGE }}:v1"
Then use:
container:
image: git.neosisyphus.com/evol3d/evol-testbed:v1
This avoids surprise breakage when latest changes.
17. Quick checklist
1. Commit ci/Dockerfile and workflows.
2. Create Gitea token with package/container write access.
3. Registry/image values are already hardcoded in the workflow.
4. Add Actions secrets:
- REGISTRY_PASSWORD
- REGISTRY_USERNAME only if needed
5. Make sure the runner can run docker build.
6. Run build-ci-image workflow.
7. Confirm image appears in Gitea Packages.
8. Use image in .gitea/workflows/build.yml.
9. Push normal project code.
10. Build should run inside the prebuilt Clang/Vulkan image.
The most important final workflow line is:
container:
image: git.neosisyphus.com/evol3d/evol-testbed:latest