CentOS und Ubuntu repositories mirroren

Nicht nur bei Systemen die vom Internet abgeschottet sind macht das anlegen eines lokalen mirrors (spiegeln) eines CentOS (RedHat) oder Ubuntu repositories Sinn. Man kann dann z.B. auch einzelne Versionsstände „einfrieren“, so dass diese während einem Zeitraum immer dieselben Paket haben und dann etwa quartalsweise aktualisieren.
In diesem Beitrag lernt ihr alles was es zum spiegeln der beiden repositories braucht, wie ihr Repositories einzelner Pakte anlegt und wie ihr unterschiedliche Versionsstände verwalten könnt.

Grundsätzlich braucht es für RPM und DEB basierte repositories unterschiedliche tools, da diese verschieden aufgebaut sind.

Inhalt

Mirror eines RPM (Redhat) repositories

Ein RPM repository kann mit rsync synchronisiert werden. Danach muss noch der GPG Public Key mit wget heruntergleaden werden:

rsync  -avSHP --delete rsync://linuxsoft.cern.ch/centos/8 "/srv/repository/centos/8/"
wget -P /srv/repository/centos/8/ wget https://www.centos.org/keys/RPM-GPG-KEY-CentOS-Official

Nachfolgend ein Script, welches das aktuelle CentOS und EPEL repository synchronisiert und zudem noch z.B. die ISOs ausschliesst und täglich per cronjob aufgerufen werden kann:

mirror-sync-centos.sh

#!/bin/bash
set -euo pipefail

### CentOS
centosdir=/srv/repository/current/centos
rsync_lock_prefix=/var/run/rsync_updates_centos
rsync_url=rsync://linuxsoft.cern.ch/centos

if [ -f ${rsync_lock_prefix} ]; then
  logger -i -t "$0" -p INFO "Updates via rsync for CentOS already running."
else
  if [ -d ${centosdir} ] ; then
    logger -i -t "$0" -p INFO "touch ${rsync_lock_prefix}";
    touch ${rsync_lock_prefix};

    if [ $? != 0 ]; then
      logger -i -t "$0" -p INFO "exit 1"
      exit 1
    fi

    logger -i -t "$0" -p INFO "/usr/bin/rsync --bwlimit=4m -avSHP --delete --exclude \"local*\" --exclude \"isos\" ${rsync_url}/ ${centosdir}/;";
    /usr/bin/rsync --exclude="local*" --exclude="isos" --exclude="altarch" --exclude="*aarch64*" --exclude="playground" -avSHP --delete ${rsync_url}/ ${centosdir}/;
    logger -i -t "$0" -p INFO "/bin/rm -f ${rsync_lock_prefix}";
    /bin/rm -f ${rsync_lock_prefix};
  else
    logger -i -t "$0" -p INFO "Target directory ${centosdir} not present."
  fi
fi



### EPEL
epeldir=/srv/repository/current/epel
epel_rsync_lock_prefix=/var/run/rsync_updates_epel
epel_rsync_url=rsync://linuxsoft.cern.ch/epel

if [ -f ${epel_rsync_lock_prefix} ]; then
  logger -i -t "$0" -p INFO "Updates via rsync for EPEL already running."
else
  if [ -d ${epeldir} ] ; then
    logger -i -t "$0" -p INFO "touch ${epel_rsync_lock_prefix}";
    touch ${epel_rsync_lock_prefix};

    if [ $? != 0 ]; then
      logger -i -t "$0" -p INFO "exit 1"
      exit 1
    fi

    logger -i -t "$0" -p INFO "/usr/bin/rsync --bwlimit=4m -avSHP --delete --exclude \"local*\" --exclude \"isos\" ${epel_rsync_url}/ ${epeldir}/;";
    /usr/bin/rsync --exclude="local*" --exclude="isos" --exclude="playground" -avSHP --delete ${epel_rsync_url}/ ${epeldir}/;
    logger -i -t "$0" -p INFO "/bin/rm -f ${epel_rsync_lock_prefix}";
    /bin/rm -f ${epel_rsync_lock_prefix};
  else
    logger -i -t "$0" -p INFO "Target directory ${epeldir} not present."
  fi
fi

Mirror eines RPM Paket repositories

