概述

软件包管理是 Linux 系统运维的基础。Debian 系使用 apt/dpkg,Red Hat 系使用 yum/dnf/rpm。理解两套包管理体系的原理和用法,掌握仓库管理、依赖解析、包构建、版本锁定和离线安装,是高效运维的前提。本文系统对比两大体系,并深入实践包构建和镜像源优化。

apt/dpkg 体系

体系架构

apt (高级前端)
  ├── apt-get     → 包安装/卸载/更新
  ├── apt-cache   → 包查询/搜索
  └── apt         → 综合命令(交互友好)
dpkg (底层工具)
  ├── dpkg        → .deb 包安装/卸载
  ├── dpkg-deb    → .deb 包操作
  └── dpkg-query  → 包查询
aptitude (替代前端,可选)

apt vs apt-get

# apt 是 apt-get 和 apt-cache 的综合,输出更友好
# 常用对照:

# 安装
$ apt install nginx      # 新(推荐交互使用)
$ apt-get install nginx  # 旧(推荐脚本使用)

# 搜索
$ apt search nginx
$ apt-cache search nginx

# 查看包信息
$ apt show nginx
$ apt-cache show nginx

# 更新索引
$ apt update
$ apt-get update

# 升级
$ apt upgrade            # 升级已安装的包(不删除)
$ apt full-upgrade       # 升级(可删除包以解决依赖)
$ apt-get dist-upgrade   # 等同 full-upgrade

在脚本中建议使用 apt-get/apt-cache,因为其输出格式稳定;交互操作使用 apt 更友好。

基本操作

# 安装包
$ apt install nginx
$ apt install nginx=1.24.0-1ubuntu1    # 安装指定版本
$ apt install -y nginx                  # 自动确认
$ apt install --no-install-recommends nginx  # 不安装推荐包

# 卸载
$ apt remove nginx        # 卸载但保留配置
$ apt purge nginx         # 卸载并删除配置
$ apt autoremove          # 卸载不再需要的依赖
$ apt autoclean           # 清理过期的 deb 文件
$ apt clean               # 清理所有 deb 文件

# 更新
$ apt update              # 更新包索引
$ apt upgrade             # 升级所有包
$ apt full-upgrade        # 升级(含依赖变更)
$ apt install --only-upgrade nginx  # 只升级指定包

# 查询
$ apt list --installed        # 已安装的包
$ apt list --upgradable       # 可升级的包
$ apt show nginx              # 包详情
$ apt search "web server"     # 搜索
$ apt depends nginx           # 查看依赖
$ apt rdepends nginx          # 查看反向依赖
$ apt policy nginx            # 查看版本和来源

dpkg 底层操作

# 安装 deb 包
$ dpkg -i package.deb      # 安装
$ dpkg -i --force-depends package.deb  # 忽略依赖安装(不推荐)

# 卸载
$ dpkg -r package          # 卸载(保留配置)
$ dpkg -P package          # 卸载(删除配置)

# 查询
$ dpkg -l                  # 列出所有已安装的包
$ dpkg -l nginx            # 查看指定包状态
$ dpkg -L nginx            # 查看包安装的文件
$ dpkg -S /usr/sbin/nginx  # 查找文件属于哪个包
$ dpkg -s nginx            # 查看包详情
$ dpkg -I package.deb      # 查看 deb 包信息
$ dpkg -c package.deb      # 查看 deb 包内容

# 解压(不安装)
$ dpkg -x package.deb /tmp/extract
$ dpkg -e package.deb /tmp/extract/DEBIAN  # 提取控制文件

apt 包状态

$ dpkg -l nginx
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version        Architecture Description
+++-==============-==============-============-=================================
ii  nginx          1.24.0-1       amd64        high performance web server
字段含义
Desiredi应安装
Statusi已安装
Err(none)无错误
混合状态 ii正常安装
rc已卸载但配置保留
hi已安装且被锁定
un未安装

修复损坏的依赖

# 修复依赖
$ apt --fix-broken install
$ apt-get -f install

# 重新配置已安装的包
$ dpkg --configure -a

# 强制重装
$ apt install --reinstall nginx
$ dpkg --force-all -i package.deb  # 最后手段

