Linux 的软件管理


Linux的软件管理

一个操作系统平台的发展极大程度上取决于其软件生态的质量。其软件生态系统中软件的多样性、易用性、持久性直接决定了操作系统平台的生命力。一个操作系统平台想要有良好的发展,除了不断改进完善自身、打磨操作系统内功外,必须注重并推动其软件生态系统建设发展。当前常见的主流操作系统,无论基础物理平台是 PC 端还是移动端,如 Windows、Mac OS、Android、IOS 无一例外体现了这一特色。Linux 系统也不例外,植根于开源社区,Linux 构建了自己的软件生态。而对平台生态中的各种软件进行高效管理,则是软件生态发展和建设的关键和基础。

本篇重点对 Ubuntu 的软件管理进行总结梳理。

一、Ubuntu 软件管理对象 — deb 软件安装包

总体而言,软件可以有两种方式提供给用户:

  • 1)源代码形式;
  • 2)软件安装包形式。

源代码形式为用户提供了最大的自主权和灵活性,用户可以自主对软件进行编译、链接,并将软件的文件安装(拷贝)到相关位置,进而启动并运行软件,这种方式对操作系统的软件管理能力要求不高,软件管理本质上更多的由用户自己来把控。显然,这种方式对用户技术能力要求较高,更多针对特定用户,不适合一般大众用户。

软件安装包方式的出现简化了上述问题,它提供了“一站式”的解决方案,将众多编译链接后的文件以及其他相关文件(资源文件等)进行统一集成(也称归档,archive),“打包”成一个文件,通过对集成后的“包”设计统一化的结构,并在操作系统中的设计对应的软件包管理机制,如此,则无需用户深度了解软件管理的具体细节,即可利用软件包和包管理机制来包办软件的安装、卸载、查询等工作。

Ubuntu 中使用的是 deb 格式(结构)的软件包,deb 是 Debian 及其派生操作系统所使用的一种软件包格式。Deb 文件是一种典型的集成包。一般而言,将众多不同类型的文件集成到一起,形成一个统一的包,则一定是一种集成包,常见的 doc 文件、ppt 文件、apk 文件、ipa 文件均是如此。deb 也不例外,deb 是标准的 Unix 系统 ar 归档包(集成包)。除安装文件外,文件包也包括关于这个包的元数据,如软件包及其内容的说明。此外,许多软件包还包括预安装和安装后脚本,这些脚本用来在软件安装前和安装后执行参数和环境配置任务。

具体实现上,deb 文件包一般包含三部分内容:

  • debian-binary: 指出包格式的版本号。
  • control.tar: tar文件,包含控制信息。
  • data.tar: tar文件,包含实际可安装到系统的文件。
deb 文件包是具有典型代表性的“软件安装封装包”,包括
- 软件运行文件(可执行文件、库文件)
- 安装脚本、安装后配置脚本
- 软件包元数据(metadata)
等信息。

(从文件内部组织结构本身的角度讲,deb 包本身也存在文件安全加固的需求,与 android 的 apk 文件包问题类似)

二、Ubuntu 软件管理方法介绍

Ubuntu 管理软件模式主要有基于单个软件的管理模式基于软件仓库(repository)的软件管理模式。软件仓库,顾名思义,即多个软件集成到一起的统一管理的一种方式。

0x21、单个软件管理方法介绍 — 软件管理基础工具

针对单个软件,Ubuntu 使用 dpkg (Debian Package) 工具进行管理。dpkg 也是 Debian 及其派生操作系统底层、基础的软件管理工具。利用 dpkg 对 deb 软件包进行安装、卸载、查看信息等操作。

