# Linux 发行版

Linux 操作系统 = Linux 内核 + 不同功能
但是因为内核和功能包有多种不同配置,因此 Linux 有多种发行版。
几种主要的发行版及其衍生是:

  • Arch -> Manjaro
  • Debian -> Ubuntu
  • RHEL -> Scientific Linux

# 安装软件的困惑?

我们要在 Linux 操作系统上安装一个软件,思考如下问题:

  • 你需要哪些文件?如何获取他们?
  • 用户需要做多少工作?
  • 开发者需要做多少工作?
  • 在发行软件的过程中还有其他人参与工作吗?
  • 如何更新软件包?
  • 如何保证软件包来源的安全性?

一个简陋的安装方案是:直接下载一堆文件。这其中包含的内容有:

  • 编译好的二进制可执行文件
  • 配置信息
  • 说明文档
  • 许可证 (License)
  • 其他

那么问题来了:

  • 我们需要哪些文件?
  • 这些文件放在哪里?
  • 如何进行环境配置?
  • 这个安装包和我的系统兼容吗?
  • 我怎么更新呢?

一个进阶的安装方案是:下载一个压缩包。但是我们也面临一些问题:

  • 这里面的文件是编译好的还是未编译的?
  • 软件包之间存在依赖关系怎么办?
  • 这个软件如何应对不同 Linux 发行版的需求?
  • 如何更新?如何保证更新后的版本可靠?

# 解决方案:打包!

# 什么是包?

包是 Linux 操作系统上软件的组织方式。

# 什么是仓库( repository )?

仓库是一系列软件包的合集列表。 Debian 上常见的仓库包括:

  • Debian stable (all the packages available to install on a default Debian stable install)
  • Debian security updates
  • Debian backports
  • Docker’s custom repositories

其中:

  • 每个 Linux 发行版都维护仓库,里面列举了该仓库中可安装的所有软件包
  • 包维护者负责对开发者的软件进行打包
  • 对于不同的 Linux 发行版,打包的方式不同

包和仓库区别的详细解释参考这里:

# 包的安装过程

  1. 从包列表中读取该包
  2. 查看该包的所有依赖项
  3. 看看依赖项中哪些包已经安装了
  4. 安装未安装的依赖
  5. 解压缩文件等
  6. 完成一些安装后需要做的工作,如将其作为 service 启动

# 包更新方式

  • 部分 Linux 发行版采用 periodic release 方式,例如 Debian ,2 年一发行
  • 部分采用 rolling release 方式,例如 Arch ,发行版更新更快,但是是以稳定性为代价
    更多内容参考这里:Rolling distribution releases versus periodic releases are a tradeoff

# 自动化包管理工具

# apt

  1. apt update :生成列表,显示仓库中包含哪些包
  2. apt upgrade / apt dist-upgrade :把列表中的包升级到最新版本
  3. apt policy <packagename> :列举可安装的包版本
  4. apt -t [targetrelease] install [package] :安装特定版本包
  5. apt install <packagename> :安装包
  6. apt remove <packagename> :卸载包
  7. apt search <packagename> :搜索包
  8. apt install ./<packagename>.deb :安装本地的 deb
  9. apt download <packagename>.deb :下载包

    几种不同命令的区别参考这里:

  • Why use apt-get upgrade instead of apt-get dist-upgrade?
    :::

# dpkg : 多用于安装本地包

  1. dpkg -i [packagefilename] :安装本地包
  2. dpkg --remove [packagename] :卸载本地包
  3. dpkg -I [packagename] :查看本地包的更多信息
  4. dpkg --configure -a :查看所有解压了但是还没安装的包

# 使用什么包?

/etc/apt/sources.list/etc/apt/sources.list.d 文件中维护镜像源:

deb http://mirrors/debian/ stretch-backports main contrib non-free
deb http://mirrors/debian-security/ stretch/updates main contrib non-free
deb-src http://mirrors/debian-security/ stretch/updates main contrib non-free
deb http://mirrors/debian/ stretch-updates main contrib non-free
deb-src http://mirrors/debian/ stretch-updates main contrib non-free
deb http://mirrors/debian/ stretch main contrib non-free
deb-src http://mirrors/debian/ stretch main contrib non-free
# OCF
deb http://apt/ stretch-backports main
deb-src http://apt/ stretch-backports main
deb http://apt/ stretch main
deb-src http://apt/ stretch main
deb http://mirrors/puppetlabs/apt/ stretch puppet