yum/dnf/rpm 体系

体系架构

dnf (yum 的继任者,Fedora/RHEL 8+)
  ├── dnf          → 包安装/卸载/更新
  ├── dnf-config-manager → 仓库管理
  └── dnf-utils    → 实用工具(repoquery 等)
yum (RHEL 7 及以下)
rpm (底层工具)
  ├── rpm          → .rpm 包安装/卸载
  ├── rpm2cpio     → 解压 rpm
  └── rpmbuild     → 构建 rpm

yum vs dnf

# dnf 命令基本兼容 yum
# 主要改进:
# - 更快的依赖解析(libsolv)
# - 更好的内存使用
# - 模块化支持
# - 更清晰的错误信息

# 常用命令(yum/dnf 通用)
$ dnf install nginx
$ dnf remove nginx
$ dnf update nginx
$ dnf update             # 更新所有包
$ dnf search nginx
$ dnf info nginx
$ dnf list installed
$ dnf list available
$ dnf history            # 操作历史
$ dnf history undo 5     # 撤销第 5 次操作

基本操作

# 安装
$ dnf install nginx
$ dnf install nginx-1.24.0    # 指定版本
$ dnf install -y nginx        # 自动确认
$ dnf install --nogpgcheck nginx  # 跳过 GPG 检查(不推荐)
$ dnf reinstall nginx         # 重装

# 卸载
$ dnf remove nginx            # 卸载
$ dnf autoremove              # 卸载不需要的依赖
$ dnf remove --noautoremove nginx  # 不自动卸载依赖

# 更新
$ dnf check-update            # 检查可更新的包
$ dnf update                  # 更新所有
$ dnf upgrade                 # 等同 update
$ dnf update --security       # 只更新安全补丁

# 查询
$ dnf list nginx              # 查看包
$ dnf info nginx              # 包详情
$ dnf search "web server"     # 搜索
$ dnf provides /usr/sbin/nginx  # 查找文件属于哪个包
$ dnf repoquery --requires nginx  # 查看依赖
$ dnf repoquery --whatrequires nginx  # 反向依赖
$ dnf history                 # 操作历史
$ dnf grouplist               # 包组列表
$ dnf groupinstall "Development Tools"  # 安装包组

rpm 底层操作

# 安装
$ rpm -ivh package.rpm       # 安装
$ rpm -Uvh package.rpm       # 升级安装
$ rpm -Fvh package.rpm       # 只升级已安装的
$ rpm -ivh --nodeps package.rpm  # 忽略依赖(不推荐)
$ rpm -ivh --force package.rpm   # 强制重装

# 卸载
$ rpm -e package             # 卸载
$ rpm -e --nodeps package    # 忽略依赖卸载(危险)

# 查询
$ rpm -qa                    # 列出所有已安装的包
$ rpm -q nginx               # 查看是否安装
$ rpm -qi nginx              # 包详情
$ rpm -ql nginx              # 包安装的文件
$ rpm -qc nginx              # 配置文件
$ rpm -qd nginx              # 文档文件
$ rpm -qf /usr/sbin/nginx    # 文件属于哪个包
$ rpm -qR nginx              # 依赖关系
$ rpm -q --whatrequires nginx  # 反向依赖
$ rpm -q --changelog nginx   # 变更日志

# 验证
$ rpm -V nginx               # 验证文件完整性
$ rpm -Va                    # 验证所有包
# S=大小变化 M=权限变化 5=MD5变化 T=时间变化

rpm 包状态验证

$ rpm -V nginx
S.5....T.  c /etc/nginx/nginx.conf
# 字段含义:
# S - 文件大小改变
# 5 - MD5 校验和改变
# L - 符号链接改变
# T - 修改时间改变
# D - 设备改变
# U - 用户改变
# G - 组改变
# M - 权限改变
# . - 该属性未改变

# 第二列:
# c - 配置文件
# d - 文档文件
# g - 幽灵文件(不应存在)
# l - 许可证文件
# r - readme 文件
# (空) - 普通文件

仓库管理

apt 仓库管理

# 查看已配置的仓库
$ apt policy
$ cat /etc/apt/sources.list
$ ls /etc/apt/sources.list.d/

