Dateien nach "/" hochladen
This commit is contained in:
@@ -0,0 +1,327 @@
|
|||||||
|
# RPM Mirror Sync
|
||||||
|
|
||||||
|
`sync.sh` spiegelt einzeln benannte Pakete aus Drittanbieter-RPM-Repos in ein
|
||||||
|
lokales Repo, ohne dabei Pakete mitzuspiegeln, die AlmaLinux selbst schon
|
||||||
|
liefert (BaseOS, AppStream, Extras, CRB/"Extras for Enterprise"). Nur die in
|
||||||
|
der YAML-Liste explizit genannten Pakete bekommen AppStream-Metadaten und
|
||||||
|
werden damit in GNOME Software / Discover als installierbar angezeigt.
|
||||||
|
|
||||||
|
## Voraussetzungen (auf dem Server, der das Skript ausführt)
|
||||||
|
|
||||||
|
```
|
||||||
|
dnf install -y dnf-plugins-core createrepo_c python3-pyyaml git
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Skript muss als root laufen (schreibt kurzzeitig eine `.repo`-Datei nach
|
||||||
|
`/etc/yum.repos.d/`).
|
||||||
|
|
||||||
|
## Konfiguration
|
||||||
|
|
||||||
|
Alles über Umgebungsvariablen, z.B. in der systemd-Unit oder im Cron-Job:
|
||||||
|
|
||||||
|
| Variable | Bedeutung | Default |
|
||||||
|
|---------------------|------------------------------------------------------------------|---------|
|
||||||
|
| `SOURCES_GIT_REPO` | Git-Repo mit der YAML-Liste (leer = lokale Datei verwenden) | – |
|
||||||
|
| `SOURCES_GIT_BRANCH` | Branch im Git-Repo | `main` |
|
||||||
|
| `SOURCES_YAML_FILE` | Pfad zur YAML-Datei (im Git-Repo oder lokal) | `sources.yaml` |
|
||||||
|
| `WORK_DIR` | Arbeitsverzeichnis (Downloads, Logs, Zwischenlisten) | `/var/cache/rpm-mirror-sync` |
|
||||||
|
| `REPO_BASE_DIR` | Zielverzeichnis der gespiegelten Repos | `/srv/repo` |
|
||||||
|
| `CLIENT_REPO_DIR` | Wo fertige `.repo`-Dateien für Clients abgelegt werden | `${REPO_BASE_DIR}/client-repos` |
|
||||||
|
| `CLIENT_BASE_URL` | URL, unter der `REPO_BASE_DIR` für Clients erreichbar ist | `http://mirror.example.local/repo` |
|
||||||
|
| `ALMA_REPO_IDS` | repoids der lokalen AlmaLinux-Repos (`dnf repolist`) | `baseos appstream extras crb` |
|
||||||
|
|
||||||
|
**Wichtig:** `ALMA_REPO_IDS` muss zu den tatsächlichen repoids auf dem
|
||||||
|
Server passen (`dnf repolist` prüfen) — sonst funktioniert der
|
||||||
|
Ausschluss-Mechanismus nicht korrekt.
|
||||||
|
|
||||||
|
## Ausführen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export SOURCES_GIT_REPO=https://git.example.com/infra/rpm-sources.git
|
||||||
|
export CLIENT_BASE_URL=http://repo.internal.example.com/repo
|
||||||
|
./sync.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach liegt unter `REPO_BASE_DIR/pkgs/` das eine kombinierte Repo mit allen
|
||||||
|
Paketen aller Quellen (per Webserver auszuliefern) und unter
|
||||||
|
`CLIENT_REPO_DIR/mirror.repo` die eine fertige `.repo`-Datei, die auf die
|
||||||
|
Clients verteilt wird (z.B. via Ansible/Config-Management nach
|
||||||
|
`/etc/yum.repos.d/`).
|
||||||
|
|
||||||
|
Am besten per systemd-Timer (z.B. täglich) statt Cron, damit Logs sauber in
|
||||||
|
`journalctl` landen.
|
||||||
|
|
||||||
|
## Wie der Ausschluss von AlmaLinux-Abhängigkeiten funktioniert
|
||||||
|
|
||||||
|
1. Für jedes Source-Repo wird zunächst abgefragt, welche Pakete *dieses*
|
||||||
|
Repo überhaupt bereitstellt (`dnf repoquery` nur gegen das Source-Repo).
|
||||||
|
2. Anschließend wird die komplette Abhängigkeitskette der gewünschten
|
||||||
|
Pakete aufgelöst — dabei sind sowohl das Source-Repo als auch die
|
||||||
|
lokalen AlmaLinux-Repos aktiv, damit die Auflösung überhaupt gelingt
|
||||||
|
(z.B. wenn ein Paket von `glibc` abhängt).
|
||||||
|
3. Von den heruntergeladenen RPMs wird alles verworfen, was nicht in der
|
||||||
|
Liste aus Schritt 1 steht — also alles, was tatsächlich aus einem
|
||||||
|
AlmaLinux-Repo kam. Übrig bleiben nur RPMs, die es ausschließlich im
|
||||||
|
Drittanbieter-Repo gibt.
|
||||||
|
|
||||||
|
**Wichtig: "übrig bleiben" ist meist mehr als nur die Namen unter
|
||||||
|
`packages:`.** Wenn ein angefordertes Paket von weiteren Drittanbieter-Paketen
|
||||||
|
abhängt, die AlmaLinux nicht bereitstellt (z.B. bei .NET: `dotnet-host`,
|
||||||
|
`dotnet-hostfxr-*`, `dotnet-apphost-pack-*`, `aspnetcore-runtime-*`, ...),
|
||||||
|
werden die zwangsläufig mitgespiegelt — sonst schlägt `dnf install
|
||||||
|
dotnet-sdk-8.0` auf dem Client mit einer fehlenden Abhängigkeit fehl, die
|
||||||
|
nirgendwo sonst verfügbar wäre. Nur echte AlmaLinux-Pakete werden
|
||||||
|
ausgeschlossen, nicht Drittanbieter-Abhängigkeiten. Im Log ist das ab jetzt
|
||||||
|
pro Paket sichtbar:
|
||||||
|
|
||||||
|
```
|
||||||
|
[...] keeping (requested): dotnet-sdk-8.0-8.0.130-1.el10_2.x86_64
|
||||||
|
[...] keeping (dependency): dotnet-host-10.0.11-1.el10_2.x86_64
|
||||||
|
[...] Source 'dotnet': kept 26 package(s) - 6 explicitly requested + 20 pulled-in third-party dependencies (...)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sonderfall: `baseurl` zeigt auf ein AlmaLinux-eigenes Repo
|
||||||
|
|
||||||
|
`dnf` "sucht" nie selbstständig bei Drittanbietern — es lädt ausschließlich
|
||||||
|
von der URL, die ihr unter `baseurl` eintragt. Zeigt diese URL zufällig auf
|
||||||
|
ein AlmaLinux-eigenes Repo (z.B. `.../AppStream/...`), ist also gar keine
|
||||||
|
externe Quelle im Spiel. Genau das ist bei .NET auf AlmaLinux 10 der Fall:
|
||||||
|
`dotnet-sdk`, `dotnet-runtime`, `dotnet-host` & Co. sind Teil des offiziellen
|
||||||
|
AppStream-Repos (anders als bei älteren Alma-/RHEL-Versionen mit separatem
|
||||||
|
Microsoft-Repo).
|
||||||
|
|
||||||
|
Konsequenz: Die "requested"-Pakete sind hier technisch schon über das
|
||||||
|
normale, auf jedem Client ohnehin aktivierte AppStream-Repo installierbar —
|
||||||
|
der Ausschluss-Mechanismus (Schritt 1-3 oben) erkennt das nicht, weil er nur
|
||||||
|
gegen die *anderen* Alma-Repos (BaseOS, Extras, CRB) vergleicht, nicht gegen
|
||||||
|
die Quelle selbst. Ein normaler Mirror-Lauf würde hier also RPM-Inhalte
|
||||||
|
duplizieren, die AlmaLinux bereits liefert.
|
||||||
|
|
||||||
|
**Für genau diesen Fall gibt es `metadata_only: true`** (pro Quelle in der
|
||||||
|
YAML, siehe `sources.example.yaml`): Es werden **keine RPMs** heruntergeladen,
|
||||||
|
verifiziert oder umsigniert — nur kuratierte AppStream-Metadaten für die
|
||||||
|
gelisteten Paketnamen werden generiert und veröffentlicht. Das tatsächliche
|
||||||
|
Installieren übernimmt `dnf` weiterhin ganz normal über das Repo, das das
|
||||||
|
Paket wirklich bereitstellt (bei AlmaLinux-eigenen Paketen also das
|
||||||
|
Standard-AppStream-Repo, das auf jeder Standardinstallation ohnehin aktiv
|
||||||
|
ist). Der Effekt: Discover zeigt nur eure kuratierte Auswahl statt des
|
||||||
|
kompletten (oft sehr großen) AppStream-Kataloges, ohne dass ihr Inhalte
|
||||||
|
dupliziert, die es schon gibt.
|
||||||
|
|
||||||
|
**Voraussetzung:** Die Clients müssen das Repo, das die Pakete tatsächlich
|
||||||
|
bereitstellt, bereits aktiviert haben — bei Standard-AlmaLinux-Installationen
|
||||||
|
(BaseOS/AppStream/Extras/CRB aktiv) ist das automatisch der Fall.
|
||||||
|
|
||||||
|
Für ein echtes Drittanbieter-Repo (Pakete, die AlmaLinux nirgends hat) lasst
|
||||||
|
ihr `metadata_only` einfach weg (Default: `false`) — dann läuft der volle
|
||||||
|
Mirror-Prozess wie oben beschrieben, inklusive Verifikation und Umsignieren.
|
||||||
|
|
||||||
|
## Umsignieren mit einem eigenen GPG-Key
|
||||||
|
|
||||||
|
Damit eure Clients nicht für jede gespiegelte Quelle einen eigenen GPG-Key
|
||||||
|
importieren müssen, signiert `sync.sh` jedes gespiegelte Paket auf einen
|
||||||
|
einzigen, mirror-eigenen Schlüssel um:
|
||||||
|
|
||||||
|
1. Beim ersten Lauf wird — falls noch keiner unter `GPG_HOME` existiert —
|
||||||
|
einmalig ein GPG-Schlüsselpaar erzeugt (unattended, ohne Passphrase; das
|
||||||
|
ist für automatisierte Repo-Signierung üblich). Der öffentliche Teil wird
|
||||||
|
nach `REPO_BASE_DIR/RPM-GPG-KEY-mirror` exportiert.
|
||||||
|
2. Für jede Quelle wird — sofern `gpgkey:` in der YAML gesetzt ist — das
|
||||||
|
heruntergeladene RPM zunächst gegen den **originalen** Key des Upstream
|
||||||
|
geprüft (`rpmkeys --checksig`). Schlägt die Prüfung fehl, bricht das
|
||||||
|
Skript für diese Quelle ab (kein stillschweigendes Mirroring manipulierter
|
||||||
|
Pakete). Ist kein `gpgkey:` angegeben, wird eine Warnung geloggt und die
|
||||||
|
Prüfung übersprungen.
|
||||||
|
3. Danach wird die ursprüngliche Signatur entfernt und durch eine Signatur
|
||||||
|
mit dem mirror-eigenen Key ersetzt (`rpmsign --resign`).
|
||||||
|
4. Alle generierten Client-`.repo`-Dateien verweisen auf denselben Key
|
||||||
|
(`${CLIENT_BASE_URL}/RPM-GPG-KEY-mirror`) — unabhängig davon, wie viele
|
||||||
|
Quellen gespiegelt werden.
|
||||||
|
|
||||||
|
**`gpgcheck` und `repo_gpgcheck`:** Die generierte `.repo`-Datei setzt beide
|
||||||
|
auf `1`:
|
||||||
|
- `gpgcheck=1` prüft beim Installieren die Signatur **jedes einzelnen RPM**
|
||||||
|
gegen den Mirror-Key.
|
||||||
|
- `repo_gpgcheck=1` prüft zusätzlich die Signatur der **Repo-Metadaten
|
||||||
|
selbst** (`repodata/repomd.xml.asc`, ein detached signature). Ohne das
|
||||||
|
könnte jemand mit Schreibzugriff auf den Webserver/die Leitung
|
||||||
|
theoretisch die Paketliste manipulieren (z.B. ein älteres, verwundbares
|
||||||
|
Paket als aktuell ausgeben oder Einträge entfernen), ohne dass eine
|
||||||
|
einzelne RPM-Signatur berührt würde — `repo_gpgcheck` schließt genau diese
|
||||||
|
Lücke.
|
||||||
|
|
||||||
|
`sync.sh` signiert `repomd.xml` nach jedem Lauf neu (nachdem `createrepo_c`
|
||||||
|
und `modifyrepo_c` fertig sind, da beide die Datei noch verändern) mit
|
||||||
|
demselben Mirror-Key, den auch die Pakete tragen — Clients brauchen also
|
||||||
|
weiterhin nur den einen `RPM-GPG-KEY-mirror`.
|
||||||
|
|
||||||
|
**Wichtig zur Aufbewahrung des privaten Schlüssels:** `GPG_HOME`
|
||||||
|
(Default: `${WORK_DIR}/gnupg`) enthält den privaten Signierschlüssel und darf
|
||||||
|
**niemals** über nginx/den Webserver erreichbar sein — im mitgelieferten
|
||||||
|
Docker-Setup liegt er bewusst auf dem `sync-cache`-Volume, das *nicht* in den
|
||||||
|
`nginx`-Container gemountet wird, nur `repo-data` (die öffentlichen Dateien)
|
||||||
|
ist das. Wer Lesezugriff auf `GPG_HOME` hat, kann Pakete als euer Mirror
|
||||||
|
signieren — entsprechend schützen (Backups, Zugriffsrechte).
|
||||||
|
|
||||||
|
`GPG_HOME` muss auf persistentem Speicher liegen: wird es gelöscht, erzeugt
|
||||||
|
das Skript beim nächsten Lauf einen neuen Schlüssel, und alle Clients müssen
|
||||||
|
den neuen öffentlichen Key erneut importieren.
|
||||||
|
|
||||||
|
### Revocation-Zertifikat
|
||||||
|
|
||||||
|
Da der Mirror-Key mit `expire=never` erzeugt wird, gibt es kein automatisches
|
||||||
|
Ablaufdatum, über das ein kompromittierter Key von selbst "entschärft" würde.
|
||||||
|
Deshalb erzeugt `sync.sh` beim allerersten Lauf zusammen mit dem Schlüssel
|
||||||
|
auch ein **Revocation-Zertifikat** unter `GPG_HOME/revocation-cert.asc` — das
|
||||||
|
ist die einzige Möglichkeit, den Key später für ungültig zu erklären, falls
|
||||||
|
der private Schlüssel jemals kompromittiert wird.
|
||||||
|
|
||||||
|
**Direkt nach dem ersten Start aus dem Container herausholen und offline
|
||||||
|
sichern:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose cp syncer:/var/cache/rpm-mirror-sync/gnupg/revocation-cert.asc \
|
||||||
|
./mirror-key-revocation-cert.asc
|
||||||
|
```
|
||||||
|
|
||||||
|
(Pfad anpassen, falls ihr `WORK_DIR`/`GPG_HOME` in `.env` geändert habt.)
|
||||||
|
Das Zertifikat danach an einem Ort außerhalb des Docker-Hosts aufbewahren
|
||||||
|
(Passwort-Safe, Offline-Backup o.ä.) — nicht im selben Ordner wie der
|
||||||
|
private Key selbst, sonst bringt es im Kompromittierungsfall nichts. Das
|
||||||
|
Skript loggt den Hinweis beim ersten Lauf zusätzlich in `sync.log`.
|
||||||
|
|
||||||
|
Kommt der Ernstfall, importiert ihr das Zertifikat auf einer Maschine mit
|
||||||
|
Zugriff auf `GPG_HOME` (`gpg --homedir ... --import mirror-key-revocation-cert.asc`),
|
||||||
|
exportiert den nun als widerrufen markierten Public Key erneut nach
|
||||||
|
`REPO_BASE_DIR/RPM-GPG-KEY-mirror` und verteilt ihn an alle Clients — dnf/rpm
|
||||||
|
lehnen mit einem widerrufenen Schlüssel signierte Pakete danach ab.
|
||||||
|
|
||||||
|
## Wie die Sichtbarkeit in Discover/GNOME Software gesteuert wird
|
||||||
|
|
||||||
|
`createrepo_c` erzeugt Repo-Metadaten für **alle** im Zielverzeichnis
|
||||||
|
liegenden RPMs (nötig, damit `dnf install` Abhängigkeiten auflösen kann).
|
||||||
|
GNOME Software/Discover zeigt aber nur Pakete an, für die es
|
||||||
|
AppStream-Komponenten-Metadaten gibt. Diese werden vom Skript **nur** für
|
||||||
|
die explizit unter `packages:` gelisteten Namen erzeugt (nicht für
|
||||||
|
mitgezogene Abhängigkeiten) und per `modifyrepo_c --mdtype=appstream` in
|
||||||
|
die Repo-Metadaten injiziert.
|
||||||
|
|
||||||
|
**Einschränkung:** Es werden nur "generic" AppStream-Komponenten erzeugt
|
||||||
|
(kein Icon, keine Screenshots, keine `.desktop`-Datei — die liefert das
|
||||||
|
Originalpaket nicht mit). Das reicht, damit ein Paket in Discover
|
||||||
|
installierbar ist und in der Suche auftaucht, aber es erscheint **nicht**
|
||||||
|
auf der kuratierten "Entdecken"-Startseite von GNOME Software — das ist ein
|
||||||
|
Verhalten von GNOME Software/appstreamcli, das sich über Repo-Metadaten
|
||||||
|
allein nicht ändern lässt.
|
||||||
|
|
||||||
|
## Repo auf Clients einbinden
|
||||||
|
|
||||||
|
Alle Quellen landen in **einem einzigen** kombinierten Repo unter
|
||||||
|
`REPO_BASE_DIR/pkgs/` — egal wie viele Einträge eure `sources.yaml` hat.
|
||||||
|
Entsprechend gibt es auch nur **eine** Client-`.repo`-Datei:
|
||||||
|
`CLIENT_REPO_DIR/mirror.repo` (Default: `/srv/repo/client-repos/mirror.repo`,
|
||||||
|
über nginx erreichbar unter `/repo/client-repos/mirror.repo`).
|
||||||
|
|
||||||
|
**Einbinden auf einem Client — ein Kommando, ein Repo:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL http://<host>:8080/repo/client-repos/mirror.repo \
|
||||||
|
-o /etc/yum.repos.d/rpm-mirror.repo
|
||||||
|
dnf makecache
|
||||||
|
```
|
||||||
|
|
||||||
|
Das war's — egal ob ihr später weitere Quellen zur `sources.yaml`
|
||||||
|
hinzufügt, die Client-Konfiguration bleibt unverändert (`baseurl` und
|
||||||
|
`gpgkey` ändern sich nicht, nur der Inhalt des Repos wächst). Für die
|
||||||
|
Verteilung an viele Clients eignet sich dasselbe `curl`-Kommando in
|
||||||
|
Ansible/Config-Management oder einem Kickstart-Postscript.
|
||||||
|
|
||||||
|
`https://<host>/repo` selbst (ohne `/pkgs/`) ist weiterhin **kein** dnf-Repo,
|
||||||
|
sondern nur ein Verzeichnis-Listing (nginx `autoindex`) — `baseurl` muss auf
|
||||||
|
`/repo/pkgs/` zeigen (das steht schon so in der generierten
|
||||||
|
`mirror.repo`, ihr müsst daran nichts anpassen).
|
||||||
|
|
||||||
|
**Namenskonflikte:** Da jetzt alle Quellen in ein gemeinsames Verzeichnis
|
||||||
|
spiegeln, dürfen zwei Quellen keine RPMs mit demselben Paketnamen aber
|
||||||
|
unterschiedlichem Inhalt liefern (identische NEVRA aus zwei Quellen ist
|
||||||
|
unproblematisch, das ist einfach dasselbe Paket). Achtet bei mehreren
|
||||||
|
Drittanbieter-Repos in einer `sources.yaml` auf eindeutige Paketnamen.
|
||||||
|
|
||||||
|
## Dateien
|
||||||
|
|
||||||
|
- `sync.sh` — Hauptskript
|
||||||
|
- `sync_helpers.py` — YAML-Parsing & AppStream-XML-Generierung (muss im
|
||||||
|
selben Verzeichnis wie `sync.sh` liegen)
|
||||||
|
- `sources.example.yaml` — Beispiel-Quellenliste
|
||||||
|
- `docker-compose.yml`, `.env.example`, `docker/` — Container-Setup (siehe unten)
|
||||||
|
|
||||||
|
## Docker-Setup
|
||||||
|
|
||||||
|
Zwei Container:
|
||||||
|
|
||||||
|
- **syncer** — AlmaLinux 10 Image, führt `sync.sh` beim Start und danach alle
|
||||||
|
`SYNC_INTERVAL_SECONDS` erneut aus (einfache Sleep-Loop, kein Cron/systemd
|
||||||
|
im Container). Schreibt nach `/srv/repo` (benanntes Volume `repo-data`).
|
||||||
|
- **nginx** — liefert `repo-data` read-only unter `http://<host>:${NGINX_PORT}/repo/`
|
||||||
|
mit Directory-Listing aus, inklusive `client-repos/` für die fertigen
|
||||||
|
`.repo`-Dateien.
|
||||||
|
|
||||||
|
### Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# .env anpassen: mindestens CLIENT_BASE_URL und ALMA_REPO_IDS prüfen
|
||||||
|
docker compose up -d --build
|
||||||
|
docker compose logs -f syncer
|
||||||
|
```
|
||||||
|
|
||||||
|
**`.env` ist die einzige Konfigurationsquelle:** `docker-compose.yml` selbst
|
||||||
|
enthält keine hartkodierten Umgebungsvariablen oder Defaults mehr — beide
|
||||||
|
Container laden alles per `env_file: .env`. Wer etwas ändern will (Pfade,
|
||||||
|
Sync-Intervall, Client-URL, Signier-Identität, Port, ...), bearbeitet
|
||||||
|
ausschließlich `.env` und macht `docker compose up -d`, ohne `docker-compose.yml`
|
||||||
|
anzufassen.
|
||||||
|
|
||||||
|
Danach ist das (eine, kombinierte) Repo erreichbar unter
|
||||||
|
`http://localhost:8080/repo/pkgs/` und die eine Client-`.repo`-Datei unter
|
||||||
|
`http://localhost:8080/repo/client-repos/mirror.repo`.
|
||||||
|
|
||||||
|
### Eigene Quellenliste einbinden
|
||||||
|
|
||||||
|
**Lokale Datei (Standard):** `LOCAL_SOURCES_YAML` in `.env` auf den Pfad
|
||||||
|
eurer echten `sources.yaml` setzen (relativ zum `docker-compose.yml`), z.B.
|
||||||
|
`LOCAL_SOURCES_YAML=./sources.yaml`. Wird read-only nach
|
||||||
|
`/config/sources.yaml` im Container gemountet.
|
||||||
|
|
||||||
|
**Git-Repo statt lokaler Datei:** `SOURCES_GIT_REPO`, `SOURCES_GIT_BRANCH`
|
||||||
|
und `SOURCES_YAML_FILE` (Pfad *innerhalb* des Git-Repos, relativ) in `.env`
|
||||||
|
setzen. Der Bind-Mount aus der lokalen Variante wird dann schlicht ignoriert.
|
||||||
|
|
||||||
|
### Einmaliger Sync statt Dauerlauf
|
||||||
|
|
||||||
|
`RUN_ONCE=true` in `.env` setzen — der `syncer`-Container synct dann einmal
|
||||||
|
und beendet sich, statt in der Schleife zu laufen. Praktisch, wenn ihr den
|
||||||
|
Sync lieber über einen externen Scheduler (Kubernetes CronJob, systemd-Timer
|
||||||
|
mit `docker compose run`, etc.) anstoßen wollt.
|
||||||
|
|
||||||
|
### ALMA_REPO_IDS prüfen
|
||||||
|
|
||||||
|
Die repoids im Container können von einer bare-metal-Installation abweichen.
|
||||||
|
Nach dem ersten Start prüfen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec syncer dnf repolist
|
||||||
|
```
|
||||||
|
|
||||||
|
und `ALMA_REPO_IDS` in `.env` entsprechend anpassen, dann
|
||||||
|
`docker compose up -d` erneut ausführen.
|
||||||
|
|
||||||
|
### Persistenz
|
||||||
|
|
||||||
|
- `repo-data` (Volume) — die gespiegelten Repos selbst; das ist auch, was
|
||||||
|
nginx ausliefert.
|
||||||
|
- `sync-cache` (Volume) — Arbeitsverzeichnis von `sync.sh`
|
||||||
|
(`WORK_DIR`, u.a. Logs unter `sync.log`).
|
||||||
|
|
||||||
|
Beide überleben `docker compose down`; erst `docker compose down -v` löscht
|
||||||
|
sie.
|
||||||
Reference in New Issue
Block a user