### RPM 管理工具发行版说明 ###
与 Ubuntu 的 dpkg 对应的,Fedora 使用 rpm (RPM Package Manager) 工具进行软件包管理。
  • 安装软件

    dpkg -i packagename

  • 卸载软件
    • 保守卸载,保留软件的配置文件

      dpkg -r packaganame

      利用该方式卸载软件,通过 dpkg -l 查看软件状态为 rc

      软件状态信息,前一个字母代表 Desired action,后一个字母代表 Package status,如
      - r = Remove
      - c = Config-files
      状态具体含义参见 `man dpkg-query`
      
    • 彻底卸载,同时删除配置文件

      dpkg – – purge packagename

  • 查看软件的基本信息
    ### RPM 管理工具发行版说明 ###
    Fedora 使用 -q (--query) 选项查看软件相关信息
    
    • 查看软件包状态信息

      dpkg -s ( – – status) packaganame

      ### RPM 管理工具发行版说明 ###
      -i (--info) 选项
      rpm -qi packagename
      
    • 查看系统中已安装软件包

      dpkg -l ( – – list)

      ### RPM 管理工具发行版说明 ###
      -a (--all) 选项
      rpm -qa
      
    • 查看软件包中安装到系统中的文件

      dpkg -L ( – – listfiles) packagename

      ### RPM 管理工具发行版说明 ###
      -l (--list) 选项
      查看已安装软件包中的文件列表和安装的完整目录
      rpm -ql packagename
      
      -c (--configfiles)
      查看已安装软件包中的配置文件的位置
      rpm -qc packagename
      
      -d (--docfiles) 选项
      查看已安装软件包中的帮助文档
      rpm -qd packname
      
    • 查看(指令)文件所属的软件包 (反向查询)

      dpkg -S ( – – search) /path/filename

      ### RPM 管理工具发行版对比说明 ###
      ## -f (--file) 选项
      ## 查看指定文件由哪个软件包生成(反向查询)
      rpm -qf /path/filename
      

      dpkg 的 -L-S 是一对作用相反的参数,一个是查看软件包中所包含的文件,一个是查看文件隶属于哪个软件包。

  • 查看软件包的安装、更新与删除的时间信息

    dpkg -s 可以查看软件包的基本状态信息,但这些信息不包括软件包的安装和更新的信息。可以采用查看日志文件的方式来获取。

    当软件包信息发生变更,会将信息存储在 /var/log/dpkg.log 日志文件中。因为变更信息是一个持续增加的量,因此 dpkg.log 也采用了 linux 中通常使用的 “日志轮转机制”,日志增加到一定程度的量以后,旧的日志自动成为 “轮转” 记录,即生成 log.1log.2.gzlog.3.gz 的文件,以保持 .log 文件的 “最新状态”。

    这些 log 文件一般都由 logrotate 工具来控制,会根据配置好的要求,以固定周期对 log 文件进行拆分和压缩,并只保留最新的一部分 log,从而避免 log 文件占用太多的存储空间。

    dpkg 的 log “轮转” 日志记录包含了各个软件包的安装与更新的记录,通过查看轮转记录,就可以查看各个软件包的安装与更新的信息。

    可以使用 grep/more/less/cat 等工具直接查看非压缩的 log 文本文件的内容;使用 zcommands,即 zgrep/zmore/zless 等工具搜索或查看压缩的 log 日志文件(即 .log.number.gz)的内容。

    zgrep installed/upgrade/remove /var/log/dpkg.log.5.gz

    zmore /var/log/dpkg.log.5.gz

    zless /var/log/dpkg.log.5.gz

Ubuntu 的软件管理工具需要相关的 “数据库” 支持,dpkg 的基本数据在 /var/lib/dpkg 文件夹内;dpkg 的安装与更新记录在 /var/log/dpkg* 等文件中。

0x22、基于远程仓库的软件管理方式介绍

随着当前软件复杂程度以及软件工程模块化的不断提升,现代软件代码的封装组织方式,早已由单一的自给自足的封装方式,演变为依托既有封装代码基础上的集成与改进。在软件运行时,不仅需要包含执行自身业务逻辑的相关代码,往往还需要其他额外的其他第三方软件或代码库的支持。也就是说,软件与软件(库)之间是有依赖关系的。