# 添加仓库(传统方式)
$ echo "deb http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse" >> /etc/apt/sources.list

# 添加 PPA
$ add-apt-repository ppa:nginx/stable
$ apt update

# 添加仓库(推荐方式)
# /etc/apt/sources.list.d/nginx.list
deb [arch=amd64 signed-by=/etc/apt/keyrings/nginx.gpg] https://nginx.org/packages/ubuntu noble nginx

# 导入 GPG 密钥
$ curl -fsSL https://nginx.org/keys/nginx_signing.key | gpg --dearmor -o /etc/apt/keyrings/nginx.gpg

# 禁用仓库
# 在行首加 #
# 或使用 apt preferences

# 更新索引
$ apt update

apt 仓库优先级

# /etc/apt/preferences.d/nginx
Package: nginx
Pin: release o=nginx
Pin-Priority: 1001

# 优先级说明:
# 1001+  - 降级也允许安装
# 990    - 默认(已安装的优先)
# 500    - 标准优先级
# 100    - 非官方源
# <0     - 拒绝安装

# 查看优先级
$ apt policy nginx

dnf/yum 仓库管理

# 查看已配置的仓库
$ dnf repolist
$ dnf repolist --all

# 仓库配置文件
$ ls /etc/yum.repos.d/
# /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

# 启用/禁用仓库
$ dnf config-manager --enable nginx-stable
$ dnf config-manager --disable nginx-stable

# 临时启用仓库
$ dnf --enablerepo=nginx-stable install nginx

# 添加仓库
$ dnf config-manager --add-repo https://nginx.org/packages/centos/nginx.repo

# 导入 GPG 密钥
$ rpm --import https://nginx.org/keys/nginx_signing.key

dnf 模块化

# 查看可用模块
$ dnf module list

# Node.js 模块示例
$ dnf module list nodejs
Name      Stream    Profiles                          Summary
nodejs    18        common [d], development, minimal  Javascript runtime
nodejs    20        common [d], development, minimal  Javascript runtime

# 启用模块流
$ dnf module enable nodejs:20

# 安装模块
$ dnf module install nodejs:20/common

# 切换模块流
$ dnf module reset nodejs
$ dnf module enable nodejs:18
$ dnf module install nodejs:18

依赖解析

apt 依赖解析

# 查看依赖
$ apt depends nginx
$ apt-cache depends nginx

# 查看反向依赖
$ apt rdepends nginx
$ apt-cache rdepends nginx

# 查看依赖树
$ apt-cache depends --recurse nginx | head -50

# 查看某个包为何被安装
$ apt why nginx
# nginx <depends> nginx-core
# nginx-core <depends> nginx

# 查看包的推荐和建议
$ apt show nginx | grep -E "Depends|Recommends|Suggests"

dnf 依赖解析

# 查看依赖
$ dnf repoquery --requires nginx
$ dnf repoquery --requires --recursive nginx

# 反向依赖
$ dnf repoquery --whatrequires nginx

# 查看包提供的功能
$ dnf repoquery --provides nginx

# 查看包的文件
$ dnf repoquery --list nginx

# 依赖树
$ dnf repoquery --requires --resolve --recursive nginx

依赖冲突处理

# apt: 模拟安装查看冲突
$ apt install -s nginx

# dnf: 使用 --best 显示最佳可用版本
$ dnf install --best nginx

# dnf: 使用 --allowerasing 允许删除冲突包
$ dnf install --allowerasing nginx

# 查看冲突详情
$ dnf install nginx --assumeno  # 模拟,回答 no

包构建

构建 deb 包

目录结构

mypackage/
├── DEBIAN/
│   ├── control          # 包信息(必须)
│   ├── postinst         # 安装后脚本
│   ├── prerm            # 卸载前脚本
│   ├── postrm           # 卸载后脚本
│   ├── preinst          # 安装前脚本
│   ├── conffiles        # 配置文件列表
│   ├── md5sums          # 文件校验和(自动生成)
│   └── triggers         # 触发器
├── usr/
│   ├── bin/
│   │   └── myapp        # 可执行文件
│   ├── lib/
│   │   └── myapp/
│   │       └── config.yaml
│   └── share/
│       └── man/
│           └── man1/
│               └── myapp.1
└── etc/
    └── myapp/
        └── config.conf

