From 4dee87df56fc4e33d11605cf96a7a5f3d511e72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Cierzniakowski?= Date: Sun, 9 Aug 2026 15:09:25 +0200 Subject: [PATCH] feat: add resolve-buildx-cache as a shared composite action --- README.md | 67 +++++++++++++++++++++++++++++++ resolve-buildx-cache/README.md | 68 ++++++++++++++++++++++++++++++++ resolve-buildx-cache/action.yaml | 45 +++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 README.md create mode 100644 resolve-buildx-cache/README.md create mode 100644 resolve-buildx-cache/action.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..6100795 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# gitea-runner/actions + +Współdzielone composite actions do jobów Gitea Actions na `git.cierzniak.it`. + +Jedna akcja = jeden podkatalog. Repo może zostać prywatne — runner uwierzytelnia się +przy pobieraniu akcji, patrz „Dostęp" niżej. + +## Akcje + +| Akcja | Do czego | +| --- | --- | +| [`resolve-buildx-cache`](resolve-buildx-cache/) | `DOCKER_CACHE_*` z runnera → `driver-opts` i refy cache'a dla buildx | + +## Jak używać + +Pełny URL w `uses:` i **tag**, nigdy `@main`: + +```yaml + - name: Resolve buildx cache settings + id: cache + uses: https://git.cierzniak.it/gitea-runner/actions/resolve-buildx-cache@v1 + with: + cache-image: ${{ github.repository }}/app +``` + +Pełny URL jest konieczny, bo `DEFAULT_ACTIONS_URL` tej instancji wskazuje na GitHuba — +`uses: gitea-runner/actions/...@v1` poleciałoby tam i padło. Przestawianie tego ustawienia +na `self` jest odradzane przez dokumentację Gitei, bo wymusiłoby mirrorowanie lokalnie także +`actions/checkout` i całej reszty. + +Tag zamiast gałęzi, ponieważ jedno repo obsługuje wiele pipeline'ów: push do `main` +przy `@main` zmieniłby je wszystkie naraz. + +## Dostęp + +Organizacja `gitea-runner` jest `limited`, więc anonimowy `git clone` tego repo nie działa. +To **nie** jest przeszkoda: `act_runner` pobiera akcje z tokenem +(`GoGitActionCache.Fetch` → `http.BasicAuth{Username: "token", Password: token}`). + +Żeby ten token był autoryzowany, każde repo-konsument musi mieć tu nadany dostęp: + +> **Settings → Actions → General → collaborative owners** — dodaj *właściciela* +> (organizację albo użytkownika), nie pojedyncze repo. + +Bez tego job pada przy rozwiązywaniu `uses:`, jeszcze przed pierwszym krokiem akcji. +Ustawienia nie ma w REST API — trzeba wyklikać. + +Aktualnie nadane: `cierzniak-it`. + +Kandydaci do dodania, gdy akcja pojedzie szerzej (repo z buildxem w CI): +`leczenieran` (`wizytowka`, `elektroniczna-dokumentacja-medyczna`), +`welding-technology-review` (`witryna-internetowa`), `ekoinbud` (`production-system`). + +## Wersjonowanie + +`vN` to **ruchomy** tag majora — poprawki i wstecznie zgodne zmiany przesuwają go na nowy +commit, konsumenci nie ruszają swoich workflow. Zmiana łamiąca kontrakt (usunięty input, +zmieniona semantyka outputu) dostaje `vN+1`, a stary tag zostaje tam, gdzie stał. + +Po przesunięciu tagu: `git tag -f vN && git push -f origin vN`. Runner rozwiązuje ref przy +każdym jobie, więc konsumenci łapią zmianę bez żadnej akcji po swojej stronie — to samo +zdanie czyta się też jako ostrzeżenie o zasięgu rażenia. + +## Powiązane repo + +- [`gitea-runner/images`](https://git.cierzniak.it/gitea-runner/images) — obrazy bazowe + jobów, ADR-y i przykłady workflow. diff --git a/resolve-buildx-cache/README.md b/resolve-buildx-cache/README.md new file mode 100644 index 0000000..5b84cbd --- /dev/null +++ b/resolve-buildx-cache/README.md @@ -0,0 +1,68 @@ +# resolve-buildx-cache + +Zamienia zmienne `DOCKER_CACHE_*` wystawiane przez runnera na opcje buildx. + +```yaml + - name: Resolve buildx cache settings + id: cache + uses: https://git.cierzniak.it/gitea-runner/actions/resolve-buildx-cache@v1 + with: + cache-image: ${{ github.repository }}/app + + - uses: docker/setup-buildx-action@v4 + with: + driver-opts: ${{ steps.cache.outputs.driver-opts }} + + - uses: docker/build-push-action@v7 + with: + cache-from: ${{ steps.cache.outputs.cache-from }} + cache-to: ${{ steps.cache.outputs.cache-to }} +``` + +## Wejście i wyjście + +| Input | Wymagany | Co to | +| --- | --- | --- | +| `cache-image` | tak | Ścieżka obrazu cache'a bez hosta rejestru, np. `org/repo/app`. Ref powstaje jako `/:cache` | + +| Output | Do czego | +| --- | --- | +| `driver-opts` | `driver-opts` dla `docker/setup-buildx-action` | +| `cache-from` | `cache-from` dla `docker/build-push-action` | +| `cache-to` | `cache-to` dla `docker/build-push-action` | + +Każdy job budujący osobny obraz podaje własny `cache-image` — inaczej cztery buildy +nadpisywałyby sobie jeden wpis w rejestrze. + +## Zmienne runnera + +Czytane jako zwykłe env joba z `runner.envs` w `config.yaml` runnera, **nie** przez kontekst +`vars.*` — ten widzi wyłącznie zmienne zdefiniowane po stronie Gitei. Runnery czytają +`config.yaml` przy starcie, więc po zmianie trzeba je zrestartować. + +| Zmienna | Znaczenie | +| --- | --- | +| `DOCKER_CACHE_TYPE` | typ cache'a buildx, w praktyce `registry` | +| `DOCKER_CACHE_SERVER` | host rejestru cache'a, np. `registry:5000` | +| `DOCKER_CACHE_NETWORK` | sieć Compose, do której trzeba podpiąć buildkita, żeby zobaczył rejestr | + +## Dlaczego tak + +**Puste `DOCKER_CACHE_TYPE`/`DOCKER_CACHE_SERVER` degradują joba do buildu bez cache'a** +(`::warning::` w logu), zamiast go wywalać. Cache jest optymalizacją; brak konfiguracji na +nowej puli runnerów nie ma prawa zatrzymać wdrożenia. + +**`DOCKER_CACHE_NETWORK` nie jest wpisany na sztywno.** Buildkit startuje jako osobny +kontener poza siecią stacku runnerów, więc przy rejestrze stojącym w tej sieci trzeba go +podpiąć jawnie. Ale przy flotach w LXC, gdzie rejestr ma własne IP, nie ma do czego się +podpinać, a `network=` wywala joba twardo. Dlatego pusta wartość oznacza +„nie przekazuj `driver-opts` wcale" — repo nie zna topologii runnera i nie ma czego zgadywać. + +**`registry.insecure=true` w refach**, bo rejestr cache'a chodzi po HTTP bez TLS-a. +Zastępuje to wcześniejszy `buildkitd-config-inline` z blokiem `[registry."..."]`, który przy +pustej zmiennej generował `[registry.""]` — blok składniowo zepsuty, a nie błąd. + +**Wartości jadą z runnera, nie z `vars.*` Gitei**, bo każda pula ma własny rejestr cache'a +i wskazuje na siebie. Gdy siedziały jako zmienne organizacji, po przeniesieniu na runnery +`vars.DOCKER_CACHE_*` rozwiązywało się do pustego stringa — build leciał na zielono bez +cache'a i nikt tego nie zauważył. diff --git a/resolve-buildx-cache/action.yaml b/resolve-buildx-cache/action.yaml new file mode 100644 index 0000000..84c64c7 --- /dev/null +++ b/resolve-buildx-cache/action.yaml @@ -0,0 +1,45 @@ +name: Resolve buildx cache settings +description: >- + Turns the DOCKER_CACHE_* variables exported by the runner into buildx driver options and + cache refs. Missing variables degrade the job to a build without cache instead of failing it. + +inputs: + cache-image: + description: Cache image path without the registry host (e.g. "org/repo/app"). + required: true + +outputs: + driver-opts: + description: driver-opts for docker/setup-buildx-action; empty when the cache registry needs no network pinning. + value: ${{ steps.resolve.outputs.driver-opts }} + cache-from: + description: cache-from ref for docker/build-push-action; empty disables cache reads. + value: ${{ steps.resolve.outputs.cache-from }} + cache-to: + description: cache-to ref for docker/build-push-action; empty disables cache writes. + value: ${{ steps.resolve.outputs.cache-to }} + +runs: + using: composite + steps: + - id: resolve + shell: bash + env: + CACHE_IMAGE: ${{ inputs.cache-image }} + run: | + if [ -n "${DOCKER_CACHE_NETWORK}" ]; then + echo "driver-opts=network=${DOCKER_CACHE_NETWORK}" >> "$GITHUB_OUTPUT" + else + echo "driver-opts=" >> "$GITHUB_OUTPUT" + fi + + if [ -z "${DOCKER_CACHE_TYPE}" ] || [ -z "${DOCKER_CACHE_SERVER}" ]; then + echo "::warning::DOCKER_CACHE_* not set on the runner - building without cache" + echo "cache-from=" >> "$GITHUB_OUTPUT" + echo "cache-to=" >> "$GITHUB_OUTPUT" + exit 0 + fi + + ref="${DOCKER_CACHE_SERVER}/${CACHE_IMAGE}:cache" + echo "cache-from=type=${DOCKER_CACHE_TYPE},ref=${ref},registry.insecure=true" >> "$GITHUB_OUTPUT" + echo "cache-to=type=${DOCKER_CACHE_TYPE},ref=${ref},registry.insecure=true,mode=max" >> "$GITHUB_OUTPUT"