feat: add resolve-buildx-cache as a shared composite action
This commit is contained in:
@@ -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.
|
||||||
@@ -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 `<DOCKER_CACHE_SERVER>/<cache-image>: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=<nieistniejąca>` 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ł.
|
||||||
@@ -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"
|
||||||
Reference in New Issue
Block a user