作为 Ubuntu 最基础的软件管理方式,dpkg 在软件安装上只能支持安装指定 deb 包内的软件,如软件运行需要其他额外软件或代码库支持,还需利用 dpkg 工具进行额外的补充安装,dpkg 工具无法解决软件依赖缺失的问题。而基于仓库的软件管理方式则提供了“一站式”的解决方案。仓库,即 repository,本质上就是多个 deb 文件的集合,将多个不同类型、不同用途、以及有相互依赖关联关系的软件或代码库统一整合到一个仓库中,安装软件时,可以找到软件间的依赖关系,并将目标软件及其运行所依赖的软件或代码库一起进行安装。

仓库模式,是基于网络环境常见的软件管理方式。这种方式避免了将一个软件所有必备组件封装成一个“大包”的负担,降低了多个软件共用组件的存储开销。

0x221、Ubuntu 的软件仓库种类

Ubuntu 立足于开源世界,软件众多,特点各异,利用“仓库”对这些软件进行有效管理时,对软件包进行分类管理是必然之选。Ubuntu 的软件仓库宏观上可分为“主仓库”和“辅助仓库”两个大类。

a) 主仓库 — Canonical 公司

主仓库,由 Canonical 公司定义。承载了 Ubuntu 中应用的最重要、最核心的软件,按照是否有“官方支持”和“是否开源”这两类划分指标,可具体可分为四种主要类型:

官方支持仓库(Canonical 收录且管理):

  • Main — “公司全力支持”。商业公司 Canonical 官方团队完全支持,自由开源软件
  • Restricted — “公司受限支持,非 Canonical 公司完全可控软件”。商业公司 Canonical 官方团队提供协助支持,Canonical 官方团队不可以自行修改它们,而只能向软件的真正作者提交问题报告。非完全自由开源软件(主要指私有设备驱动)

非官方支持仓库(Canonical 收录但不管):

  • Universe — “开源宇宙”。开源社区支持,面向广阔的开源世界,自由开源软件
  • Multiverse — “多元宇宙”。非 Canonical 官方的非自由软件(版权受限/法律约束)

b) 辅助仓库 — 其他组织或个人

一些组织和个人出于各自原因,也需要自行发行一些软件包,Ubuntu 设计了 PPA 仓库机制来满足这类需求。

PPA,全名 Personal Package Archives,即个人软件包集(归档集)。很多软件包由于各种原因,不能进入官方的 Ubuntu 软件仓库。为了方便 Ubuntu 用户使用,Canonical 官方利用 launchpad.net 提供了 ppa,它允许用户建立自己的软件仓库,自由的上传软件。有时,PPA 也被用来对一些打算进入 Ubuntu 官方仓库的软件,或者某些软件的新版本进行测试。

0x222、基于远程仓库的软件管理机制的实现

Ubuntu 系统使用 apt 工具集实现基于远程仓库的软件管理。

apt 工具集全名 (Advanced Packaging Tool),它是专门应对软件仓库而生的工具集。相比 dpkg 工具,apt 是更为高层的工具。它在底层实现上还是使用了 dpkg 工具完成软件包的基本操作,而上层则实现了对远程仓库的安装包自动获取、软件包依赖关系的自动分析、自动配置及自动安装。从某种程度而言,可以将 apt 视为 dpkg 的“前端”,dpkg 在底层完成对单个软件包的操作,而 apt 工具集则管理软件包之间的关联关系,以及更高层的版本管理等工作(如版本跟踪、版本 pinning 等)。

20180714_1.png

0x2221、仓库目录的设计 — /etc/apt/source.list

Ubuntu 软件仓库类型众多,地址各异,要利用各类仓库,首选需要建立一个仓库的索引目录。Ubuntu 使用 apt 完成基于仓库的软件管理,apt 工具则利用/etc/apt/source.list 文件和 /etc/apt/source.list.d/ 文件夹完成仓库的索引目录的搭建。其中,/etc/apt/source.list 是仓库索引目录的主文件,/etc/apt/source.list.d/ 文件夹是一种辅助机制,可以以独立文件的形式添加仓库索引