Repositories einzelner Pakete (z.B. icinga2) kann man mit dem Tool reposync mirroren.

Das tool setze ein installiertes yum voraus; der Paketmanager „yum“ kann jedoch auch auf Debian/Ubuntu installiert werden (apt install yum).

Dann kann man anhand der in yum konfigurierten Repositories ein Paket spiegeln:

/etc/yum.repos.d/icinga2.repo

[icinga-stable-release-8]
name=ICINGA (stable release)
baseurl=https://packages.icinga.com/epel/$releasever/release/
enabled=1
gpgcheck=1
gpgkey=https://packages.icinga.com/icinga.key

repo-sync

reposync -q --config=/etc/yum/yum.conf --repoid=icinga-stable-release --plugins --newest-only --downloadcomps --download-metadata --norepopath --download_path=/srv/repos/icinga2/epel/8/release

createrepo -q /srv/repos/icinga2/centos/8/release

wget -N -q 'https://packages.icinga.com/icinga.key' -O /srv/repos/icinga2/icinga.key

Da man dies dann regelmässig aufruft empfihelt es sich ein kleines Script dafür zu erstellen:

mirror-sync-icinga2.sh

#!/bin/bash

SOFTWARE="icinga2"
REPO_BASE=/srv/repos/${SOFTWARE}

mkdir -p ${REPO_BASE}/epel
ln -sv ${REPO_BASE}/epel ${REPO_BASE}/centos
wget -N -q 'https://packages.icinga.com/icinga.key' -O $REPO_BASE/icinga.key

for REPOID in $(grep -oP '\[\K[^][]*(?=])' /etc/yum.repos.d/${SOFTWARE}.repo); do
  REPO_VERSION=$(echo $REPOID | egrep -o '[[:digit:]]{1}' | head -n1)
  if [ ! -z "$REPO_VERSION"  ]; then
    logger -t mirror.${SOFTWARE}[$$] "Updating $REPOID (to: $REPO_BASE/epel/$REPO_VERSION/release)"
    reposync -q --config=/etc/yum/yum.conf --repoid=$REPOID --plugins --newest-only --downloadcomps --download-metadata --norepopath --download_path=$REPO_BASE/epel/$REPO_VERSION/release
    createrepo -q ${REPO_BASE}/centos/${REPO_VERSION}/release
    logger -t mirror.${SOFTWARE}[$$] "Finished $REPOID"
  else
    logger -t mirror.${SOFTWARE}[$$] "Invalid version for repoid: $REPOID (name repoid in the format repo-name-VERSION; i.ex. icinga-stable-release-8)"
  fi
done

Das Script spiegelt automatisch jedes release repository, welches in /etc/yum.repos.d/icinga2.repo nach dem format: name-release aufgeführt ist, also z.B.: icinga-stable-release-7, icinga-stable-release-8, usw.

Mirror eines DEB (Debian) repositories

Um das ganze Repository zu mirroren wird unter Debian/Ubuntu apt-mirror verwendet.

apt-get install apt-mirror

In /etc/apt/mirror.list können dann die Einstellungen vorgenommen werden.

Danach startet man den mirror Vorgang mit:

apt-mirror

Achtung: Durch apt-mirror entsteht beim ersten Start ein enormes Datenvolumen! Ubuntu belegt zur Zeit ca. 60 GiB / Architektur OHNE Quellcode-Pakete!

Mirror eines DEB Paket repositories

Ein DEB Paket repository kann man mit dem Tool debmirror anlegen. Am besten macht man sich dann ein flexibeles Script für mehrere Repositories.

Nachfolgend ein Beispiel für icinga2 und mariadb

repo-mirror.sh

#!/bin/bash

mirror_icinga2() {
  method=https
  product=icinga2
  localpath="/srv/repos/$product"
  mirr=packages.icinga.com
  rootpath="ubuntu"
  distri="icinga-bionic,icinga-focal,icinga-jammy"
  section="main"
  arch="amd64,i386"
  options="--no-check-gpg --ignore-release-gpg --postcleanup --diff=none --rsync-extra=none --verbose"
  logger -t mirror[$$] Updating $mirr $rootpath ${distri} ${section}

  debmirror --progress --nosource --host=${mirr} --root=${rootpath} --method=$method --dist=${distri} -section=${section} --arch=${arch} $options $localpath
  mkdir -p /srv/repos/keys/$product
  wget -q 'https://packages.icinga.com/icinga.key' -O /srv/repos/keys/$product/public
  return_code=$?
  logger -t mirror[$$] Finished $mirr $rootpatha ${distri} ${section}
  return $return_code
}