control 文件

# mypackage/DEBIAN/control
Package: myapp
Version: 1.0.0
Architecture: amd64
Maintainer: Admin <admin@sre.wang>
Installed-Size: 1024
Depends: libc6 (>= 2.34), libssl3
Recommends: logrotate
Suggests: myapp-doc
Conflicts: oldapp
Replaces: oldapp
Section: utils
Priority: optional
Description: My Application
 A custom application for server management.
 .
 Features:
  - Feature 1
  - Feature 2

维护脚本

#!/bin/bash
# mypackage/DEBIAN/postinst

set -e

case "$1" in
    configure)
        # 创建用户
        if ! id myapp &>/dev/null; then
            useradd --system --no-create-home --shell /usr/sbin/nologin myapp
        fi
        
        # 设置权限
        chown myapp:myapp /var/lib/myapp
        chmod 750 /var/lib/myapp
        
        # 启用服务
        systemctl enable myapp.service
        systemctl start myapp.service
        
        echo "myapp installed successfully"
        ;;
    
    abort-upgrade|abort-remove|abort-deconfigure)
        ;;
    
    *)
        echo "postinst called with unknown argument \`$1'" >&2
        exit 1
        ;;
esac

exit 0

构建

# 确保 control 文件权限正确
$ chmod 755 mypackage/DEBIAN/postinst
$ chmod 755 mypackage/DEBIAN/prerm

# 生成 md5sums
$ cd mypackage
$ find . -type f ! -path './DEBIAN/*' -exec md5sum {} \; | sed 's/\.\///' > DEBIAN/md5sums

# 构建 deb 包
$ dpkg-deb --build mypackage
# 或
$ dpkg -b mypackage myapp_1.0.0_amd64.deb

# 验证
$ dpkg-deb --info myapp_1.0.0_amd64.deb
$ dpkg-deb --contents myapp_1.0.0_amd64.deb

# 使用 lintian 检查
$ lintian myapp_1.0.0_amd64.deb

使用 debhelper 构建(进阶)

# 安装构建工具
$ apt install debhelper dh-make devscripts

# 初始化包
$ dh_make --createorig -p myapp_1.0.0

# 编辑 debian/ 目录下的文件
# debian/control
# debian/rules
# debian/changelog

# 构建
$ dpkg-buildpackage -us -uc -b

构建 rpm 包

spec 文件

# myapp.spec
Name:           myapp
Version:        1.0.0
Release:        1%{?dist}
Summary:        My Application

License:        MIT
URL:            https://sre.wang
Source0:        %{name}-%{version}.tar.gz

BuildRequires:  gcc
BuildRequires:  make
Requires:       openssl
Requires(post): systemd
Requires(preun): systemd
Requires(postun): systemd

%description
A custom application for server management.

%prep
%setup -q

%build
make %{?_smp_mflags}

%install
make install DESTDIR=%{buildroot}
install -D -m 644 config/myapp.service %{buildroot}%{_unitdir}/myapp.service
install -D -m 644 config/myapp.conf %{buildroot}%{_sysconfdir}/myapp/myapp.conf

%files
%{_bindir}/myapp
%{_unitdir}/myapp.service
%dir %{_sysconfdir}/myapp
%config(noreplace) %{_sysconfdir}/myapp/myapp.conf
%doc README.md
%license LICENSE

%post
%systemd_post myapp.service

%preun
%systemd_preun myapp.service

%postun
%systemd_postun_with_restart myapp.service

%changelog
* Wed Jul 10 2026 Admin <admin@sre.wang> - 1.0.0-1
- Initial release

构建

# 1. 准备构建环境
$ dnf install rpmdevtools rpmbuild
$ rpmdev-setuptree

# 2. 目录结构
~/rpmbuild/
├── BUILD/
├── RPMS/
├── SOURCES/
│   └── myapp-1.0.0.tar.gz
├── SPECS/
│   └── myapp.spec
└── SRPMS/