/etc/apt/source.list 中的仓库可以有两种存储机制:一种是“单行风格”,即每一行表示一个仓库;一种是“单节风格”,类似诗歌的章节,每一个章节表示一个仓库。“单行风格”使用较为主流。

仓库定义的基本语法:

20180714_2.png

单行风格的仓库包含四个主要部分:

  • Archive type:说明软件包的状态,或为二进制软件包,或为源代码软件包。

  • URI:软件仓库的统一资源标识符,指明了仓库的地址。仓库的地址不仅包括 http、https 等网络地址,还包括 file、cdrom、ftp 等协议所指定的地址,如:

    • deb file:/home/apt/debian stable main contrib non-free
    • deb ftp://ftp.debian.org/debian stretch contrib
  • Distribution:这个属性指明该仓库所对应的 Linux 发行版本特征,这个特征可以是以下几种:
    • Linux 发行版本的发行代号(release code name / alias),如 Bionic、Zesty、Xenial 等;
    • Linux 发行版本的发行类型,如 oldstable、stable、testing、unstable;
    • 发行版后还可能有进一步的指定,如 xenial-updates、trusty-security、stable-backports 等;

    具体选择哪个特征,依期望追溯的目标不同而有所不同。

  • Component:这个属性指明软件包的具体分类。Debian 与 Ubuntu 有不同的软件包分类方式。Ubuntu 的软件分类方式即上文所指出的四种分类方式:main、restricted、universe、multiverse。

0x2222、软件仓库数据在本地系统留存的设计

基于网络使用仓库管理软件,必然躲不开远程仓库和本地数据同步信息的设计问题。

  • 本地系统与远程仓库的数据库信息同步

为了使用远程仓库,本地系统需要与远程仓库同步软件数据库信息,这些信息存储在 /var/lib/apt/lists/ 文件夹内。

  • 本地系统从远程仓库下载的软件包留存

Apt 从远程仓库下载软件后,再进行本地安装,则本地系统必须有相关的留存机制,ubuntu 使用 /var/cache/apt/archives/ 文件夹留存从远程仓库取回的软件包。

三、Ubuntu 仓库软件管理工具 — Apt 管理工具集

0x31、针对仓库的管理工具

Apt 工具集使用 /etc/apt/source.list/etc/apt/source.list.d/ 来构建仓库索引目录,那么,对软件仓库的管理也就是对这两部分内容进行增、删、改、查工作。既可以按照仓库的语法直接编辑相关文件,也可用利用 cli 工具进行管理。

仓库添加/删除 — Apt-add-repository

基本语法:

apt-add-repository REPOSITORY:添加仓库
apt-add-repository -r REPOSITORY:删除仓库

添加仓库命令中的 REPOSITORY 可以是主仓库,也可以是 PPA 仓库。

  • 添加主仓库 –> URI格式 –> 入 /etc/apt/sources.list
  • 添加PPA仓库 –> ppa:/ 格式 –> 入 /etc/apt/sources.list.d/

Apt-add-repository 本身是一个 python 脚本文件。

0x32、针对软件的管理工具

apt 工具集包括三个核心工具:apt、apt-get、apt-cache。这三个工具完成对仓库中的软件各类管理任务。

0x321、软件列表更新 — apt-get update

要使用远程软件仓库,首先一步是了解仓库中软件的基本情况(仓库中有哪些软件、版本情况等),并将仓库中的最新软件信息与系统本地信息同步,以便将来本地系统使用远程仓库,为此,要在本地建立远程仓库软件的索引,ubuntu 使用 apt-get update 建立仓库索引。

