dpkg 与 deb 打包
dpkg 是 Debian 包管理的底层工具,apt 依赖 dpkg 执行实际的包操作。本章覆盖 dpkg 命令参考、手动创建 .deb 包、维护脚本编写、debhelper 构建系统和 reprepro 本地仓库。
1. 资源链接
2. dpkg 命令完整参考
2.1 包管理
# 安装 .deb 包(不处理依赖)
sudo dpkg -i package.deb
# 安装后自动修复依赖
sudo dpkg -i package.deb && sudo apt install -f
# 删除包(保留配置)
sudo dpkg -r packagename
# 完全删除(包括配置)
sudo dpkg -P packagename
# 列出所有已安装的包
dpkg -l
# 列出特定包的版本和状态
dpkg -l packagename
# 查看 .deb 包的内容(未安装)
dpkg -c package.deb
dpkg --contents package.deb
# 查看 .deb 包的信息
dpkg -I package.deb
dpkg --info package.deb
2.2 查询已安装的包
# 查看包的详细状态
dpkg -s packagename
# 列出包安装的所有文件
dpkg -L packagename
# 查找某个文件属于哪个包
dpkg -S /path/to/file
# 查找部分文件名属于哪个包
dpkg -S '*libfoo*'
# 查看系统架构
dpkg --print-architecture
# 查看可用的外部架构(如 i386 兼容)
dpkg --print-foreign-architectures
# 添加 i386 架构支持
sudo dpkg --add-architecture i386
2.3 包状态操作
# 重新配置已安装的包(运行 postinst 脚本)
sudo dpkg-reconfigure packagename
# 对未正确配置的包执行配置
sudo dpkg --configure -a
# 查看包的 conffile(配置文件)状态
dpkg --status packagename | grep -A5 "Conffiles"
# 审计:检查哪些安装的包文件被修改过
sudo dpkg --verify
# 验证特定包
sudo dpkg --verify packagename
2.4 强制操作(高级)
# 强制覆盖文件
sudo dpkg --force-overwrite -i package.deb
# 强制删除(忽略依赖)
sudo dpkg --force-depends -r packagename
# 忽略全部冲突(极度危险)
sudo dpkg --force-all -i package.deb
# 强制架构
sudo dpkg --force-architecture -i package.deb
# 查看所有强制选项
dpkg --force-help
# 解除 hold(禁止升级)标记
sudo dpkg --set-selections <<< "packagename install"
# 设置 hold 标记
sudo dpkg --set-selections <<< "packagename hold"
2.5 包列表导出与恢复
# 导出所有已安装包
dpkg --get-selections > pkg-list.txt
# 导出包及其标记(install/deinstall/purge/hold)
dpkg --get-selections "*" > full-selections.txt
# 从列表恢复(在新系统上)
sudo dpkg --set-selections < pkg-list.txt
sudo apt-get dselect-upgrade
# 只导出显式安装的包(apt 层面)
apt-mark showmanual > manual-pkgs.txt
3. dpkg 数据库
3.1 数据库结构
# dpkg 数据库位置
ls /var/lib/dpkg/
# 主要文件和目录:
# status — 已安装包的完整状态
# available — 可安装包的缓存
# info/ — 每个包的控制文件和脚本
# pkgname.list — 包的文件列表
# pkgname.md5sums — 文件校验和
# pkgname.postinst — 安装后脚本
# pkgname.prerm — 删除前脚本
# updates/ — 未完成的更新
# diversions — 文件转移
# statoverride — 文件所有者覆盖
3.2 数据库查询
# 查看包的所有维护脚本
ls /var/lib/dpkg/info/packagename. *
# 查看包安装的文件列表
cat /var/lib/dpkg/info/packagename.list
# 查看包 conffiles
cat /var/lib/dpkg/info/packagename.conffiles
# 搜索包含特定文件的包
grep -l "filename" /var/lib/dpkg/info/ * .list
4. 创建 .deb 包基础
4.1 最小 deb 包结构
myapp-1.0.0/
├── DEBIAN/
│ └── control # 包元数据(必需)
│ ├── preinst # 安装前脚本(可选)
│ ├── postinst # 安装后脚本(可选)
│ ├── prerm # 删除前脚本(可选)
│ ├── postrm # 删除后脚本(可选)
│ ├── conffiles # 配置文件列表(可选)
│ └── md5sums # 文件校验
└── usr/
├── bin/myapp
├── share/
│ ├── doc/myapp/copyright
│ └── applications/myapp.desktop
└── lib/myapp/
4.2 control 文件完整字段
Package: myapp
Version: 1.2.3-1
Section: utils
Priority: optional
Architecture: amd64
Essential: no
Maintainer: Your Name <you@example.com>
Uploaders: Co-maintainer <co@example.com>
Homepage: https://example.com/myapp
Description: 简短描述(≤60字符)
长描述,可以多行。
每行开头留一个空格。
段落间用 " ." 空行分隔。
.
这是第三段描述。
Depends: libc6 (>= 2.31), python3
Recommends: python3-requests
Suggests: python3-lxml
Pre-Depends: ${misc:Pre-Depends}
Conflicts: old-myapp
Provides: virtual-myapp
Replaces: old-myapp
Breaks: some-other-package (<< 2.0)
Built-Using: gcc-12 (= 12.2.0-14)
Installed-Size: 1524
4.3 字段说明
字段 必填 说明 Package包名,只能小写字母、数字、-、+、. Version格式:上游版本-Debian修订版本,如 1.2.3-1 Architectureamd64、i386、arm64、all、anyMaintainer维护者姓名和邮箱 Description第一行是简短描述,后续段落是长描述 Depends运行时强制依赖 Pre-Depends在解包前就必须安装的依赖 Recommends推荐安装(默认会安装) Suggests建议安装(不会自动安装) Conflicts冲突的包名 Provides此包提供的虚拟包名 Replaces替换的文件来自哪个包 Breaks破坏指定版本的包 Section分类:utils、net、devel、admin 等 Priorityrequired、important、standard、optional、extraEssentialyes 表示系统必需,包管理器不可删除Homepage项目主页 URL Installed-Size安装后占用磁盘空间(KB),由构建工具自动填写
4.4 构建 .deb 包
# Level 1:最原始方式(dpkg-deb 手动打包)
# 1. 创建目录结构
mkdir -p myapp-1.0.0/DEBIAN
mkdir -p myapp-1.0.0/usr/bin
mkdir -p myapp-1.0.0/usr/share/doc/myapp
# 2. 编写 control 文件
cat > myapp-1.0.0/DEBIAN/control << 'EOF'
Package: myapp
Version: 1.0.0-1
Section: utils
Priority: optional
Architecture: amd64
Maintainer: Your Name <you@example.com>
Description: My first deb package
This is a simple example of creating a deb package manually.
EOF
# 3. 放入文件
cp myapp_script.sh myapp-1.0.0/usr/bin/myapp
chmod 755 myapp-1.0.0/usr/bin/myapp
cat > myapp-1.0.0/usr/share/doc/myapp/copyright << 'EOF'
Copyright (c) 2025 Your Name
Licensed under MIT License.
EOF
# 4. 打包
dpkg-deb --build myapp-1.0.0/
# 生成 myapp-1.0.0.deb
# 5. 命名规范(可选改名)
mv myapp-1.0.0.deb myapp_1.0.0-1_amd64.deb
# 6. 检查包质量
lintian myapp_1.0.0-1_amd64.deb
# 7. 查看包内容
dpkg -c myapp_1.0.0-1_amd64.deb
dpkg -I myapp_1.0.0-1_amd64.deb
5. 维护脚本(Maintainer Scripts)
5.1 四个脚本及其调用时机
脚本 调用时机 参数 preinst包文件解压前 install 或 upgrade 旧版本postinst包文件解压后 configure 最新版本prerm包文件删除前 remove 或 upgrade 新版本 或 deconfigurepostrm包文件删除后 remove 或 purge 或 upgrade 新版本
5.2 postinst 示例
#!/bin/bash
# DEBIAN/postinst
set -e
case " $1 " in
configure )
# 创建系统用户
if ! getent passwd myapp > /dev/null ; then
adduser --system --group --home /var/lib/myapp --no-create-home myapp
fi
# 设置目录权限
chown -R myapp:myapp /var/lib/myapp
chmod 755 /var/lib/myapp
# 启动服务
if [ -x /bin/systemctl ]; then
systemctl daemon-reload
systemctl enable myapp.service
systemctl start myapp.service || true
fi
echo "myapp 安装完成。"
;;
abort-upgrade | abort-remove | abort-deconfigure )
;;
*)
echo "postinst called with unknown argument \`$1 '" >&2
exit 1
;;
esac
exit 0
5.3 prerm 示例
#!/bin/bash
# DEBIAN/prerm
set -e
case " $1 " in
remove | upgrade | deconfigure )
# 停止服务
if [ -x /bin/systemctl ]; then
systemctl stop myapp.service || true
systemctl disable myapp.service || true
fi
;;
failed-upgrade )
;;
*)
echo "prerm called with unknown argument \`$1 '" >&2
exit 1
;;
esac
exit 0
5.4 postrm 示例
#!/bin/bash
# DEBIAN/postrm
set -e
case " $1 " in
purge )
# 删除系统用户和数据(仅 purge 时)
if getent passwd myapp > /dev/null ; then
userdel myapp
fi
rm -rf /var/lib/myapp
;;
remove | upgrade | failed-upgrade | abort-install | abort-upgrade | disappear )
;;
*)
echo "postrm called with unknown argument \`$1 '" >&2
exit 1
;;
esac
exit 0
5.5 conffiles
# DEBIAN/conffiles
# 列出被标记为配置文件的文件路径
# dpkg 不会覆盖这些文件,而会将新版本保存为 .dpkg-new
/etc/myapp/config.yml
/etc/myapp/settings.ini
/etc/logrotate.d/myapp
6. debhelper 构建系统
6.1 dh_make 初始化
# 安装打包工具
sudo apt install dh-make devscripts build-essential fakeroot lintian
# 准备源码
tar -czf myapp-1.0.0.tar.gz myapp-1.0.0/
cd myapp-1.0.0/
export DEBEMAIL = "you@example.com"
export DEBFULLNAME = "Your Name"
# 初始化 Debian 打包目录
dh_make -f ../myapp-1.0.0.tar.gz
# 选择包类型(s: single binary, m: multiple binary, l: library...)
# 通常选择 s
6.2 debian/ 目录结构
myapp-1.0.0/
├── src/ # 上游源码
└── debian/
├── changelog # 变更日志
├── control # 包元数据
├── rules # 构建规则(Makefile)
├── copyright # 版权信息
├── compat # debhelper 兼容性级别
├── install # 文件安装映射
├── dirs # 需要创建的目录
├── links # 符号链接
├── postinst # 安装后脚本
├── prerm # 删除前脚本
├── postrm # 删除后脚本
├── conffiles # 配置文件
├── watch # 监控上游新版本
└── source/
└── format # 源码格式("3.0 (quilt)")
6.3 debian/rules
#!/usr/bin/make -f
# 使用 dh 简化的最小 rules:
% :
dh $@
# 覆盖特定步骤:
override_dh_auto_configure :
./configure --prefix=/usr --sysconfdir=/etc
override_dh_auto_build :
$( MAKE )
override_dh_auto_test :
$( MAKE ) test
override_dh_auto_install :
$( MAKE ) install DESTDIR= $$ (pwd)/debian/myapp
override_dh_compress :
dh_compress -X.yml
override_dh_usrlocal :
# 禁止安装到 /usr/local
6.4 debian/install
# 格式:<源码路径> <目标路径>
src/myapp usr/bin/
src/config.yml etc/myapp/
src/systemd/myapp.service lib/systemd/system/
6.5 构建包
# 使用 debuild 构建(推荐)
debuild -us -uc
# -us 不签名源码包
# -uc 不签名 .changes 文件
# 或使用 dpkg-buildpackage
dpkg-buildpackage -us -uc -ui
# 或使用 pbuilder/cowbuilder(干净 chroot 环境)
sudo apt install pbuilder
sudo pbuilder create
sudo pbuilder build ../myapp_1.0.0-1.dsc
# 检查包
lintian ../myapp_1.0.0-1_amd64.changes
6.6 debian/changelog 格式
myapp (1.0.0-1) unstable; urgency=medium
* Initial release. (Closes: #123456)
* Added systemd service file.
* Fixed segmentation fault on amd64.
-- Your Name <you@example.com> Wed, 15 Jan 2025 10:00:00 +0800
生成 changelog 条目:
dch -i # 交互式添加新条目
dch -r "" # 标记为 release
dch --bpo # 标记为 backports 版本
7. dh 命令速查
命令 作用 dh_auto_configure自动检测并运行配置 dh_auto_build自动检测并编译 dh_auto_test自动检测并测试 dh_auto_install安装到 debian/tmp/ dh_install根据 .install 文件复制文件 dh_installdocs安装文档 dh_installman安装 man 手册 dh_installinit安装 init/systemd 脚本 dh_installsystemd安装并启用 systemd 服务 dh_installchangelogs安装 changelog dh_link创建符号链接 dh_strip剥离调试符号 dh_compress压缩文档 dh_fixperms修正文件权限 dh_makeshlibs生成共享库依赖信息 dh_shlibdeps计算共享库依赖 dh_gencontrol生成 control 文件 dh_md5sums生成 md5sums dh_builddeb打包 .deb
8. reprepro —— 本地 APT 仓库
8.1 安装与初始化
sudo apt install reprepro
# 创建仓库目录
sudo mkdir -p /srv/repo/debian
cd /srv/repo/debian
# 创建 conf/distributions
sudo mkdir -p conf
sudo tee conf/distributions << 'EOF'
Origin: My Organization
Label: Custom Debian Repository
Codename: bookworm
Architectures: amd64 i386 arm64 source
Components: main
Description: Custom package repository for Debian Bookworm
SignWith: yes
DebIndices: Packages Release . .gz .bz2
UDebIndices: Packages . .gz .bz2
DscIndices: Sources Release . .gz .bz2
EOF
8.2 添加包到仓库
# 添加单个 .deb
reprepro -b /srv/repo/debian includedeb bookworm myapp_1.0.0-1_amd64.deb
# 添加源码包
reprepro -b /srv/repo/debian includedsc bookworm myapp_1.0.0-1.dsc
# 删除包
reprepro -b /srv/repo/debian remove bookworm myapp
# 列出仓库中的包
reprepro -b /srv/repo/debian list bookworm
# 查看包信息
reprepro -b /srv/repo/debian listfilter bookworm 'Package (==myapp)'
8.3 导出仓库密钥
# 导出 GPG 公钥
gpg --export --armor "My Repo Key" > /srv/repo/debian/repo-key.asc
# 客户端导入
sudo cp repo-key.asc /etc/apt/trusted.gpg.d/my-repo.asc
# 或
sudo apt-key add repo-key.asc
8.4 HTTP 服务
# nginx 配置
sudo tee /etc/nginx/sites-available/repo << 'EOF'
server {
listen 80;
server_name repo.example.com;
root /srv/repo/debian;
location / {
autoindex on;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/repo /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
8.5 客户端配置
# 添加 deb 源
echo "deb [signed-by=/etc/apt/trusted.gpg.d/my-repo.asc] https://repo.example.com/ bookworm main" | \
sudo tee /etc/apt/sources.list.d/myrepo.list
sudo apt update
sudo apt install myapp
9. 常用开发工具
# lintian — Debian 包质量检查
sudo apt install lintian
lintian myapp_1.0.0-1_amd64.deb
lintian -i myapp_1.0.0-1_amd64.deb # 带详细说明
lintian -EviIL +pedantic myapp_1.0.0-1_amd64.deb # 最严格
# piuparts — 安装/升级/删除测试
sudo apt install piuparts
sudo piuparts myapp_1.0.0-1_amd64.deb
# pbuilder — 干净 chroot 构建
sudo apt install pbuilder
sudo pbuilder create --distribution bookworm
sudo pbuilder build myapp_1.0.0-1.dsc
# sbuild — 更专业的构建环境(Debian 开发者使用)
sudo apt install sbuild schroot
sudo sbuild-createchroot bookworm /srv/chroot/bookworm http://deb.debian.org/debian
sbuild -d bookworm myapp_1.0.0-1.dsc
# devscripts — 打包辅助脚本集
sudo apt install devscripts
dch -i # 编辑 changelog
uscan # 扫描上游新版本
debuild # 构建包
dget # 下载源码包
what-patch # 分析补丁
10. 相关资源