Dateien nach "/" hochladen
This commit is contained in:
@@ -0,0 +1,195 @@
|
|||||||
|
# DNF-Spiegelserver fuer Pakete ohne Flatpak
|
||||||
|
|
||||||
|
Ergaenzt den bestehenden Flathub-Filter-Spiegel um einen zweiten Weg fuer
|
||||||
|
Anwendungen, die es nur als RPM gibt. Beide sollen unter einer Domain laufen:
|
||||||
|
|
||||||
|
- `https://<domain>/flatpak/...` - bereits vorhanden
|
||||||
|
- `https://<domain>/dnf/...` - dieser Stack
|
||||||
|
|
||||||
|
## Funktionsprinzip
|
||||||
|
|
||||||
|
Der `dnf-mirror`-Container laeuft dauerhaft und fuehrt alle
|
||||||
|
`SYNC_INTERVAL_SECONDS` (Default 6h) folgenden Zyklus aus:
|
||||||
|
|
||||||
|
0. **packages.yaml aktualisieren**: `git fetch`/`reset --hard` gegen das in
|
||||||
|
`SOURCES_GIT_URL` konfigurierte Git-Repo, das eine Datei `packages.yaml`
|
||||||
|
enthaelt (siehe `sources-repo-template/`). Das passiert vor **jedem**
|
||||||
|
Sync-Lauf - neue/geaenderte Eintraege in diesem separaten Repo wirken also
|
||||||
|
spaetestens beim naechsten automatischen Lauf, ganz ohne Neubau/Neustart
|
||||||
|
des Containers. `packages.yaml` listet Fremdrepos mit ihrer URL und genau
|
||||||
|
den Paketnamen, die daraus geholt werden sollen, z.B.:
|
||||||
|
```yaml
|
||||||
|
repos:
|
||||||
|
- id: vscode
|
||||||
|
baseurl: https://packages.microsoft.com/yumrepos/vscode
|
||||||
|
gpgkey: https://packages.microsoft.com/keys/microsoft.asc
|
||||||
|
packages:
|
||||||
|
- code
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach, pro dort definiertem Fremdrepo:
|
||||||
|
|
||||||
|
1. **`dnf download`** holt aus dem Fremdrepo genau die unter `packages:`
|
||||||
|
gelisteten Paketnamen (keine automatische Abhaengigkeitsaufloesung, keine
|
||||||
|
sonstigen Pakete aus diesem Repo - siehe `sources-repo-template/README.md`).
|
||||||
|
2. **Filtern**: Jedes heruntergeladene Paket wird trotzdem gegen die
|
||||||
|
Paketnamen geprueft, die AlmaLinux selbst liefert (BaseOS/AppStream/
|
||||||
|
Extras/CRB/EPEL - konfigurierbar ueber `ALMA_BASELINE_REPOIDS`). Ist der
|
||||||
|
Name dort vorhanden, wird das Paket verworfen: die Clients haben ihre
|
||||||
|
Alma-Repos ja selbst schon eingebunden und loesen es von dort auf (Schutz
|
||||||
|
gegen versehentliches Doppelspiegeln, falls jemand faelschlich ein
|
||||||
|
Alma-Paket in `packages.yaml` eintraegt). Ausnahmen lassen sich im
|
||||||
|
`force_include`-Feld von `packages.yaml` eintragen (z.B. wenn eine
|
||||||
|
Anwendung eine neuere Version einer Bibliothek braucht als Alma mitbringt).
|
||||||
|
3. **Umsignieren**: Die verbleibenden, tatsaechlich zu spiegelnden Pakete
|
||||||
|
werden mit `rpmsign --resign` komplett neu signiert - die Original-
|
||||||
|
Herstellersignatur wird ersetzt. Dadurch brauchen Clients nur **einen**
|
||||||
|
GPG-Key (den des Spiegelservers), egal von wie vielen verschiedenen
|
||||||
|
Herstellern die gespiegelten Pakete urspruenglich stammen.
|
||||||
|
4. **Metadaten bauen**: `createrepo_c` fuer die eigentlichen Repo-Metadaten,
|
||||||
|
`appstream-builder` fuer AppStream-Katalogdaten, damit die Anwendungen mit
|
||||||
|
Name/Icon/Beschreibung in **Discover (GNOME Software)** auftauchen statt
|
||||||
|
nur per `dnf`/`pkcon` auf der Kommandozeile sichtbar zu sein.
|
||||||
|
5. `repomd.xml` wird zusaetzlich separat signiert (`repomd.xml.asc`), damit
|
||||||
|
Clients `repo_gpgcheck=1` nutzen koennen (schuetzt auch die Metadaten
|
||||||
|
selbst, nicht nur die einzelnen Pakete).
|
||||||
|
6. Eine fertige Client-`.repo`-Datei wird nach `/srv/dnf/<id>.repo`
|
||||||
|
geschrieben und ist unter `https://<domain>/dnf/<id>.repo` abrufbar.
|
||||||
|
|
||||||
|
Der `nginx`-Container bekommt das Ausgabe-Volume read-only gemountet und
|
||||||
|
liefert es unter `/dnf/` aus. Er baut keine Pakete, sondern ist nur fuer den
|
||||||
|
Zugriff von aussen zustaendig.
|
||||||
|
|
||||||
|
## Erste Einrichtung
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. Paketliste: sources-repo-template/packages.yaml (angepasst) in ein
|
||||||
|
# EIGENES, separates Git-Repo pushen (siehe sources-repo-template/README.md)
|
||||||
|
cp sources-repo-template/packages.yaml /pfad/zum/eigenen/git-repo/packages.yaml
|
||||||
|
# Inhalt pruefen/anpassen (eigene Fremdrepos + Paketnamen eintragen), dann
|
||||||
|
# committen+pushen ins neue Git-Repo
|
||||||
|
|
||||||
|
# 2. Compose-Stack konfigurieren
|
||||||
|
cp .env.example .env
|
||||||
|
# .env anpassen: mindestens MIRROR_DOMAIN, GPG_NAME, GPG_EMAIL, SOURCES_GIT_URL
|
||||||
|
|
||||||
|
# 3. Bei SSH-Zugriff aufs Git-Repo: Deploy-Key (nur Lesezugriff) ablegen
|
||||||
|
cp /pfad/zum/deploy-key ./git-ssh/id_ed25519
|
||||||
|
chmod 600 ./git-ssh/id_ed25519
|
||||||
|
|
||||||
|
docker compose up -d --build
|
||||||
|
docker compose logs -f dnf-mirror # ersten Sync-Lauf beobachten
|
||||||
|
```
|
||||||
|
|
||||||
|
Der `./gpg`-Ordner neben der `docker-compose.yml` wird beim ersten Start vom
|
||||||
|
Container selbst befuellt (GPG-Schluesselpaar) - dort ist nichts manuell
|
||||||
|
vorzubereiten, aber der Ordner sollte auf dem Host entsprechend geschuetzt
|
||||||
|
(nicht world-readable) und **gesichert/gebackupt** werden: geht er verloren,
|
||||||
|
muessen alle Clients den neuen Public Key neu importieren.
|
||||||
|
|
||||||
|
Nach dem ersten Lauf:
|
||||||
|
|
||||||
|
- `https://<domain>/dnf/RPM-GPG-KEY-mirror` - der Public Key des Spiegels
|
||||||
|
- `https://<domain>/dnf/vscode.repo` - fertige Repo-Datei fuer Clients
|
||||||
|
- `https://<domain>/dnf/vscode/` - das eigentliche Repository
|
||||||
|
|
||||||
|
## Neue Anwendungen spiegeln
|
||||||
|
|
||||||
|
Fuer jede Anwendung ohne Flatpak einen Eintrag unter `repos:` in der
|
||||||
|
`packages.yaml` **im separaten Paketlisten-Git-Repo** ergaenzen (Fremdrepo-
|
||||||
|
URL + die gewuenschten Paketnamen unter `packages:`), committen, pushen - der
|
||||||
|
Container zieht das beim naechsten Sync-Lauf automatisch. Kein Zugriff auf
|
||||||
|
den Docker-Host/Compose-Stack noetig, das kann also z.B. per Merge-Request-
|
||||||
|
Review an ein anderes Team delegiert werden.
|
||||||
|
|
||||||
|
## Clients anbinden
|
||||||
|
|
||||||
|
Einmalig (per Ansible/Kickstart/Intune-Skript/Image-Build - vermutlich schon
|
||||||
|
Teil eurer bestehenden Entra-ID-Provisioning-Pipeline), z.B. mit dem
|
||||||
|
mitgelieferten Skript:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./client/bootstrap.sh software.example.org vscode
|
||||||
|
```
|
||||||
|
|
||||||
|
Das importiert den Mirror-GPG-Key und legt die `.repo`-Datei ab. Rootlose
|
||||||
|
Installation/Update/Deinstallation laeuft danach ueber die bereits
|
||||||
|
bestehenden Polkit-Regeln fuer PackageKit wie gewohnt - hier ist nichts
|
||||||
|
zusaetzlich noetig.
|
||||||
|
|
||||||
|
## Bekannte Einschraenkungen
|
||||||
|
|
||||||
|
- **AppStream/Discover**: `appstream-builder` (Paket `appstream-glib`, aus
|
||||||
|
EPEL) extrahiert AppStream-Metadaten aus Paketen, die selbst
|
||||||
|
`.metainfo.xml`/`.desktop`-Dateien mitbringen. Bringt eine Anwendung so
|
||||||
|
etwas nicht mit, erscheint sie trotzdem installierbar, aber ohne
|
||||||
|
Katalogeintrag (Name/Icon/Beschreibung) in Discover - nur per Suche nach
|
||||||
|
dem Paketnamen. Das ist eine Eigenschaft des Quellpakets, keine
|
||||||
|
Konfigurationsluecke.
|
||||||
|
- **Namensbasierter Abgleich**: Paket X wird uebersprungen, sobald ein Paket
|
||||||
|
gleichen Namens in Alma existiert - unabhaengig von der Version. Falls eine
|
||||||
|
gespiegelte Anwendung eine neuere Version einer Alma-Bibliothek als
|
||||||
|
Abhaengigkeit braucht, dafuer `force_include` in `packages.yaml` nutzen.
|
||||||
|
- **Keine Abhaengigkeitsaufloesung**: `packages.yaml` listet die zu
|
||||||
|
spiegelnden Pakete explizit; `dnf download` holt genau diese Namen aus dem
|
||||||
|
jeweiligen Fremdrepo, ohne fehlende Abhaengigkeiten automatisch
|
||||||
|
nachzuladen. Fehlt einer gespiegelten Anwendung eine Bibliothek, die weder
|
||||||
|
aus Alma/EPEL noch aus demselben Fremdrepo kommt, muss sie explizit mit in
|
||||||
|
`packages:` aufgenommen werden.
|
||||||
|
- **GPG-Key-Ablage**: Der Signing-Key liegt (statt in einem anonymen Docker-
|
||||||
|
Volume) im Ordner `./gpg` direkt neben der `docker-compose.yml` - dadurch
|
||||||
|
laesst er sich mit normalen Host-Mitteln sichern/backupen/einschraenken.
|
||||||
|
Der Container startet dafuer intern kurz als root, chownt `./gpg` auf den
|
||||||
|
unprivilegierten `mirror`-User und wechselt dann per `setpriv` dauerhaft zu
|
||||||
|
diesem (siehe `mirror/entrypoint.sh`) - der eigentliche Sync inkl. `git`/
|
||||||
|
`dnf`/`gpg` laeuft nie als root.
|
||||||
|
- **GPG-Passphrase**: Der Signing-Key wird standardmaessig ohne Passphrase
|
||||||
|
erzeugt, damit der Container vollautomatisch signieren kann. Der Schutz
|
||||||
|
liegt dann in den Dateirechten von `./gpg` (nicht world-readable lassen!).
|
||||||
|
Eine Passphrase ist in `run-as-mirror.sh` fuer die Schluesselerzeugung
|
||||||
|
vorbereitet, automatisches Signieren mit passphrasegeschuetztem Key ist
|
||||||
|
aber NICHT fertig verdrahtet (braucht zusaetzlich `gpg-preset-passphrase`
|
||||||
|
o.ae.) - fuer den unbeaufsichtigten Betrieb wird die leere Passphrase
|
||||||
|
empfohlen.
|
||||||
|
- **Git-Zugriff**: `SOURCES_GIT_URL` wird vor jedem Sync-Lauf gefetcht. Schlaegt
|
||||||
|
das fehl (Netzwerk, Auth), laeuft der Sync mit der letzten erfolgreich
|
||||||
|
geholten Paketliste weiter (nicht beim allerersten Lauf - dort bricht der
|
||||||
|
Sync-Zyklus ohne erreichbares Git-Repo komplett ab). Nur ein Lesezugriff
|
||||||
|
(Deploy-Key/Read-only-Token) ist noetig.
|
||||||
|
- **TLS**: Der `nginx`-Service ist bewusst schlank gehalten (Port 80). Fuer
|
||||||
|
TLS entweder Zertifikate mounten und einen `listen 443 ssl` Server-Block
|
||||||
|
ergaenzen, oder - passend zum Wunsch "eine Domain fuer beide Repos" -
|
||||||
|
diesen Stack hinter einem bereits vorhandenen Reverse Proxy/Loadbalancer
|
||||||
|
betreiben, der auch den Flatpak-Spiegel terminiert.
|
||||||
|
- Dieser Aufbau wurde nicht gegen echte Internet-Upstreams end-to-end
|
||||||
|
getestet (keine Docker-Umgebung/Internetzugriff in dieser Session
|
||||||
|
verfuegbar) - Skripte sind syntaktisch geprueft, der erste `docker compose
|
||||||
|
up` sollte aber mit echten Repo-Definitionen beobachtet werden.
|
||||||
|
|
||||||
|
## Verzeichnisstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose.yml
|
||||||
|
.env.example
|
||||||
|
gpg/ (leer, wird vom Container befuellt) - Signing-Key,
|
||||||
|
auf dem Host sichern/schuetzen
|
||||||
|
git-ssh/ optional: SSH-Deploy-Key fuers Paketlisten-Git-Repo
|
||||||
|
mirror/
|
||||||
|
Dockerfile AlmaLinux-Image mit dnf-plugins-core, createrepo_c,
|
||||||
|
rpm-sign, appstream-glib, git, python3-pyyaml, jq
|
||||||
|
entrypoint.sh laeuft als root: chownt ./gpg, wechselt per setpriv
|
||||||
|
zu "mirror"
|
||||||
|
run-as-mirror.sh laeuft als "mirror": GPG-Key-Erzeugung/-Export,
|
||||||
|
Sync-Schleife
|
||||||
|
sync.sh Kernlogik: packages.yaml aus Git holen -> dnf
|
||||||
|
download je Fremdrepo -> filtern -> signieren ->
|
||||||
|
Metadaten -> Client-.repo
|
||||||
|
config/
|
||||||
|
alma-baseline.repo.d/ optional: eigene Baseline-Repos fuer den Abgleich
|
||||||
|
sources-repo-template/ Vorlage fuer das SEPARATE Git-Repo mit der
|
||||||
|
Paketliste (packages.yaml)
|
||||||
|
nginx/
|
||||||
|
conf.d/repo.conf liefert /dnf/... aus, Platzhalter fuer /flatpak/...
|
||||||
|
client/
|
||||||
|
bootstrap.sh einmaliges Client-Onboarding (Key-Import + .repo)
|
||||||
|
```
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
services:
|
||||||
|
dnf-mirror:
|
||||||
|
build: ./mirror
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MIRROR_DOMAIN: ${MIRROR_DOMAIN}
|
||||||
|
GPG_NAME: ${GPG_NAME}
|
||||||
|
GPG_EMAIL: ${GPG_EMAIL}
|
||||||
|
GPG_PASSPHRASE: ${GPG_PASSPHRASE}
|
||||||
|
SYNC_INTERVAL_SECONDS: ${SYNC_INTERVAL_SECONDS:-21600}
|
||||||
|
SOURCES_GIT_URL: ${SOURCES_GIT_URL}
|
||||||
|
SOURCES_GIT_REF: ${SOURCES_GIT_REF:-main}
|
||||||
|
SOURCES_GIT_SSH_KEY: ${SOURCES_GIT_SSH_KEY:-}
|
||||||
|
ALMA_RELEASEVER: ${ALMA_RELEASEVER:-9}
|
||||||
|
ALMA_BASEARCH: ${ALMA_BASEARCH:-x86_64}
|
||||||
|
ALMA_BASELINE_REPOIDS: ${ALMA_BASELINE_REPOIDS:-baseos,appstream,extras,crb,epel}
|
||||||
|
volumes:
|
||||||
|
- ./mirror/config/alma-baseline.repo.d:/etc/mirror/alma-baseline.repo.d:ro
|
||||||
|
- ./git-ssh:/run/secrets/git-ssh:ro
|
||||||
|
- ./gpg:/var/lib/mirror-gpg
|
||||||
|
- dnf-repo-data:/srv/dnf
|
||||||
|
- mirror-cache:/var/cache/mirror
|
||||||
|
# kein Port-Publish: der Container schreibt nur in das Volume, das nginx
|
||||||
|
# ausliefert. Braucht ausgehenden Internetzugriff zu den Upstream-Repos
|
||||||
|
# UND zum Git-Repo mit der Paketliste (SOURCES_GIT_URL), das er vor jedem
|
||||||
|
# Sync-Lauf neu abruft.
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:1.27-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- dnf-mirror
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
# - "443:443" # TLS: siehe README (eigene Zertifikate mounten oder
|
||||||
|
# vorgeschalteten Reverse Proxy/Load Balancer nutzen)
|
||||||
|
volumes:
|
||||||
|
- dnf-repo-data:/usr/share/nginx/html/dnf:ro
|
||||||
|
- ./nginx/conf.d:/etc/nginx/conf.d:ro
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
dnf-repo-data:
|
||||||
|
mirror-cache:
|
||||||
Reference in New Issue
Block a user