仓库索引目录(/etc/apt/source.list/etc/apt/source.list.d/)发生变化,或仓库内软件发生变更(使用仓库安装软件前),都应使用 apt-get update 在本地同步一下远程仓库信息。

0x322、软件安装 — apt-get install

命令格式:

apt-get install packagename1, packagename2…

安装远程仓库中的软件。apt-get install 使用的是仓库机制,会自动查找关联、安装相关的依赖软件包,做到“一站式”安装。

具体实现上,apt 会将目标软件包和相关依赖包下载到本地系统 /var/cache/apt/archive/ 目录下,再逐个进行安装。

如,安装 opera 浏览器,apt 解析后,将 opera-stable 包,及其关联的 chromium-codecs-ffmpeg-extra 包和 libcurl3 包统一下载到 /var/cache/apt/archive/ 目录下,然后以 chromium-codecs-ffmpeg-extra、libcurl3、opera-stable 的顺序进行安装。

0x323、软件删除 — apt-get remove / purge

保守删除:

apt-get remove packagename

删除指定的软件,但会在系统中留下配置文件。

彻底删除:

apt-get remove purge packagename

不仅删除指定的软件,连同软件的配置文件,也会一并删除。正如英文 purge 的含义一样,在系统中“净化”软件的痕迹。

apt-get remove/remove purgedpkg -r/--purge 功能一致。

软件删除逻辑

(1) 对配置文件的处理

配置文件是软件“本地化”部署的重要依据,同一软件在不同系统环境中,配置文件各不相同。出于对用户软件使用习惯等关键数据进行保留的考量,一般在删除软件时,删除软件自身逻辑代码,默认对其“本地化”设置(即相关的配置文件)不进行删除。如需删除软件“本地化”设置,需要使用特定的参数,apt-get 和 dkpg 在进行软件删除时,都设置了相关的逻辑(即 purge 选项),对配置文件进行处理。

(2) 对关联软件包的考虑

原则上,软件删除是软件安装的反向逻辑,但在实现上,却有所不同。软件安装时,为了软件顺利运行,所依赖的所有软件包必须一同下载并安装;但删除时,目标软件包被删除,但一同下载的依赖软件包与不能同时删除,因为有些依赖软件包可能被其他软件所共用,此刻不具备删除条件,所以 Ubuntu 还提供了额外的机制对依赖软件包进行“清理”。

在删除软件时,apt-get remove/purge 工具只删除指定目标软件包,其安装时一同下载的关联软件包不进行删除。相关关联软件包需要使用系统级的清理工具 apt-get autoremove/apt autoremove 进行删除。

如,删除 opera 浏览器,使用 apt-get remove/purge 工具,只删除了 opera-stable 包,而其安装时相关的 chromium-codecs-ffmpeg-extra 和 libcurl3 软件包,需使用 apt-get autoremove/apt autoremove 对这两个相关软件包是否被其他软件复用进行判定后再删除。

0x324、软件查找

0x3241、模糊查找 — apt-cache search

命令格式:

apt-cache search packageinfo/packagename

会在 cache 中(应该是在本地同步软件数据库中,全搜索,不局限于已安装的软件)搜索所有与 packageinfo 相关软件包,搜索范围包括包名字段(package names)和包描述字段(descriptions),如果只想在仓库中搜索包名,则加上 -n (–name-only)选项。

0x3242、同一软件各个版本查找 — apt-cache madison

命令格式:

apt-cache madison packagename

列出 cache 中 packagename 软件在系统中各个软件仓库中的各个版本信息。

0x3243、软件包中的依赖关系查找 — apt-cache showpkg

命令格式:

apt-cache showpkg packagename

列出 cache 中 packagename 软件包的信息,如名称、版本、提供者、包的正向和反向依赖关系等。

0x325、软件自动更新 — apt-get upgrade / dist-upgrade

命令格式:

apt-get upgrade/apt-get dist-upgrade

两者都是针对系统中已安装的软件进行升级更新,本质上是一致的。只是升级策略有所不同,不同的聚焦点在于对软件相依性的处理上。

