概括

概括

概括

请注意version-specific问题标题!这个问题是不是, 如何

  1. 在一台 Debian 主机上,捕获所有已安装软件包的列表。
  2. 在另一台 Debian 主机上,安装列出的软件包的最新版本。

这个问题更确切地说是如何

  1. 在某个时间点的 Debian 主机上,
    1. 捕获一个包裹地图含有
      • 每个已安装包的名称
      • 当前安装的每个软件包的版本
    2. ... 所需的任何附加数据
  2. 稍后在同一主机上恢复包映射,以便随后
    1. 仅安装包映射中的包
    2. 对于地图中的每个包,仅安装适当的版本

细节

动机

最近,我对我的一个 Debian 机器进行了一次“大更新”(即涉及大量软件包或内核等主要软件包,或两者兼而有之),但它没有“干净地”更新(即没有重大问题)。将来,当我对 Debian 机器应用错误更新时,我希望能够回滚(A)包裹放在同一个盒子上(二)到以前的版本。 (之前没有进行图像备份,这很慢。)不幸的是我不知道该怎么做。我知道怎么

  1. 在一个 Debian 机器上,捕获其已安装软件包集中的每个软件包名称的列表。
  2. 在另一个框中,安装列表中每个软件包的最新版本。

感谢许多讨论如何做到这一点的网页,包括几个 SE。大多数(包括,, 和)做或多或少复杂的变化

  1. 备份: dpkg --get-selections > ${PACKAGE_LIST_FILEPATH}
  2. 恢复: dpkg --set-selections < ${PACKAGE_LIST_FILEPATH}

关于这个主题的最全面的(也是最有脚本化的,我更喜欢的)SE 可能是这个:它是少数建议同时备份存储库列表(使用cp -R /etc/apt/sources.list*)和存储库密钥(使用apt-key exportall)的方法之一,但它也使用dpkg上述方法。这个SE建议使用aptitude(FWIW,我更喜欢,并且怀疑比dpkg) 进行备份和安装,并且这个SE建议deborphan进行备份。

但以上都没有保存包版本,所以没有一个适合我的用例。 (IIUC——我错过了什么吗?)

假设

显然,人们必须从自己的设备备份(并能够根据需要恢复)任意文件。同样,人们应该能够备份/恢复软件包,并将其集成到定期运行的备份工具中。幸运的是,包列表的备份/恢复是很好理解的。可以使用bash以下代码进行备份

## setup

PACKAGE_LIST_FILENAME='package.list'         # see use below
REPO_KEYS_FILENAME='repo.keys'               # ditto
DATE_FORMAT="%Y%m%d_%H%M%S"
BACKUP_TIMESTAMP="$(date +${DATE_FORMAT})"   # get current timestamp, to the second

# Parent directory of that to which you will backup.
BACKUP_ROOT="/media/$(whoami)/my_backup_drive"
BACKUP_DIR="${BACKUP_ROOT}/backup_${BACKUP_TIMESTAMP}"
echo -e "Backing up to ${BACKUP_DIR}" # debugging
# TODO: check BACKUP_DIR is writable, has sufficient freespace, etc

# ASSERT: all following are subdirs of BACKUP_DIR
ETC_BACKUP_DIR="${BACKUP_DIR}/etc"           # backup /etc , typically not large
PKG_BACKUP_DIR="${BACKUP_DIR}/packages"
REPO_BACKUP_DIR="${BACKUP_DIR}/repos"   # duplicates some of /etc, but disk is cheap ...
for DIR in \
  "${ETC_BACKUP_DIR}" \
  "${PKG_BACKUP_DIR}" \
  "${REPO_BACKUP_DIR}" \
; do
  # make the backup dirs
  mkdir -p "${DIR}"  # TODO: test retval/errorcode, exit on failure
done

PACKAGE_LIST_FILEPATH="${PKG_BACKUP_DIR}/${PACKAGE_LIST_FILENAME}"
touch "${PACKAGE_LIST_FILEPATH}"             # TODO: check that it's writable, exit if not