# 3. 放置源码
$ cp myapp-1.0.0.tar.gz ~/rpmbuild/SOURCES/
$ cp myapp.spec ~/rpmbuild/SPECS/

# 4. 构建
$ rpmbuild -ba ~/rpmbuild/SPECS/myapp.spec
# -ba: 构建 src.rpm 和 binary rpm
# -bb: 只构建 binary rpm
# -bs: 只构建 src.rpm

# 5. 查看
$ ls ~/rpmbuild/RPMS/x86_64/
myapp-1.0.0-1.el9.x86_64.rpm

# 6. 验证
$ rpm -qpi ~/rpmbuild/RPMS/x86_64/myapp-1.0.0-1.el9.x86_64.rpm
$ rpm -qpl ~/rpmbuild/RPMS/x86_64/myapp-1.0.0-1.el9.x86_64.rpm

deb vs rpm 包构建对比

特性debrpm
控制文件DEBIAN/controlspec 文件
脚本位置DEBIAN/ 目录spec 文件内
依赖声明Depends/RecommendsRequires
配置文件标记conffiles%config(noreplace)
构建工具dpkg-deb / debhelperrpmbuild
源码包.dsc + .orig.tar.gz.src.rpm
变更日志debian/changelog%changelog

版本锁定

apt 版本锁定

# 方法 1: apt-mark hold
$ apt-mark hold nginx
$ apt-mark showhold
$ apt-mark unhold nginx

# 方法 2: dpkg --set-selection
$ echo "nginx hold" | dpkg --set-selections
$ dpkg --get-selections | grep hold

# 方法 3: apt preferences(更精细)
# /etc/apt/preferences.d/hold-nginx
Package: nginx
Pin: release *
Pin-Priority: -1
# 优先级 < 0 拒绝安装/升级

# 锁定特定版本
# /etc/apt/preferences.d/pin-nginx
Package: nginx
Pin: version 1.24.0*
Pin-Priority: 1001

dnf/yum 版本锁定

# 方法 1: versionlock 插件
$ dnf install python3-dnf-plugin-versionlock
$ dnf versionlock add nginx
$ dnf versionlock list
$ dnf versionlock delete nginx
$ dnf versionlock clear

# 方法 2: 在 repo 中排除
# /etc/yum.repos.d/centos.repo
[baseos]
exclude=nginx kernel*

# 方法 3: dnf 配置
# /etc/dnf/dnf.conf
exclude=nginx

离线安装

方法 1: 下载 deb 包及依赖

# 下载包及所有依赖
$ apt download nginx
$ apt-get install --download-only -o Dir::Cache=/tmp/packages nginx
# 或
$ apt install --reinstall --download-only nginx

# 更好的方式:使用 apt-rdepends
$ apt install apt-rdepends
$ apt-rdepends nginx | grep -v "^ " | awk '{print $1}' | xargs apt download

# 使用 dpkg-offline
$ apt install dpkg-offline
$ dpkg-offline /path/to/iso nginx

