build: imaget hentes fra vores egen Gitea, og runen peger derind
GitHub er utilgængeligt i ti dage. Koden ligger allerede begge steder; det, der manglede, var imaget og et sted at bygge det. **Imaget ligger i Gitea nu**, begge arkitekturer. Kopieret med `docker buildx imagetools create`, som flytter hele manifest-indekset mellem to registre uden at hente lagene ned — en `docker pull` på denne maskine ville have hentet arm64 og efterladt serveren uden en amd64 at køre. **Og det kan hentes uden legitimation, mens repoet bliver ved med at være privat.** Det var ikke givet: panelets `PullImage` sætter aldrig `RegistryAuth`, så et privat register er udelukket, og Gitea gør normalt en container-pakke privat sammen med det repo, den hører til. Men en pakke bindes kun til et repo, når den skubbes med et repo-link — og denne er ikke, så dens synlighed følger brugeren `kw`, som er offentlig. Bevist frem for antaget: `docker --config /tmp/tom pull` hentede den med samme digest som GHCR havde. En bar `curl` mod `/v2/…/manifests/…` svarer 401 også for et læsbart image, fordi registret uddeler et anonymt token først — så den er ikke prøven, og den kostede en runde at gennemskue. **Runen er bumpet til version 5.** Ikke fordi felterne ændrede sig, men fordi en rune ikke opdaterer sig selv: panelet skriver rune-rækken fra en UI-handling, så ændringen kræver **Runes → verdande → Update**, og katalog-listen caches ti minutter. **Et Actions-workflow til Gitea** ligger i `.gitea/workflows/`. Sin egen fil frem for en delt: `secrets.GITHUB_TOKEN` findes ikke der, registret er et andet, og der er ingen Releases-side at skrive til. En delt fil ville være fire betingede led, der hver kun gælder ét af de to steder. Den laver ingen release, fordi opdateringsnotitsen i appen læser GitHubs — skal den flyttes med, er det `internal/update`, der skal have en ny adresse. **Det virker ikke endnu:** der er ingen runner registreret på Gitea. Indtil der er, bygges og skubbes imaget i hånden herfra. Dokumentationen og landingssiden siger den nye adresse. Rune-siden er skrevet om, hvor den fortalte om GHCR-pakkeindstillinger, og siger nu, hvordan man prøver efter på den måde, der faktisk svarer på spørgsmålet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8d5dd1f1c3
commit
20b8c12b4a
@@ -0,0 +1,67 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
# Samme udløser som GitHub-workflowet: et semver-tag, og ikke andet.
|
||||||
|
#
|
||||||
|
# Gitea Actions læser samme format som GitHub Actions og kan bruge handlinger
|
||||||
|
# derfra, men det er *ikke* det samme sted. Filen ligger derfor for sig i
|
||||||
|
# `.gitea/workflows/` frem for at være delt: `secrets.GITHUB_TOKEN` findes ikke
|
||||||
|
# her, registret er et andet, og der er ingen Releases-side at skrive til. En delt
|
||||||
|
# fil ville være fire betingede led, der hver kun gælder ét af de to steder.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ["v[0-9]+.[0-9]+.[0-9]+*"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
image:
|
||||||
|
name: Build and publish image
|
||||||
|
# `ubuntu-latest` betyder her det, runneren er sat op til at kalde det.
|
||||||
|
# Registreres runneren med en anden etiket, skal denne linje følge med.
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: docker/setup-qemu-action@v3
|
||||||
|
- uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
# `GITEA_TOKEN` er automatisk til stede i et Actions-job og har lov at
|
||||||
|
# skrive pakker for den, der ejer repoet. Ingen hemmelighed at sætte op.
|
||||||
|
- uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: gitea.nolimit.dk
|
||||||
|
username: ${{ gitea.actor }}
|
||||||
|
password: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
|
- id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: gitea.nolimit.dk/${{ gitea.repository }}
|
||||||
|
# v1.4.2 udgiver 1.4.2, 1.4 og 1 — så en rune, der er bundet til :1, får
|
||||||
|
# rettelser uden nogensinde at krydse et hovedversionsskifte.
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,pattern={{major}}
|
||||||
|
type=raw,value=latest
|
||||||
|
|
||||||
|
# arm64 er ikke valgfrit: et hjemmelab er lige så tit en Raspberry Pi eller
|
||||||
|
# en Apple silicon-VM som en x86-kasse.
|
||||||
|
- uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ gitea.ref_name }}
|
||||||
|
# Ingen `cache-from: type=gha`. Den cache er GitHubs tjeneste, og den
|
||||||
|
# findes ikke her — bedt om den, fejler trinnet på noget, der ikke har
|
||||||
|
# med bygningen at gøre. Uden cache tager en kold bygning nogle minutter
|
||||||
|
# længere, og det er prisen, indtil runneren har en cache af sin egen.
|
||||||
|
# Ingen Release oprettes.
|
||||||
|
#
|
||||||
|
# GitHub-workflowet laver en Release, fordi opdateringsnotitsen i appen læser
|
||||||
|
# `releases/latest` derfra. Gitea har sit eget Releases-begreb, men notitsen
|
||||||
|
# peger på GitHub — så en release her ville ingen læse. Skal notitsen flyttes
|
||||||
|
# med, er det `internal/update`, der skal have en ny adresse, og det er en
|
||||||
|
# ændring for sig.
|
||||||
@@ -171,7 +171,7 @@ docker run -d --name verdande \
|
|||||||
-p 8080:8080 \
|
-p 8080:8080 \
|
||||||
-v verdande-data:/data \
|
-v verdande-data:/data \
|
||||||
-e VERDANDE_BASE_URL=https://todo.example.dk \
|
-e VERDANDE_BASE_URL=https://todo.example.dk \
|
||||||
ghcr.io/kristianwind/verdande:latest
|
gitea.nolimit.dk/kw/verdande:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### From source
|
### From source
|
||||||
|
|||||||
+1
-1
@@ -72,7 +72,7 @@ docker run -d --name verdande \
|
|||||||
-p 8080:8080 \
|
-p 8080:8080 \
|
||||||
-v verdande-data:/data \
|
-v verdande-data:/data \
|
||||||
-e VERDANDE_BASE_URL=https://todo.example.dk \
|
-e VERDANDE_BASE_URL=https://todo.example.dk \
|
||||||
ghcr.io/kristianwind/verdande:latest
|
gitea.nolimit.dk/kw/verdande:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Open the address, create the first account — that account is the administrator.
|
Open the address, create the first account — that account is the administrator.
|
||||||
|
|||||||
+19
-8
@@ -7,14 +7,14 @@ verdande ships with a Rune manifest for
|
|||||||
|
|
||||||
```
|
```
|
||||||
create container: Error response from daemon:
|
create container: Error response from daemon:
|
||||||
No such image: ghcr.io/kristianwind/verdande:latest
|
No such image: gitea.nolimit.dk/kw/verdande:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
This message is a liar. It does not mean the tag is missing from the registry —
|
This message is a liar. It does not mean the tag is missing from the registry —
|
||||||
it means the image is not on the host, and the panel's attempt to fetch it failed
|
it means the image is not on the host, and the panel's attempt to fetch it failed
|
||||||
without saying so.
|
without saying so.
|
||||||
|
|
||||||
The usual cause is a **private** GHCR package. Yggdrasil pulls anonymously: its
|
The usual cause is a **private** package. Yggdrasil pulls anonymously: its
|
||||||
`PullImage` calls the Docker SDK with no `RegistryAuth`, so a private image comes
|
`PullImage` calls the Docker SDK with no `RegistryAuth`, so a private image comes
|
||||||
back 401. The pull error is discarded, and `ContainerCreate` — which only ever
|
back 401. The pull error is discarded, and `ContainerCreate` — which only ever
|
||||||
looks locally — then reports the image as missing.
|
looks locally — then reports the image as missing.
|
||||||
@@ -24,10 +24,21 @@ looks locally — then reports the image as missing.
|
|||||||
sends them itself with each request. Yggdrasil is a different client and
|
sends them itself with each request. Yggdrasil is a different client and
|
||||||
sends none, so logging in changes nothing for the panel.
|
sends none, so logging in changes nothing for the panel.
|
||||||
|
|
||||||
**Make the package public.** Under
|
**The package has to be readable without credentials.** On Gitea that does not
|
||||||
[Packages → verdande → Package settings](https://github.com/users/kristianwind/packages/container/package/verdande)
|
mean making the source repository public: a container package is only tied to a
|
||||||
→ *Change visibility*. The repository stays private; only the built image becomes
|
repository when it is pushed with a repository link, and this one is not — so its
|
||||||
readable, which is what the manifest and these pages have always assumed.
|
visibility follows the account, which is public, while `kw/verdande` stays
|
||||||
|
private.
|
||||||
|
|
||||||
|
Check it the way a puller does, with no credentials at all:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker --config /tmp/empty pull gitea.nolimit.dk/kw/verdande:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
If that works, the panel can pull it. A plain `curl` against `/v2/…/manifests/…`
|
||||||
|
answers 401 even for a readable image — the registry hands out an anonymous token
|
||||||
|
first — so a bare curl is not the test.
|
||||||
|
|
||||||
Once it is public, press **Start** on the server you already have. There is no
|
Once it is public, press **Start** on the server you already have. There is no
|
||||||
need to delete it and make another: the image reference is read from the rune at
|
need to delete it and make another: the image reference is read from the rune at
|
||||||
@@ -37,8 +48,8 @@ To keep the package private you have to put the image on the host yourself,
|
|||||||
before creating the server, and again after every release:
|
before creating the server, and again after every release:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo docker login ghcr.io -u kristianwind
|
sudo docker login gitea.nolimit.dk -u kw
|
||||||
sudo docker pull ghcr.io/kristianwind/verdande:latest
|
sudo docker pull gitea.nolimit.dk/kw/verdande:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Run it as the user the Docker daemon runs as — `sudo` if the panel does. The
|
Run it as the user the Docker daemon runs as — `sudo` if the panel does. The
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ cache, no queue and no second process.
|
|||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
!!! note "If the pull is refused"
|
!!! note "If the pull is refused"
|
||||||
The GHCR package is public, so this needs no credentials. If it is ever set
|
The image is published from a self-hosted Gitea and is readable without
|
||||||
back to private, `docker login ghcr.io` with a token carrying the
|
credentials — the package is not linked to a repository, so its visibility
|
||||||
`read:packages` scope before pulling — and see
|
follows the account rather than the (private) source repo. If it is ever set
|
||||||
|
back to private, `docker login gitea.nolimit.dk` before pulling — and see
|
||||||
[the Rune page](rune.md#if-the-image-will-not-pull), because a private image
|
[the Rune page](rune.md#if-the-image-will-not-pull), because a private image
|
||||||
fails differently and much more confusingly under Yggdrasil.
|
fails differently and much more confusingly under Yggdrasil.
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ docker run -d --name verdande \
|
|||||||
-p 8080:8080 \
|
-p 8080:8080 \
|
||||||
-v verdande-data:/data \
|
-v verdande-data:/data \
|
||||||
-e VERDANDE_BASE_URL=https://todo.example.dk \
|
-e VERDANDE_BASE_URL=https://todo.example.dk \
|
||||||
ghcr.io/kristianwind/verdande:latest
|
gitea.nolimit.dk/kw/verdande:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
`VERDANDE_BASE_URL` has to be the address you actually reach it on. Invite links,
|
`VERDANDE_BASE_URL` has to be the address you actually reach it on. Invite links,
|
||||||
@@ -30,7 +31,7 @@ means the links in your email point somewhere that does not answer.
|
|||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
verdande:
|
verdande:
|
||||||
image: ghcr.io/kristianwind/verdande:latest
|
image: gitea.nolimit.dk/kw/verdande:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
|
|||||||
+18
-2
@@ -15,14 +15,30 @@ gameskill:
|
|||||||
# this: a manifest with new fields and an unchanged version is a manifest the
|
# this: a manifest with new fields and an unchanged version is a manifest the
|
||||||
# panel has no reason to re-read, so the fields never appear and the failure is
|
# panel has no reason to re-read, so the fields never appear and the failure is
|
||||||
# silent — the server's settings page simply does not offer them.
|
# silent — the server's settings page simply does not offer them.
|
||||||
version: 4
|
# Bumpet til 5, fordi imagets adresse flyttede. En rune opdaterer ikke sig selv:
|
||||||
|
# panelet skriver rune-rækken fra en UI-handling, så ændringen her kræver
|
||||||
|
# **Runes → verdande → Update** — og katalog-listen caches ti minutter, så to
|
||||||
|
# forsøg lige efter hinanden kan begge give den gamle version.
|
||||||
|
version: 5
|
||||||
icon: "app"
|
icon: "app"
|
||||||
|
|
||||||
# The image is distroless — no shell — so keep_entrypoint runs the binary the
|
# The image is distroless — no shell — so keep_entrypoint runs the binary the
|
||||||
# image already declares as its ENTRYPOINT, and startup.exec passes it argv
|
# image already declares as its ENTRYPOINT, and startup.exec passes it argv
|
||||||
# directly rather than through /bin/sh, which does not exist in there.
|
# directly rather than through /bin/sh, which does not exist in there.
|
||||||
|
# Hentes fra vores egen Gitea frem for fra GHCR.
|
||||||
|
#
|
||||||
|
# Panelets `PullImage` sætter aldrig `RegistryAuth`, så registret skal kunne
|
||||||
|
# læses anonymt. Det kan det her: pakken er *ikke* knyttet til repoet — Gitea
|
||||||
|
# binder kun en container-pakke til et repo, når den bliver skubbet med et
|
||||||
|
# repo-link — så dens synlighed følger brugeren `kw`, som er offentlig, mens
|
||||||
|
# `kw/verdande` bliver ved med at være privat. Bevist med en `docker pull` uden
|
||||||
|
# nogen legitimation, som hentede samme digest som GHCR havde.
|
||||||
|
#
|
||||||
|
# Skubbes den nogensinde på en måde, der knytter den til repoet, bliver den
|
||||||
|
# privat med det samme, og panelet får `No such image` — lydløst, fordi
|
||||||
|
# `pullImageRetry` kasserer fejlen og `ContainerCreate` først slår op lokalt.
|
||||||
docker:
|
docker:
|
||||||
image: "ghcr.io/kristianwind/verdande:latest"
|
image: "gitea.nolimit.dk/kw/verdande:latest"
|
||||||
data_path: /data
|
data_path: /data
|
||||||
keep_entrypoint: true
|
keep_entrypoint: true
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1238,7 +1238,7 @@
|
|||||||
-p 8080:8080 \
|
-p 8080:8080 \
|
||||||
-v verdande-data:/data \
|
-v verdande-data:/data \
|
||||||
-e VERDANDE_BASE_URL=https://todo.example.dk \
|
-e VERDANDE_BASE_URL=https://todo.example.dk \
|
||||||
ghcr.io/kristianwind/verdande:latest</code></pre>
|
gitea.nolimit.dk/kw/verdande:latest</code></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user