277 lines
9.2 KiB
Markdown
277 lines
9.2 KiB
Markdown
# git-pages → Nginx + PV -arkkitehtuuri
|
|
|
|
> Päivitetty: 2026-06-28
|
|
|
|
## Ongelma
|
|
|
|
git-pages storage v2 pakottaa kaikki tiedostot yhteen `.index`-protobufiin per site.
|
|
Raja on 1MB kovakoodattu. Yksi monorepo täytti tämän, eikä uusia raportteja voi
|
|
julkaista ennen kuin ongelma on ratkaistu.
|
|
|
|
## Ratkaisu
|
|
|
|
Poista git-pages kokonaan. Korvaa Nginx:llä (static serving) + kevyellä upload-sidecarilla (tar.gz HTTP PUT → extract). Tiedostot suoraan PV:llä ilman `.index`-välikerrosta.
|
|
|
|
## Lukitut päätökset
|
|
|
|
1. **git-pages poistuu** — sovellus ei ole mukana luku- eikä kirjoitusketjussa
|
|
2. **Nginx palvelee suoraan PV:ltä** — `root /data`, `autoindex on`, `try_files $uri $uri/ $uri/index.html =404`
|
|
3. **Upload-sidecar** — busybox httpd + CGI, ottaa vastaan `PUT /path` + tar.gz body ja purkaa PV:lle
|
|
4. **URL = FS-polku** — ei Host-header-kikkaa, ei slugia, ei rewritea
|
|
5. **Traefik** — PATCH/PUT → upload-sidecar:8081 (BasicAuth), GET/HEAD → nginx:8080 (ForwardAuth myöh.)
|
|
6. **CI-julkaisu** — `curl -X PUT --data-binary @report.tar.gz https://{host}/{owner}/{repo}/{branch_raw}/{sha8}/{suite}/`
|
|
7. **Branch raakana URL:ssa** — `feature/x` URL:ssa = `feature/x/` FS:ssä. Ei slugitusta
|
|
8. **Linkki on aina 1-suuntainen** — gitea → raportti. Raportista ei linkkiä giteaan
|
|
9. **GITEA_API_URL poistuu** publish-skriptin pakollisista env-varista (retention käyttää omaansa)
|
|
|
|
## Ympäristömuuttujat
|
|
|
|
### GITHUB_REF_NAME
|
|
|
|
Gitea Actions runnerin automaattisesti asettama muuttuja, joka on branchin/tagin nimi ilman `refs/heads/`-etuliitettä.
|
|
|
|
| Tilanne | Arvo |
|
|
|---------|------|
|
|
| branch `main` | `main` |
|
|
| branch `feature/branch` | `feature/branch` |
|
|
| tag `v1.0.0` | `v1.0.0` |
|
|
|
|
Käytännössä `git rev-parse --abbrev-ref HEAD`. Branchin `/` on sallittu URL-polussa, joten `GITHUB_REF_NAME` voidaan käyttää sellaisenaan rakenteessa `${GITHUB_REF_NAME}/${SHA8}/${SUITE}`. Rinnakkaisissa buildeissa jokainen runner ajaa oman branchinsa kontekstissa → URL pysyy uniikkina.
|
|
|
|
```
|
|
CI → curl -X PUT → Traefik (BasicAuth middleware)
|
|
→ upload-sidecar:8081 (busybox httpd + CGI)
|
|
→ tar -xzf - -C /data/{owner}/{repo}/{branch}/{sha8}/{suite}/
|
|
→ PV /app/data/
|
|
|
|
Browser → GET → Traefik
|
|
→ nginx:8080 (root /app/data)
|
|
→ /data/{owner}/{repo}/{branch}/{sha8}/{suite}/index.html
|
|
```
|
|
|
|
## Tiedostomuutokset
|
|
|
|
### Poistuu (4 tiedostoa)
|
|
|
|
| Tiedosto | Miksi |
|
|
|----------|-------|
|
|
| `templates/init-job.yaml` | Ei enää git-pages API:a alustettavaksi |
|
|
| `templates/configmap.yaml` (nykyinen) | Korvataan nginx-conf + CGI |
|
|
| `templates/deployment.yaml` (nykyinen) | Korvataan uudella |
|
|
| `git-pages-image` (values.yaml) | Ei enää git-pages-konttia |
|
|
|
|
### Muuttuu (8 tiedostoa)
|
|
|
|
| # | Tiedosto | Muutos |
|
|
|---|----------|--------|
|
|
| 1 | `Chart.yaml` | description, poista appVersion |
|
|
| 2 | `values.yaml` | Poista git-pages-keyt, lisää nginx/sidecar |
|
|
| 3 | `dev-values.yaml` | Matchaa uusi values-rakenne |
|
|
| 4 | `templates/configmap.yaml` | `nginx.conf` + `upload.sh` (CGI) |
|
|
| 5 | `templates/deployment.yaml` | 2 konttia: nginx:alpine (8080) + busybox httpd (8081) |
|
|
| 6 | `templates/ingressroute.yaml` | Backend: PATCH/PUT → upload:8081, GET/HEAD → nginx:8080 |
|
|
| 7 | `templates/service.yaml` | 2 porttia: http-read(8080), http-write(8081) |
|
|
| 8 | `templates/NOTES.txt` | Uusi URL + esimerkit |
|
|
|
|
### Pysyy ennallaan (8 tiedostoa)
|
|
|
|
| Tiedosto | Huomio |
|
|
|----------|--------|
|
|
| `templates/certificate.yaml` | TLS hostille |
|
|
| `templates/middleware.yaml` | BasicAuth + HTTPS redirect |
|
|
| `templates/publish-auth-secret.yaml` | Sama BasicAuth-secret |
|
|
| `templates/pvc.yaml` | Sama PVC |
|
|
| `templates/retention-configmap.yaml` | Päivitä retention-scriptit |
|
|
| `templates/retention-cronjob.yaml` | Pieni muutos (ei git-pages API) |
|
|
| `templates/retention-rbac.yaml` | Ennallaan |
|
|
| `_helpers.tpl` | Vain label-helpers |
|
|
|
|
### Chartin ulkopuolella
|
|
|
|
| Tiedosto | Muutos |
|
|
|----------|--------|
|
|
| `scripts/publish-git-pages.sh` | Uusi: `curl -X PUT` tar.gz upload-sidecariin |
|
|
| `scripts/report-status.sh` | Tarkista URL-muoto |
|
|
| `git-pages/docs/architecture.md` | Uusi arkkitehtuuri |
|
|
| `docs/design-rationale.md` | Päivitys |
|
|
| `files/retention-*.sh` | Lue PV:tä suoraan, ei git-pages API:a |
|
|
|
|
## Nginx-konfiguraatio (ydin)
|
|
|
|
```nginx
|
|
server {
|
|
listen 8080;
|
|
root /app/data;
|
|
autoindex on;
|
|
|
|
location / {
|
|
try_files $uri $uri/ $uri/index.html =404;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Upload CGI (ydin)
|
|
|
|
```bash
|
|
#!/bin/sh
|
|
read -r method uri _
|
|
case "$method" in
|
|
PUT)
|
|
dest="/app/data${uri%/*}" # strip filename
|
|
mkdir -p "$dest"
|
|
cat - | tar -xzf - -C "$dest"
|
|
echo "Status: 201 Created"
|
|
echo ""
|
|
;;
|
|
esac
|
|
```
|
|
|
|
## Deployment (kontit)
|
|
|
|
```yaml
|
|
containers:
|
|
- name: nginx
|
|
image: nginx:alpine
|
|
ports:
|
|
- containerPort: 8080
|
|
name: http-read
|
|
volumeMounts:
|
|
- name: nginx-conf
|
|
mountPath: /etc/nginx/conf.d
|
|
- name: data
|
|
mountPath: /app/data
|
|
- name: upload
|
|
image: alpine:latest
|
|
command: ["busybox", "httpd", "-f", "-p", "8081", "-h", "/cgi"]
|
|
ports:
|
|
- containerPort: 8081
|
|
name: http-write
|
|
volumeMounts:
|
|
- name: cgi-scripts
|
|
mountPath: /cgi
|
|
readOnly: true
|
|
- name: data
|
|
mountPath: /app/data
|
|
```
|
|
|
|
## CI-julkaisu (publish-skripti)
|
|
|
|
### Muutokset nykyiseen
|
|
|
|
| Kohta | Nykyinen | Uusi |
|
|
|-------|----------|------|
|
|
| `GITEA_API_URL` | pakollinen env-var | **poistettu** (retention käyttää omaansa) |
|
|
| Tar-prefiksi | `{owner}/{repo}/reports/{sha8}/{suite}` | ei prefiksiä — `{suite}` |
|
|
| Paketti | `tar -cf` | `tar -czf` (gzip) |
|
|
| Content-Type | `application/x-tar` | `application/tar+gz` |
|
|
| Headerit | `Atomic: no`, `Create-Parents: yes` | poistettu |
|
|
| Kohde | `PATCH {GIT_PAGES_URL}/` | `PUT {GIT_PAGES_URL}/{owner}/{repo}/{branch}/{sha8}/{suite}/` |
|
|
| Branch | vain `.meta` | URL:ssa + `.meta` |
|
|
|
|
### Uusi skripti (ydin)
|
|
|
|
```bash
|
|
#!/usr/bin/env sh
|
|
set -eu
|
|
|
|
SUITE_PATH="${1:-}"
|
|
[ -n "$SUITE_PATH" ] || { echo "ERROR: suite_path required" >&2; exit 1; }
|
|
[ -n "${GIT_PAGES_URL:-}" ] || { echo "ERROR: GIT_PAGES_URL is not set" >&2; exit 1; }
|
|
[ -n "${GIT_PAGES_PUBLISH_TOKEN:-}" ] || { echo "ERROR: GIT_PAGES_PUBLISH_TOKEN is not set" >&2; exit 1; }
|
|
[ -n "${GITHUB_REPOSITORY:-}" ] || { echo "ERROR: GITHUB_REPOSITORY is not set" >&2; exit 1; }
|
|
[ -n "${GITHUB_SHA:-}" ] || { echo "ERROR: GITHUB_SHA is not set" >&2; exit 1; }
|
|
[ -n "${GITHUB_REF_NAME:-}" ] || { echo "ERROR: GITHUB_REF_NAME is not set" >&2; exit 1; }
|
|
|
|
OWNER="${GITHUB_REPOSITORY%%/*}"
|
|
REPO="${GITHUB_REPOSITORY##*/}"
|
|
SHA8=$(echo "$GITHUB_SHA" | cut -c1-8)
|
|
BRANCH="${GITHUB_REF_NAME}"
|
|
SUITE="${SUITE_PATH%/}"
|
|
PAGES_USER="${GIT_PAGES_PUBLISH_USER:-publish}"
|
|
|
|
[ -d "$SUITE" ] || { echo "ERROR: not a directory: $SUITE" >&2; exit 1; }
|
|
|
|
WORK=$(mktemp -d)
|
|
TAR=$(mktemp)
|
|
trap 'rm -rf "$WORK" "$TAR"' EXIT
|
|
|
|
# Kopioi raporttitiedostot
|
|
mkdir -p "$WORK/$SUITE"
|
|
cp -a "$SUITE/." "$WORK/$SUITE/"
|
|
|
|
# Generoi index.html (sama logiikka kuin nykyään)
|
|
cd "$WORK"
|
|
if [ ! -f "$SUITE/index.html" ]; then
|
|
# identtinen item-listaus kuin nykyisessä skriptissä
|
|
…
|
|
fi
|
|
|
|
# .meta tiedosto retentionia varten
|
|
cat > "$SUITE/.meta" <<EOF
|
|
{"branch":"${BRANCH}","sha":"${GITHUB_SHA}","published_at":"$(date -u +%Y-%m-%dT%H:%M:%SZ)"}
|
|
EOF
|
|
|
|
# Pakkaa
|
|
tar czf "$TAR" -C "$WORK" "$SUITE"
|
|
|
|
# PUT upload-sidecariin
|
|
PUBLISH_URL="${GIT_PAGES_URL}/${OWNER}/${REPO}/${BRANCH}/${SHA8}/${SUITE}/"
|
|
HTTP_CODE=$(curl -sS -X PUT "$PUBLISH_URL" \
|
|
-u "${PAGES_USER}:${GIT_PAGES_PUBLISH_TOKEN}" \
|
|
-H "Content-Type: application/tar+gz" \
|
|
--data-binary @"$TAR" \
|
|
-o /tmp/git-pages-publish-response.txt \
|
|
-w "%{http_code}")
|
|
|
|
case "$HTTP_CODE" in
|
|
200|201|204) ;;
|
|
*)
|
|
echo "ERROR: publish HTTP ${HTTP_CODE}" >&2
|
|
cat /tmp/git-pages-publish-response.txt >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
echo "${PUBLISH_URL}"
|
|
```
|
|
|
|
## Gitea commit -linkki (report-status.sh)
|
|
|
|
Gitean commit-näkymään tuleva raporttilinkki muodostetaan `scripts/report-status.sh`:ssa.
|
|
|
|
### Muutos
|
|
|
|
| Kohta | Nykyinen (rivi 21) | Uusi |
|
|
|-------|-------------------|------|
|
|
| URL | `${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/reports/${SHA8}/${SUITE}` | `${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/${GITHUB_REF_NAME}/${SHA8}/${SUITE}` |
|
|
|
|
`reports/` → `{GITHUB_REF_NAME}/`. Branchin raaka nimi URL-polussa on sallittu. Muu skripti (Gitea API -kutsu, token, json-body) pysyy identtisenä.
|
|
|
|
Tarkista: `GITHUB_REF_NAME` on oltava asetettu — Gitea Actions asettaa sen automaattisesti. Jos sitä tarvitaan tarkistuksena, lisätään `report-status.sh`:n env-var-tarkistuksiin.
|
|
|
|
## Gitea Actions step summary (report-summary.yml)
|
|
|
|
`.gitea/workflows/report-summary.yml` luo GITHUB_STEP_SUMMARY -taulukon raporttilinkeillä.
|
|
|
|
### Muutos
|
|
|
|
| Kohta | Nykyinen (rivi 28) | Uusi |
|
|
|-------|-------------------|------|
|
|
| BASE | `${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/reports/${SHA8}` | `${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/${GITHUB_REF_NAME}/${SHA8}` |
|
|
|
|
Sama muuri: `reports/` → `${GITHUB_REF_NAME}/`. Loppuosa identtinen.
|
|
|
|
## Retention
|
|
|
|
Retention siirtyy lukemaan PV:tä suoraan (find, ls, stat) git-pages API:n sijaan:
|
|
|
|
1. Listaa kaikki kansiot `/app/data/{owner}/{repo}/{branch}/{sha8}/`
|
|
2. Lue `.meta` jokaisesta
|
|
3. Tarkista branchin olemassaolo Gitea API:lla
|
|
4. Poista vanhat/kuolleet branchit kansiorakenteesta (`rm -rf`)
|
|
|
|
## Avoimet asiat (ei tässä MVP:ssä)
|
|
|
|
- ForwardAuth GET/HEAD-reitille (OIDC)
|
|
- 6 rinnakkaisen testin orkestrointi
|