# 安装离线包
$ dpkg -i /tmp/packages/*.deb
$ apt --fix-broken install  # 修复依赖(如果需要)

方法 2: 下载 rpm 包及依赖

# 下载包及依赖
$ dnf install --downloadonly --downloaddir=/tmp/packages nginx

# 使用 repotrack
$ dnf install dnf-utils
$ repotrack nginx -p /tmp/packages

# 安装离线包
$ rpm -Uvh /tmp/packages/*.rpm
# 或
$ dnf localinstall /tmp/packages/*.rpm

方法 3: 创建本地仓库

# apt 本地仓库
$ apt install dpkg-dev
$ mkdir -p /opt/local-repo
$ cp *.deb /opt/local-repo/
$ cd /opt/local-repo && dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz

# 配置仓库
# /etc/apt/sources.list.d/local.list
deb [trusted=yes] file:///opt/local-repo ./

$ apt update
$ apt install myapp

# dnf 本地仓库
$ dnf install createrepo
$ mkdir -p /opt/local-repo
$ cp *.rpm /opt/local-repo/
$ createrepo /opt/local-repo

# 配置仓库
# /etc/yum.repos.d/local.repo
[local]
name=Local Repository
baseurl=file:///opt/local-repo
gpgcheck=0
enabled=1

$ dnf install myapp

方法 4: 使用快照/镜像

# apt-mirror: 完整镜像
$ apt install apt-mirror
# /etc/apt/mirror.list
deb http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu noble-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu noble-security main restricted universe multiverse

$ apt-mirror
# 下载到 /var/spool/apt-mirror/

# reposync: 镜像 dnf 仓库
$ dnf install dnf-utils
$ reposync --repoid=baseos --download_path=/opt/mirror
$ createrepo /opt/mirror/baseos

镜像源优化

选择最快的镜像

# apt: netselect-apt
$ apt install netselect-apt
$ netselect-apt noble
# 自动选择最快的 Ubuntu 镜像

# 或手动测试
$ time curl -sI http://archive.ubuntu.com/ubuntu/ > /dev/null
$ time curl -sI http://mirrors.aliyun.com/ubuntu/ > /dev/null
$ time curl -sI http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ > /dev/null

# dnf: fastestmirror 插件
# /etc/dnf/dnf.conf
fastestmirror=True

$ dnf clean all
$ dnf makecache

配置国内镜像

# Ubuntu/Debian 镜像源
# /etc/apt/sources.list
deb https://mirrors.aliyun.com/ubuntu/ noble main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu/ noble-updates main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu/ noble-security main restricted universe multiverse

# 或清华源
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ noble main restricted universe multiverse

# Debian
deb https://mirrors.aliyun.com/debian/ bookworm main contrib non-free non-free-firmware
deb https://mirrors.aliyun.com/debian/ bookworm-updates main contrib non-free non-free-firmware
deb https://mirrors.aliyun.com/debian-security/ bookworm-security main contrib non-free non-free-firmware

# RHEL/CentOS 镜像源
# /etc/yum.repos.d/CentOS-Base.repo
[baseos]
name=CentOS Stream $releasever - BaseOS
baseurl=https://mirrors.aliyun.com/centos-stream/$releasever-stream/BaseOS/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

[appstream]
name=CentOS Stream $releasever - AppStream
baseurl=https://mirrors.aliyun.com/centos-stream/$releasever-stream/AppStream/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

# AlmaLinux/Rocky Linux
# 通常已有国内镜像,参考官方文档

镜像缓存优化

# apt: 配置缓存
# /etc/apt/apt.conf.d/99-cache
Dir::Cache "/var/cache/apt";
Dir::Cache::archives "archives";
APT::Install-Recommends "false";  # 减少不必要的包
APT::Install-Suggests "false";
APT::Get::Install-Suggests "false";

# 清理缓存
$ apt clean          # 清理所有下载的 deb
$ apt autoclean      # 只清理过期的 deb
$ apt autoremove     # 清理不需要的依赖

# dnf: 配置缓存
# /etc/dnf/dnf.conf
keepcache=True       # 保留下载的 rpm
cachedir=/var/cache/dnf

$ dnf clean all      # 清理缓存
$ dnf makecache      # 重建缓存

使用代理

# apt 代理
# /etc/apt/apt.conf.d/99proxy
Acquire::http::Proxy "http://proxy.sre.wang:8080";
Acquire::https::Proxy "http://proxy.sre.wang:8080";

# 或环境变量
$ export http_proxy=http://proxy.sre.wang:8080
$ export https_proxy=http://proxy.sre.wang:8080
$ apt update

# dnf 代理
# /etc/dnf/dnf.conf
proxy=http://proxy.sre.wang:8080
proxy_username=user
proxy_password=pass

包管理安全

GPG 密钥管理

# apt: GPG 密钥
# 导入密钥(新方式)
$ install -d /etc/apt/keyrings
$ curl -fsSL https://nginx.org/keys/nginx_signing.key | gpg --dearmor -o /etc/apt/keyrings/nginx.gpg

# 导入密钥(旧方式,不推荐)
$ apt-key add nginx_signing.key

# 查看已导入的密钥
$ apt-key list

# 删除密钥
$ apt-key del ABC12345
$ rm /etc/apt/keyrings/nginx.gpg

# dnf: GPG 密钥
$ rpm --import https://nginx.org/keys/nginx_signing.key

# 查看已导入的密钥
$ rpm -qa gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n'

# 删除密钥
$ rpm -e gpg-pubkey-abc12345

验证包完整性

# apt: 验证
$ apt install --allow-unauthenticated nginx  # 禁用验证(不推荐)
$ apt install nginx  # 默认验证

# dpkg 验证
$ debsums nginx    # 验证已安装包的文件
$ debsums -c nginx # 只检查变化的文件

# dnf: 验证
$ dnf install --nogpgcheck nginx  # 禁用验证(不推荐)

# rpm 验证
$ rpm -K package.rpm     # 验证签名
$ rpm --checksig package.rpm

# 验证所有已安装包
$ rpm -Va | grep -E "S\.5" | head -20
# 检查文件是否被篡改

实战案例

案例 1:自动化包安装脚本

#!/bin/bash
# install-packages.sh - 跨发行版包安装

set -e

# 检测包管理器
if command -v apt &>/dev/null; then
    PKG_MGR="apt"
elif command -v dnf &>/dev/null; then
    PKG_MGR="dnf"
elif command -v yum &>/dev/null; then
    PKG_MGR="yum"
else
    echo "Unsupported distribution"
    exit 1
fi

# 包名映射(不同发行版包名可能不同)
declare -A PACKAGES=(
    ["nginx"]="nginx"
    ["redis"]="redis-server"  # Debian 用 redis-server
    ["vim"]="vim"
    ["curl"]="curl"
    ["git"]="git"
)

# 安装函数
install_package() {
    local name=$1
    local apt_name=${2:-$1}
    local dnf_name=${3:-$1}
    
    case $PKG_MGR in
        apt)
            apt update && apt install -y "$apt_name"
            ;;
        dnf|yum)
            $PKG_MGR install -y "$dnf_name"
            ;;
    esac
}

# 批量安装
for pkg in nginx redis vim curl git; do
    echo "Installing $pkg..."
    install_package "$pkg"
done

echo "All packages installed."

案例 2:构建自定义 Nginx 包

#!/bin/bash
# build-nginx-deb.sh - 构建 Nginx deb 包

set -e

VERSION="1.27.0"
NGINX_USER="www-data"
BUILD_DIR="/tmp/nginx-build"
PKG_DIR="$BUILD_DIR/nginx_$VERSION"

# 1. 准备构建环境
apt install -y build-essential libpcre3-dev zlib1g-dev libssl-dev dpkg-dev

# 2. 下载源码
mkdir -p $BUILD_DIR
cd $BUILD_DIR
wget http://nginx.org/download/nginx-$VERSION.tar.gz
tar xzf nginx-$VERSION.tar.gz

# 3. 编译
cd nginx-$VERSION
./configure \
    --prefix=/usr/share/nginx \
    --sbin-path=/usr/sbin/nginx \
    --conf-path=/etc/nginx/nginx.conf \
    --user=$NGINX_USER \
    --group=$NGINX_USER \
    --with-http_ssl_module \
    --with-http_v2_module \
    --with-http_stub_status_module
make -j$(nproc)
make install DESTDIR=$PKG_DIR

# 4. 创建 DEBIAN 目录
mkdir -p $PKG_DIR/DEBIAN

# 5. 创建 control 文件
cat > $PKG_DIR/DEBIAN/control << EOF
Package: nginx-custom
Version: $VERSION
Architecture: amd64
Maintainer: Admin <admin@sre.wang>
Depends: libc6, libpcre3, zlib1g, libssl3
Section: web
Priority: optional
Description: Custom Nginx $VERSION
 Nginx built with custom configuration.
EOF

# 6. 创建 systemd service
mkdir -p $PKG_DIR/etc/systemd/system
cat > $PKG_DIR/etc/systemd/system/nginx.service << 'EOF'
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

# 7. 创建 postinst
cat > $PKG_DIR/DEBIAN/postinst << 'EOF'
#!/bin/bash
set -e
systemctl daemon-reload
systemctl enable nginx
systemctl start nginx
EOF
chmod 755 $PKG_DIR/DEBIAN/postinst

# 8. 生成 md5sums
cd $PKG_DIR
find . -type f ! -path './DEBIAN/*' -exec md5sum {} \; | sed 's/\.\///' > DEBIAN/md5sums

# 9. 构建
cd $BUILD_DIR
dpkg-deb --build $(basename $PKG_DIR)

echo "Package built: $BUILD_DIR/nginx_$VERSION.deb"

案例 3:安全更新自动化

#!/bin/bash
# auto-security-update.sh - 安全更新自动化

set -e

LOG="/var/log/security-update.log"
exec > >(tee -a $LOG) 2>&1

echo "=== Security Update $(date) ==="

if command -v apt &>/dev/null; then
    # Debian/Ubuntu
    apt update
    
    # 只安装安全更新
    apt list --upgradable 2>/dev/null | grep -i security
    
    # 使用 unattended-upgrades
    apt install -y unattended-upgrades
    echo 'APT::Periodic::Update-Package-Lists "1";' > /etc/apt/apt.conf.d/20auto-upgrades
    echo 'APT::Periodic::Unattended-Upgrade "1";' >> /etc/apt/apt.conf.d/20auto-upgrades
    
    unattended-upgrade --dry-run -v
    
elif command -v dnf &>/dev/null; then
    # RHEL/CentOS
    dnf check-update --security
    
    # 安装安全更新
    dnf update --security -y
    
    # 使用 dnf-automatic
    dnf install -y dnf-automatic
    sed -i 's/apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf
    sed -i 's/upgrade_type = default/upgrade_type = security/' /etc/dnf/automatic.conf
    systemctl enable --now dnf-automatic.timer
fi

echo "Security update completed."

包管理速查表

操作apt/dpkgdnf/yum/rpm
安装apt install pkgdnf install pkg
卸载apt remove pkgdnf remove pkg
卸载+配置apt purge pkgdnf remove pkg
更新索引apt updatednf makecache
升级包apt upgrade pkgdnf update pkg
升级全部apt full-upgradednf update
搜索apt search keyworddnf search keyword
包信息apt show pkgdnf info pkg
已安装列表apt list --installeddnf list installed
查找文件dpkg -S filerpm -qf file / dnf provides file
包文件列表dpkg -L pkgrpm -ql pkg
安装本地包dpkg -i pkg.debdnf localinstall pkg.rpm
查看依赖apt depends pkgdnf repoquery --requires pkg
反向依赖apt rdepends pkgdnf repoquery --whatrequires pkg
锁定版本apt-mark hold pkgdnf versionlock add pkg
操作历史cat /var/log/dpkg.logdnf history
清理缓存apt cleandnf clean all

总结

Linux 包管理是系统运维的基础技能,两大体系各有特点但概念相通。核心要点:

  1. apt/dpkg 和 dnf/rpm 是两套并行的体系:Debian 系用 apt,Red Hat 系用 dnf(yum 的继任者),底层分别用 dpkg 和 rpm。
  2. 优先使用高级前端apt/dnf 处理依赖解析,dpkg/rpm 只处理单个包。
  3. 仓库管理是运维核心:正确配置仓库源、GPG 密钥、优先级,是安全使用第三方软件的前提。
  4. 依赖解析理解 Depends/Requiresapt depends/dnf repoquery --requires 查看依赖,apt why/dnf repoquery --whatrequires 查看安装原因。
  5. 包构建要掌握目录结构和控制文件:deb 用 DEBIAN/control,rpm 用 spec 文件,维护脚本处理服务启停和权限设置。
  6. 版本锁定防止意外升级apt-mark hold/dnf versionlock 锁定关键包,避免自动升级导致兼容性问题。
  7. 离线安装有多种方式:下载 deb/rpm 及依赖、创建本地仓库、使用 apt-mirror/reposync 镜像。
  8. 镜像源优化提升安装速度:使用国内镜像、配置缓存、选择最快镜像。
  9. 安全更新是运维基线:使用 unattended-upgrades/dnf-automatic 自动安装安全补丁。
  10. GPG 验证是安全基础:不要使用 --allow-unauthenticated/--nogpgcheck,确保包来源可信。

包管理的黄金法则:最小化安装,最大化控制。只安装需要的包,锁定关键包版本,定期清理不需要的依赖,保持系统干净可控。