mirror_mariadb105() {
    method=http
    product=mariadb105
    localpath="/srv/repos/$product"
    mirr=mirror.mva-n.net
    rootpath="/mariadb/repo/10.5/ubuntu"
    distri="bionic,focal"
    section="main"
    arch="amd64"
    options="--ignore-missing-release --no-check-gpg --ignore-release-gpg --postcleanup --diff=none --rsync-extra=none --verbose"
    logger -t mirror[$$] Updating $mirr $rootpath ${distri} ${section}

            debmirror $localpath --progress --method=$method        \
            --host=${mirr} --root=${rootpath} --dist=${distri}                      \
            --section=${section} --arch=${arch} \
            $options
    return_code=$?
    logger -t mirror[$$] Finished $mirr $rootpatha ${distri} ${section}
    return $return_code
}


if [ -n "$1" ]; then
    mirror_$1
else
    echo "`date`: Mirroring started" > /srv/repos/mirror.log
    for app in icinga2 mariadb105; do
        if mirror_$app; then
            echo "`date`: $app _OKAY_" >> /srv/repos/mirror.log
        else
            echo "`date`: $app _ERROR_" >> /srv/repos/mirror.log
        fi
    done
fi

exit $?

Automatische Versionsstände erstellen

Wenn man ein eigenes Repository hat, möchte man meist auch, dass die Versionsstände auf allen Servern über einen bestimmten Zeitraum gleich sind. Man erstellt dann einfach z.B. jedes Quartal, oder Kalenderwoche eine neue „Version“ des repositories.

Was im Red Hat Satellite Server mittels Content-Views möglich ist, geht auch bei z.B. CentOS oder Ubuntu repositories mit einem Shellscript:

repo_version.sh

year=`date +%Y`
kw=`date +%V`
quarter=$(( ($(date +%-m)-1)/3+1 ))

repodir=/srv/repository
repodir_current=${repodir}/current
repodir_kw=${repodir}/${year}/${kw}
repodir_quarter=${repodir}/${year}/q${quarter}

logger -i -t "$0" -p INFO "Syncing current repo to calendar week ${kw}"
mkdir -p ${repodir}/${year}
if [ ! -d ${repodir_kw} ]; then
  logs "cp -al ${repodir_current} ${repodir_kw}"
  cp -al ${repodir_current} ${repodir_kw}
fi

logger -i -t "$0" -p INFO "/usr/bin/rsync -a --delete ${repodir_current}/* ${repodir_kw}"
rsync -a --delete ${repodir_current}/* ${repodir_kw}

logger -i -t "$0" -p INFO "syncing current repo to quartal repo ${q}"
if [ ! -d ${repodir_q} ]; then
  logger -i -t "$0" -p INFO "cp -al ${repodir_current} ${repodir_q}"
  cp -al ${repodir_current} ${repodir_q}
else
  logger -i -t "$0" -p INFO "${repodir_q} exists. nothing to do"
fi

Zuerst wird mittels dem cp -al Kommando das Verzeichnis von curretn kopiert, aber mittels hardlinks (-l Paramater). Das ist wichtig weil sonst der benötigte Speicherplatz mit jeder Version um X GB ansteigen würde. Mittels Hardlinks wird pro Datei immer nur einmal der Speicherplatz verbraucht, egal, wie viele „Kopien“ davon existieren.

Mittels rsync kann man dann noch ggf. geänderte Dateien als neue Kopie im Verzeichnis erstellen.

Quellen

Published by

Steven Varco

Steven ist ein Redhat RHCE- und Kubernetes CKA Zertifizierter Linux-Crack und ist seit über 20 Jahren sowohl beruflich wie auch privat auf Linux spezialisiert. In seinem Keller steht ein Server Rack mit diversen ESX und Linux Servern.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert