Publish runner image to Gitea Container Registry
Some checks failed
Test blackout notifier / test (push) Failing after 0s
Hourly blackout check / check (push) Failing after 0s
Build runner image / build (push) Failing after 2s

This commit is contained in:
Meghdad
2026-07-17 20:22:52 +03:30
parent c23e8b98f7
commit 308ed80ff4
4 changed files with 146 additions and 32 deletions

View File

@@ -0,0 +1,73 @@
name: Build runner image
on:
push:
branches:
- main
paths:
- runner-image/**
- .gitea/workflows/build-runner-image.yml
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
container:
image: node:20-bookworm
volumes:
- /var/run/docker.sock:/var/run/docker.sock
steps:
- name: Check out repository
uses: https://gitea.com/actions/checkout@v4
- name: Install Docker client
run: |
set -eu
for attempt in 1 2 3; do
if apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
--no-install-recommends docker.io; then
break
fi
if [ "$attempt" -eq 3 ]; then
echo "Unable to install the Docker client after 3 attempts"
exit 1
fi
sleep "$((attempt * 5))"
done
rm -rf /var/lib/apt/lists/*
docker version --format 'Docker client {{.Client.Version}}, server {{.Server.Version}}'
- name: Build, verify, and publish image
env:
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
run: |
set -eu
registry="mahgit.ir"
image="$registry/meghdadfadaee/daily-blackout-check-runner"
revision="$(git rev-parse --short=12 HEAD)"
candidate="$image:$revision"
cleanup() {
docker logout "$registry" >/dev/null 2>&1 || true
}
trap cleanup EXIT
printf '%s' "$REGISTRY_TOKEN" | docker login "$registry" \
--username "$REGISTRY_USERNAME" \
--password-stdin
docker build \
--pull \
--label "org.opencontainers.image.revision=$revision" \
--label "org.opencontainers.image.source=https://mahgit.ir/MeghdadFadaee/daily-blackout-check" \
--tag "$candidate" \
runner-image
docker run --rm "$candidate" python -c "import dotenv, jdatetime, requests"
docker run --rm "$candidate" pytest --version
docker run --rm "$candidate" ruff --version
docker push "$candidate"
docker tag "$candidate" "$image:latest"
docker push "$image:latest"

View File

@@ -9,7 +9,10 @@ jobs:
check: check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: daily-blackout-check-runner:latest image: mahgit.ir/meghdadfadaee/daily-blackout-check-runner:latest
credentials:
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_TOKEN }}
env: env:
PYTHONPATH: src PYTHONPATH: src
steps: steps:

View File

@@ -11,7 +11,10 @@ jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: daily-blackout-check-runner:latest image: mahgit.ir/meghdadfadaee/daily-blackout-check-runner:latest
credentials:
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_TOKEN }}
env: env:
PYTHONPATH: src PYTHONPATH: src
steps: steps:

View File

@@ -62,37 +62,77 @@ Shell and Gitea-provided variables take precedence over `.env`.
## Gitea deployment ## Gitea deployment
This repository targets Gitea 1.25.x and a Docker-based runner advertising the This repository targets Gitea 1.25.x and a Docker-based runner advertising the
`ubuntu-latest` label. Both workflows run inside the locally built `ubuntu-latest` label. The test and hourly workflows pull this private image from
`daily-blackout-check-runner:latest` image. It contains Node for the checkout the Gitea Container Registry:
action plus Python, Git, timezone data, application dependencies, pytest, and
Ruff. Scheduled jobs therefore do not install Python or download Python packages.
Build the image on the Docker host used by `act_runner`: ```text
mahgit.ir/meghdadfadaee/daily-blackout-check-runner:latest
```sh
cd /path/to/daily-blackout-check
docker build \
--tag daily-blackout-check-runner:latest \
runner-image
docker image inspect daily-blackout-check-runner:latest >/dev/null
``` ```
Only `runner-image/` is sent as the Docker build context, so local secrets and It contains Node for the checkout action plus Python, Git, timezone data,
outage state never enter the build context or image. application dependencies, pytest, and Ruff. Scheduled jobs therefore do not
install Python or download Python packages.
The image is local rather than registry-hosted, matching the deployment pattern ### Registry credentials
used by `mahak-api-docs`. Build it on every runner host that can claim this job.
Rebuild it whenever `runner-image/Dockerfile`, `runner-image/requirements.lock`, Create a Gitea personal access token for `MeghdadFadaee` with package permission
or dependency declarations in `pyproject.toml` change. The image build requires set to **Read and Write**. Add these repository Actions secrets:
Docker Hub and PyPI access; normal workflow runs only need the Gitea instance,
| Secret | Value |
| --- | --- |
| `REGISTRY_USERNAME` | Gitea username that owns the package |
| `REGISTRY_TOKEN` | Personal access token with package Read and Write permission |
| `BARGHEMAN_TOKEN` | SAAPA bearer token |
| `EITAAYAR_TOKEN` | EitaaYar bot token |
| `CHAT_ID` | Destination chat ID |
| `BILL_IDS` | Comma-separated bill IDs |
The registry token is used to publish the image and as `container.credentials`
when Gitea Runner pulls the private image before starting a job.
### Runner configuration
The image-build workflow needs access to the Docker daemon used by `act_runner`.
In the runner's generated `config.yaml`, update the existing `container` section:
```yaml
container:
force_pull: true
valid_volumes:
- /var/run/docker.sock
```
The runner container itself must already mount the same socket, as in the normal
Docker-based `act_runner` setup. Restart the runner after changing its config.
Docker socket access is equivalent to control of the Docker host. Use a trusted,
preferably repository-level runner. The build workflow runs only for changes on
`main` under `runner-image/` or its own workflow file; it never runs for pull
requests.
### Image publishing flow
The **Build runner image** workflow:
1. Starts in `node:20-bookworm` and installs the Docker client.
2. Builds using only `runner-image/` as context, so `.env` and outage state are
never included.
3. Runs import, pytest, and Ruff smoke checks inside the candidate image.
4. Pushes an immutable tag using the first 12 characters of the Git commit.
5. Updates `latest` only after the candidate passes verification.
It runs automatically when `runner-image/**` changes on `main` and can also be
started manually. Image builds require Debian mirrors, Docker Hub, PyPI, Gitea,
and access to the Docker socket. Normal test and hourly runs only need Gitea,
`gitea.com`, SAAPA, and EitaaYar. `gitea.com`, SAAPA, and EitaaYar.
1. Build `daily-blackout-check-runner:latest` on the runner's Docker host. Deployment order:
2. Enable Actions in the repository settings.
3. Confirm an online Docker runner advertises `ubuntu-latest`. 1. Enable Packages and Actions for the repository/owner.
4. Add these repository Actions secrets: 2. Configure the runner socket permission and restart it.
`BARGHEMAN_TOKEN`, `EITAAYAR_TOKEN`, `CHAT_ID`, and `BILL_IDS`. 3. Add all repository Actions secrets listed above.
5. Run the test workflow manually. 4. Run **Build runner image** manually and confirm both registry tags appear.
5. Run **Test blackout notifier** manually.
6. Run **Hourly blackout check** manually once and inspect the notification and 6. Run **Hourly blackout check** manually once and inspect the notification and
resulting state commit. resulting state commit.
7. Leave the `@hourly` schedule enabled. 7. Leave the `@hourly` schedule enabled.
@@ -104,11 +144,6 @@ Its checkout credential must retain the default ability to push to the current
repository. Scheduled jobs should not be manually overlapped; in the rare event repository. Scheduled jobs should not be manually overlapped; in the rare event
of a push race, the job fails and unsaved notices may be repeated on the next run. of a push race, the job fails and unsaved notices may be repeated on the next run.
If a workflow tries to pull the local image instead of using it, ensure the image
exists in the same Docker daemon used by `act_runner` and set
`container.force_pull: false` in the runner's generated `config.yaml`, then
restart the runner.
## Development ## Development
```sh ```sh