保守升级 — 使用 apt-get upgrade 进行升级更新。

系统将现有的 package 升级,如果有相依性的问题,要解决此相依性需要安装其它新的 package 或影响到其它 package 的相依性时,则此时,此 package 就不会被升级,会保留下来。

智能升级 — 使用 apt-get dist-upgrade 进行升级更新

apt-get dist-upgrade 除了提供 upgrade 的全部功能外,还可以聪明的解决相依性的问题,如果有相依性问题,要解决此相依性需要安装/移除新的 package,则此时,就会试着去安装/移除它。

可以说,apt-get upgrade 是保守稳妥型升级策略,它对依赖性问题采取的逃避性策略,即遇到即躲避。是凡在升级中遇到引入情况(安装其它新的 Package)和交叉情况(影响到其它 Package 的相依性),则原定目标不予升级。

相反,apt-get dist-upgrade 是智能激进型升级策略,它对依赖性问题采取的解决性策略,即遇到即解决。它依靠 apt-get 提供一个“智能”的系统冲突解决方案,必要时可能以牺牲某些非重要软件包为代价来升级某些非常重要的软件包。通常这个会被认为是有些风险的升级。

例如,软件包 a 原先依赖 b、c、d,但是在源里面可能已经升级了,现在是 a 依赖 b、c、e。这种情况下,dist-upgrade 会删除 d 安装 e,并把 a 软件包升级,而 upgrade 会认为依赖关系改变而拒绝升级 a 软件包。

本地同步 apt-get update 是升级更新的前置条件。

0x3251、对软件自动升级进行定制 — apt-mark

apt-get upgrade 是对软件仓库中所有出现新版本的软件进行整体升级,如果只希望部分软件升级,部分软件不升级,apt 也提供了定制化自动升级策略,即 apt-mark。

使用 apt-mark 可以将指定的软件“钉住”,使其不参与整体的自动升级。

命令格式:

apt-mark hold / unhold packagename

0x326、依赖关系修复

命令格式:

apt-get -f install/remove

ubuntu 中软件集合因相互之间的依赖关系而组成了一个有序的关联关系网。因为某种原因(软件安装、软件删除、软件升级等),某些依赖关系会遭到破坏。apt 工具集本身要维系系统内软件之间的有序依赖平衡,不允许一个系统中存在被破坏的包依赖关系,则此时,使用 -f( – – fix – broken) 参数与 install/remove 相结合,来修复相应的包依赖关系。

0x327、清理无用的依赖软件包 — apt-get autoremove/apt autoremove

apt-get autoremove/apt autoremove 专门用于清理那些“当初为满足其他软件包依赖性而自动安装,现在不在使用”的软件包。

0x328、清所有库存软件包 — apt-get clean

apt-get clean 删除 /var/cache/apt/archives/ 文件夹中所有存留软件包。

综上可见,ubuntu 软件管理的两大核心主题就是“软件本身+相依性”,而这两大主题是任何具备“软件生态”操作系统上都会面临的共性问题,依赖软件包在软件安装使用时会带来便利和效率,但在软件删除时,如不能妥善处理依赖软件包的问题,则不再发挥作用的依赖软件包就会成为系统垃圾的主要来源之一,占用大量系统资源。对待这一问题,不同操作系统有不同的处理方式,ubuntu 则利用 apt 工具集的各种管理工具及相关参数对这一问题进行了“精细化”管理。

Reference

  1. 《The Linux Command Line》, chapter 15.
  2. https://en.wikipedia.org/wiki/APT_(Debian)
  3. https://help.ubuntu.com/community/Repositories/Ubuntu
  4. https://help.ubuntu.com/community/Repositories
  5. man source.list
  6. man apt-add-repository
  7. https://wiki.debian.org/SourcesList
  8. https://blog.csdn.net/gong_xucheng/article/details/53886271

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注