我个人的理解是, repository 是指仓库名,仓库中列举了该仓库有哪些软件包。而 mirror list 指明了从哪里下载这个仓库中的软件包(网络地址)?在清华的镜像中有这个仓库,而在中科大的镜像中也有这个仓库。镜像中仓库的内容随着官方仓库内容的更新而更新?
关于什么是镜像,请看这里:

  • What are mirrors?

不同的仓库中的软件版本可能不同,需要通过 apt policy 来看软件包所属的仓库。

# 每行内容如何解读?

以下内容摘自 UC Berkeley System Admin Decal 原文

deb http://mirrors/debian/ stretch-backports main contrib non-free

deb is binary package source. deb-src indicates src packages.
http://… describes the location
stretch-backports means that this is for Jessie stretch and from a backport repository
main means that the repo has packages licensed under Debian Free Software Guidelines (DFSG)
contrib repos have packages licensed under DSFG but require non-free dependencies
non-free repos have packages that do not comply with DSFG

# 手动安装包

包中通常含有 Makefile 文件,我们可以手动的进行安装。
步骤:

  1. 安装所需的相关包,例如 gcc
  2. ./configure
  3. make
  4. make install

不便之处:卸载麻烦。

# 包结构

Debian 包通常具有如下几个目录和文件:

  • control :涵盖包的元信息,例如包的大小、版本、依赖
  • debian-binary
  • etc :配置文件
  • md5sums :文件有效性检验
  • usr
    • bin :可执行文件,要加到 $PATH 环境变量中
    • share :文档,man page,本地化设置
      • doc :文档
      • info : info page
      • locale :本地化设置
      • man :man page

# 自己组包

# /usr 目录下几个重要的目录

  • /usr/bin 二进制可执行文件
  • /usr/lib 相关的库
  • /usr/include 头文件
  • /usr/share 文档等等

# 打包过程:将 hellopenguin.c 程序打包

# 初始准备

  1. 编写 hellopenguin.c 程序
#include <stdio.h>
int main(void)
{
    printf("Hello Penguin!\n");
    return 0;
}
  1. 编译 hellopenguin.c 程序,生成可执行文件 hellopenguin
gcc hellopenguin.c -o hellopenguin

# 打包环境准备

  1. 使用 fpm 工具 ( Ruby Gem )
$ sudo apt install ruby-dev
$ sudo gem install fpm
$ fpm -s dir -t deb -n [name here] -v [version #] -C [the directory with the /usr folder]

如果 gem 安装 fpm 过慢的话,需要给 ruby 环境换源,命令如下(这里使用清华源):

# 添加镜像源并移除默认源
gem sources --add https://mirrors.tuna.tsinghua.edu.cn/rubygems/ --remove https://rubygems.org/
# 列出已有源
gem sources -l
# 应该只有镜像源一个

或者在 ~/.gemrc 中将 https://mirrors.tuna.tsinghua.edu.cn/rubygems/ 加到 sources 字段。

  1. 查看 fpm 是否安装,输入 fpm

# 创建包文件夹

  1. 创建目录 packpenguin/usr/bin ,将 hellopenguin 放进去
mkdir -p packpenguin/usr/bin
mv hellopenguin packpenguin/usr/bin
  1. packpenguin 的父目录中,使用 fpm 进行打包,命令如下:
fpm -s dir -t deb -n hellopenguin -v 1.0~ocf1 -C packpenguin

其中几个字段解释如下:

  • -s :使用一个目录构建
  • -t :生成 deb
  • -n :输出包的名字叫 hellopenguin
  • -v :版本号为 1.0~ocf1
  • -C : 由 packpenguin 目录生成
  1. 安装我们组建的包: sudo dpkg -i ./hellopenguin_1.0~ocf1_amd64.deb
  2. 输入 hellopenguin ,运行 hellopenguin ,可以看到输出了 Hello Penguin!

要卸载我们安装的包,可以使用 dpkg --remove hellopenguin 命令。

# 参考资料

  • Packaging
  • Advanced Lab 2 - Packages and Packaging and Troubleshooting
  • Distros, Packaging, and Compiling
  • Beginner Lab 4 - Debian, packages, compiling software
  • FPM 文档
  • TLDR 页面