REPO_KEYS_FILEPATH="${REPO_BACKUP_DIR}/${REPO_KEYS_FILENAME}"
touch "${REPO_KEYS_FILEPATH}"                # TODO: check that it's writable, exit if not

## backup
## TODO: for all following: test retval/errorcode, exit on failure
## TODO: give user some progress indication (e.g., echo commands)

deborphan -a --no-show-section > "${PACKAGE_LIST_FILEPATH}" # or other op you prefer
sudo cp -R /etc/apt/sources.list* "${REPO_BACKUP_DIR}/"
sudo apt-key exportall > "${REPO_KEYS_FILEPATH}"
rsync --progress /etc "${ETC_BACKUP_DIR}"

并且可以使用例如bash类似的代码进行恢复

## setup
## (remember to transfer constants used above)

RESTORE_DIR="set this equal to the BACKUP_DIR from which you are restoring!"
ETC_RESTORE_DIR="${RESTORE_DIR}/etc"
PKG_RESTORE_DIR="${RESTORE_DIR}/packages"
REPO_RESTORE_DIR="${PKG_RESTORE_DIR}/repos"
PACKAGE_LIST_FILEPATH="${PKG_RESTORE_DIR}/${PACKAGE_LIST_FILENAME}"
REPO_KEYS_FILEPATH="${REPO_RESTORE_DIR}/${REPO_KEYS_FILENAME}"

## restore
## TODO: test that all following are readable, exit if not
## TODO: for all following: test retval/errorcode, exit on failure
## TODO: give user some progress indication (e.g., echo commands)

rsync --progress "${ETC_BACKUP_DIR}" /etc
# following will overwrite some of /etc restored above
sudo apt-key add "${REPO_KEYS_FILEPATH}"
sudo cp -R "${REPO_RESTORE_DIR}/sources.list*" /etc/apt/
# TODO: CHECK THIS SYNTAX!
# see my question @ https://serverfault.com/questions/56848/install-the-same-debian-packages-on-another-system/61472#comment920243_61472
sudo xargs aptitude --schedule-only install < "${PACKAGE_LIST_FILEPATH}" ; aptitude install

所以IIUC,我们必须扩展上面的内容来处理包版本。使用如下策略似乎是可行的:

备份

  1. 编写一个包映射文件,而不是包列表文件。感谢罗伯特·LCAS,我现在知道我可以以一种有用的格式获取 Debian 主机的包映射文件(每行一个包,每行包含{包名称(和体系结构,但仅当多个)、TAB、包版本字符串}然后就可以访问了。
    • 包名与awk '{print $1}' < "${PACKAGE_LIST_FILEPATH}"
    • 软件包版本awk '{print $2}' < "${PACKAGE_LIST_FILEPATH}"
  2. (额外学分)归档原始/包的当前版本.deb(如由cas表示)通过将包名称提供给dpkg-repack.
  3. (额外学分)将存档的包转换为本地 APT 存储库。希望这能在操作细节中得到描述这个 Debian 维基页面,但我仍在努力弄清楚这一点。

恢复

词汇表: *current指用户尝试恢复之前主机的状态。 *current PMF指为当前主机生成的包映射文件,包含包元组(键=包名称,值=包版本)当前已安装。 *backup PMF指之前某个时间为主机生成的包映射文件,包含要恢复的包元组。

  1. 创建当前 PMF。
  2. 通过“通常的方式”恢复存储库和密钥(见上文)。
  3. 读取备份 PMF。
  4. 对于当前 PMF 中而非备份 PMF 中的每个包元组:卸载该包(例如sudo aptitude remove [package_name])。
  5. 对于备份 PMF 中的每个包元组:安装给定版本的包(例如sudo aptitude install [package_name]=[package_version])。谢谢瑞·F·里贝罗比格本奥古斯特感谢您的关注aptitudeapt-get支持install package=version
    • (额外学分)如果恢复的存储库不包含所需版本的软件包,请从备份本地 APT 存储库安装它。

测试

去做!我将首先对一个盒子进行手动恢复,我还没有像上面这样的备份(当然,因为我还没有像上面这样的备份)任何框:-)但我有控制台喷出

答案1

一些有用的注释可以帮助您实现目标:

  1. 您可以通过运行以下命令来获取已安装软件包及其版本的列表:

    dpkg-query -W
    
  2. dpkg-repack您可以通过安装并运行如下命令来创建所有当前安装的软件包的 .deb 软件包的存档:

    dpkg-query -W | awk '{print $1}' | xargs dpkg-repack
    

    这将是dpkg-repack所有当前安装的软件包。此存档是恢复过程中缺少的关键部分 - 没有它,您可能无法恢复完全相同的包集(特别是如果您使用testingunstable)。

    警告:dpkg-repack重新包装所有内容的当前内容(可能已修改)配置文件。如果您想要原始的原始软件包,则必须从/var/cache/apt/archivesDebian 镜像获取 .deb 文件。

    可以按照以下说明将 .deb 存档转换为 apt-gettable 存储库:https://wiki.debian.org/HowToSetupADebianRepository或者您可以将它们全部安装dpkg -iBE *.deb(或者dpkg -iRBE /path/to/deb/files/如果太多而无法在一个命令行中安装)。

  3. 您仍然需要使用-get-selections--set-selections来保留已卸载的软件包等详细信息。

答案2

经过一番努力后,我想出了下面的方法,它是几种不同方法的组合

快照所有已安装的具有确切 debian 名称的软件包

dpkg --list | awk '/^ii/ { print $2,$3,$4 ;}'| tr ' ' '_'| tr '\t' '_'| sed 's/$/.deb/g'| sed 's|:amd64||g'| sort -u > dpkg_query_pkgs.txt

清理你的 apt 缓存并重新下载所有已安装的软件包,这样它们就不会出现多个版本。

apt-get clean; dpkg -l | grep "^ii"| awk ' {print $2} ' | xargs sudo apt-get -y install --reinstall --download-only

或者显式传递当前安装的版本

apt-get clean; dpkg --list | awk '/^ii/ { print $2"="$3 ;}'| xargs sudo apt-get -y install --reinstall --download-only ;

从存档中快照安装的 deb

ls -1 /var/cache/apt/archives| grep deb|sed 's|\%3a|:|g' | sort -u > apt_archives_pkgs.txt

然后你可以确认已安装的 debs 与档案

diff -y apt_archives_pkgs.txt dpkg_query_pkgs.txt

这允许您测试是否可以从 dpkg --list 中导出确切的名称,并且它将与 apt 缓存存档中的名称相匹配。

答案3

您可以使用apt-clone

  1. 安装它sudo apt install apt-clone

  2. 运行apt-clone clone filename以创建一个小型存档filename.apt-clone.tar.gz,其中仅包含对已安装包名称和版本的引用。加上 APTsources.list文件、APT 密钥环和其他信息,以便稍后在相同版本中恢复相同的软件包配置。

  3. 在目标系统(如果用于备份目的,可能是同一系统)上,运行sudo apt-clone restore filename.apt-clone.tar.gz以恢复系统状态。

附加提示:

  • 包括包裹。使用 创建克隆时apt-clone clone --with-dpkg-repack filename,克隆归档文件还将包含在软件包归档文件中找不到的手动安装的软件包的 .deb 文件,以及在软件包归档文件中仍然可用但在已安装的软件包中不存在的软件包的 .deb 文件。版本。这些 .deb 文件是从已安装的文件中重新打包的,因此原始 .deb 文件不必可用。

  • “版本不匹配”。有时,apt-clone clone会抱怨某些软件包的版本不匹配。这些包仍然包含在克隆中并将被恢复,只是不是完全相同的版本。不确定是否以及如何解决这个问题。

  • 没有长期备份。当克隆和从克隆恢复之间的时间差很小时(可能是几小时到几周)时,此工具最有用。如果您想将系统恢复到其确切状态,则它不适合长期系统备份。这是因为apt-clone使用对包名称和版本的引用,并且某些包版本可能会从包存档中消失,甚至整个 PPA 包存档也可能会消失。

  • 文档。 apt-clone --help提供有关其他可用选项的准确信息,但man apt-clone略有过时。

相关内容