Arch Linux 自定义系统打包与分发
掌握 archiso 构建自定义 Live ISO、搭建私有仓库、mkarchroot 干净编译环境——从个人定制到企业级部署。
1. 核心工具概览
| 工具 | 用途 | 安装 |
|---|---|---|
mkarchiso | 构建自定义 Live ISO | pacman -S archiso |
repo-add | 创建本地 pacman 仓库 | 预装 |
mkarchroot | 创建干净 chroot 编译环境 | pacman -S devtools |
makechrootpkg | 在 chroot 中构建包 | pacman -S devtools |
makepkg | 从 PKGBUILD 构建包 | pacman -S base-devel |
2. archiso —— 构建自定义 Live ISO
2.1 安装
sudo pacman -S archiso2.2 Profile 结构
Archiso 提供两个模板:
| Profile | 用途 | 特点 |
|---|---|---|
baseline | 最小化 Live 系统 | 极少预装软件,纯命令行 |
releng | 完整安装介质 | 官方 ISO 所用模板,包含安装工具 |
ls /usr/share/archiso/configs/
# baseline/ releng/releng profile 目录结构:
releng/
├── airootfs/ # 叠加到 Live 系统根目录的文件
│ └── etc/
│ ├── hostname
│ ├── locale.conf
│ ├── systemd/network/
│ └── systemd/system/ # 启用的 systemd 服务
├── efiboot/ # EFI 引导配置
├── syslinux/ # BIOS 引导配置
├── grub/ # GRUB 配置
├── packages.x86_64 # 要安装的包列表
├── pacman.conf # 构建时使用的 pacman 配置
└── profiledef.sh # profile 定义文件
2.3 创建自定义 Profile
mkdir -p ~/archlive
cp -r /usr/share/archiso/configs/releng/* ~/archlive/2.4 自定义 packages.x86_64
vim ~/archlive/packages.x86_64# 基础系统(必须保留)
base
linux
linux-firmware
mkinitcpio
mkinitcpio-archiso
# 引导程序
grub
efibootmgr
# 网络工具
networkmanager
iwd
openssh
curl
wget
bind
# 文件系统工具
dosfstools
e2fsprogs
btrfs-progs
xfsprogs
ntfs-3g
lvm2
# 编辑器与工具
vim
nano
git
htop
btop
tmux
rsync
unzip
p7zip
# 硬件信息
dmidecode
lshw
pciutils
usbutils
smartmontools
hdparm
# 中文支持
noto-fonts-cjk
fcitx5
fcitx5-chinese-addons
fcitx5-gtk
fcitx5-qt
fcitx5-configtool
# 开发工具(可选)
base-devel
python
nodejs
npm
go
# 安装器
archinstall
# 自定义软件(你的团队需要预装的工具)
# alacritty
# firefox
# docker
# zsh
2.5 自定义 airootfs(文件系统叠加)
airootfs/ 目录中的文件会直接复制到 Live 系统根目录:
# 自定义主机名
echo "archcustom" > ~/archlive/airootfs/etc/hostname
# 自定义 locale
echo "LANG=zh_CN.UTF-8" > ~/archlive/airootfs/etc/locale.conf
# 创建 locale.gen
mkdir -p ~/archlive/airootfs/etc/
cat > ~/archlive/airootfs/etc/locale.gen << 'EOF'
en_US.UTF-8 UTF-8
zh_CN.UTF-8 UTF-8
EOF
# 自定义 vconsole
echo "KEYMAP=us" > ~/archlive/airootfs/etc/vconsole.conf
# 预置 pacman 镜像列表
mkdir -p ~/archlive/airootfs/etc/pacman.d/
cat > ~/archlive/airootfs/etc/pacman.d/mirrorlist << 'EOF'
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
Server = https://mirrors.aliyun.com/archlinux/$repo/os/$arch
EOF
# 自定义 root 的 .bashrc
mkdir -p ~/archlive/airootfs/root/
cat > ~/archlive/airootfs/root/.bashrc << 'EOF'
alias ll='ls -alF --color=auto'
alias la='ls -A --color=auto'
alias l='ls -CF --color=auto'
export EDITOR=vim
PS1='\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]\$ '
EOF
# 预置 SSH 配置
mkdir -p ~/archlive/airootfs/etc/ssh/
cat > ~/archlive/airootfs/etc/ssh/sshd_config.d/custom.conf << 'EOF'
PermitRootLogin yes
PasswordAuthentication yes
EOF2.6 启用 systemd 服务
# 创建服务链接目录
mkdir -p ~/archlive/airootfs/etc/systemd/system/multi-user.target.wants/
mkdir -p ~/archlive/airootfs/etc/systemd/system/network-online.target.wants/
# 启用 NetworkManager
ln -sf /usr/lib/systemd/system/NetworkManager.service \
~/archlive/airootfs/etc/systemd/system/multi-user.target.wants/NetworkManager.service
ln -sf /usr/lib/systemd/system/NetworkManager-wait-online.service \
~/archlive/airootfs/etc/systemd/system/network-online.target.wants/NetworkManager-wait-online.service
# 启用 SSH
ln -sf /usr/lib/systemd/system/sshd.service \
~/archlive/airootfs/etc/systemd/system/multi-user.target.wants/sshd.service
# 启用 Docker(如果安装了)
ln -sf /usr/lib/systemd/system/docker.service \
~/archlive/airootfs/etc/systemd/system/multi-user.target.wants/docker.service2.7 自定义启动脚本
# 创建首次登录时运行的脚本
mkdir -p ~/archlive/airootfs/usr/local/bin/
cat > ~/archlive/airootfs/usr/local/bin/live-setup.sh << 'SCRIPT'
#!/bin/bash
echo "============================================"
echo " 自定义 Arch Linux Live 系统"
echo " 版本: $(date +%Y.%m.%d)"
echo "============================================"
echo ""
echo "可用工具:"
echo " archinstall - 交互式安装向导"
echo " nmtui - 网络配置(TUI)"
echo " htop - 系统监控"
echo " tmux - 终端复用"
echo ""
locale-gen 2>/dev/null
if ! ip route | grep -q default; then
echo "[提示] 未检测到网络连接,请运行 nmtui 配置网络"
fi
SCRIPT
chmod 755 ~/archlive/airootfs/usr/local/bin/live-setup.sh
# 创建 systemd 服务
mkdir -p ~/archlive/airootfs/etc/systemd/system/
cat > ~/archlive/airootfs/etc/systemd/system/live-setup.service << 'EOF'
[Unit]
Description=Live System Setup
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/live-setup.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
# 启用服务
mkdir -p ~/archlive/airootfs/etc/systemd/system/multi-user.target.wants/
ln -sf /etc/systemd/system/live-setup.service \
~/archlive/airootfs/etc/systemd/system/multi-user.target.wants/live-setup.service2.8 自定义 profiledef.sh
cat > ~/archlive/profiledef.sh << 'EOF'
#!/usr/bin/env bash
# shellcheck disable=SC2034
iso_name="archlinux-custom"
iso_label="ARCH_$(date +%Y%m)"
iso_publisher="My Organization <https://example.com>"
iso_application="Custom Arch Linux Live/Install"
iso_version="$(date +%Y.%m.%d)"
install_dir="arch"
buildmodes=('iso')
bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito'
'uefi-ia32.grub.esp' 'uefi-x64.grub.esp'
'uefi-ia32.grub.eltorito' 'uefi-x64.grub.eltorito')
arch="x86_64"
pacman_conf="pacman.conf"
airootfs_image_type="squashfs"
airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M')
file_permissions=(
["/etc/shadow"]="0:0:400"
["/usr/local/bin/live-setup.sh"]="0:0:755"
)
EOF2.9 压缩方式选择
# 在 profiledef.sh 中配置不同的压缩策略
# zstd — 平衡压缩率与速度(推荐)
airootfs_image_tool_options=('-comp' 'zstd' '-Xcompression-level' '15' '-b' '1M')
# xz — 最小体积(慢)
airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M')
# lz4 — 最快(体积较大)
airootfs_image_tool_options=('-comp' 'lz4')2.10 构建 ISO
# 构建(需要 root 权限)
sudo mkarchiso -v -w /tmp/archiso-build -o ~/archlive/out ~/archlive/
# 参数说明:
# -v 详细输出
# -w <dir> 工作目录(临时文件,需 5-10GB 空间)
# -o <dir> ISO 输出目录
# 最后一个参数 profile 目录
# 构建完成后查看
ls -lh ~/archlive/out/
# archlinux-custom-2025.01.15-x86_64.iso
# 清理构建目录(再次构建前需要)
sudo rm -rf /tmp/archiso-build2.11 测试 ISO(QEMU)
sudo pacman -S qemu-full edk2-ovmf
# BIOS 模式测试
qemu-system-x86_64 \
-m 2G \
-cdrom ~/archlive/out/archlinux-custom-*.iso \
-boot d \
-enable-kvm \
-cpu host \
-smp 2
# UEFI 模式测试
qemu-system-x86_64 \
-m 2G \
-cdrom ~/archlive/out/archlinux-custom-*.iso \
-boot d \
-enable-kvm \
-cpu host \
-smp 2 \
-bios /usr/share/edk2/x64/OVMF.4m.fd
# 带硬盘的完整测试(模拟安装过程)
qemu-img create -f qcow2 /tmp/test-disk.qcow2 20G
qemu-system-x86_64 \
-m 4G \
-cdrom ~/archlive/out/archlinux-custom-*.iso \
-drive file=/tmp/test-disk.qcow2,format=qcow2 \
-boot d \
-enable-kvm \
-cpu host \
-smp 4 \
-nic user,hostfwd=tcp::2222-:22
# SSH 进入测试
ssh -p 2222 root@localhost2.12 构建大小优化
# 精简策略(在 packages.x86_64 中控制)
# - 不要在 Live ISO 中包含过多大型软件(如完整 DE)
# - 用 base-devel 替代单独的编译工具
# - 排除文档、man page(在 airootfs 中清理)
# 创建清理脚本
cat > ~/archlive/airootfs/usr/local/bin/cleanup-live.sh << 'SCRIPT'
#!/bin/bash
rm -rf /usr/share/man/*
rm -rf /usr/share/doc/*
rm -rf /usr/share/info/*
rm -rf /usr/share/gtk-doc/*
rm -rf /var/cache/pacman/pkg/*
find /usr/lib -name '*.a' -delete
find /usr/lib -name '*.la' -delete
SCRIPT
chmod 755 ~/archlive/airootfs/usr/local/bin/cleanup-live.sh3. 自定义仓库 —— repo-add
3.1 创建本地仓库
# 创建仓库目录
sudo mkdir -p /srv/repo/custom/x86_64
# 复制自己构建的包到仓库目录
cp ~/builds/*.pkg.tar.zst /srv/repo/custom/x86_64/
# 使用 repo-add 生成仓库数据库
repo-add /srv/repo/custom/x86_64/custom.db.tar.gz \
/srv/repo/custom/x86_64/*.pkg.tar.zst
# 验证
pacman -Sl custom3.2 repo-add 完整用法
# 基本语法
repo-add [--options] <数据库文件路径> <包文件...>
# 添加包
repo-add /srv/repo/custom/x86_64/custom.db.tar.gz myapp-1.0.0-1-x86_64.pkg.tar.zst
# 添加并签名
repo-add --sign /srv/repo/custom/x86_64/custom.db.tar.gz myapp-1.0.0-1-x86_64.pkg.tar.zst
# 从数据库中删除包
repo-remove /srv/repo/custom/x86_64/custom.db.tar.gz myapp
# 显示仓库内容
repo-add -l /srv/repo/custom/x86_64/custom.db.tar.gz
# 验证完整性
repo-add --verify /srv/repo/custom/x86_64/custom.db.tar.gz3.3 签名仓库
# 生成 GPG 密钥
gpg --full-generate-key
# 选择 RSA and RSA, 4096 bits
# 导出公钥
gpg --export --armor "My Repo Key" > /srv/repo/custom/repo-key.asc
# 签名单个包
gpg --detach-sign --no-armor /srv/repo/custom/x86_64/myapp-1.0.0-1-x86_64.pkg.tar.zst
# 签名整个仓库数据库
repo-add --sign /srv/repo/custom/x86_64/custom.db.tar.gz \
/srv/repo/custom/x86_64/*.pkg.tar.zst
# 客户端导入密钥
sudo pacman-key --add repo-key.asc
sudo pacman-key --lsign-key <KEY_ID>3.4 pacman 客户端配置
# /etc/pacman.conf 中配置自定义仓库
# 本地仓库(最高优先级放在最上面)
[custom]
SigLevel = Optional TrustAll
Server = file:///srv/repo/custom/$arch
# HTTP 仓库
[custom]
SigLevel = Required DatabaseOptional
Server = https://repo.example.com/archlinux/custom/$arch
# 多个镜像(fallback)
[custom]
SigLevel = Required DatabaseOptional
Server = https://repo1.example.com/archlinux/custom/$arch
Server = https://repo2.example.com/archlinux/custom/$arch# 同步新仓库
sudo pacman -Sy
# 验证仓库可用
pacman -Sl custom
# 安装自定义仓库中的包
sudo pacman -S custom/myapp3.5 HTTP 仓库服务
# 方法 1:nginx
sudo pacman -S nginx
sudo cat > /etc/nginx/nginx.conf << 'EOF'
worker_processes auto;
events { worker_connections 1024; }
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
server {
listen 80;
server_name repo.example.com;
location /archlinux/custom/ {
alias /srv/repo/custom/;
autoindex on;
}
}
}
EOF
sudo systemctl enable --now nginx
# 方法 2:darkhttpd(轻量级)
sudo pacman -S darkhttpd
darkhttpd /srv/repo --port 8080
# 方法 3:Python 临时测试
cd /srv/repo && python -m http.server 80803.6 自动化仓库维护
# 脚本:自动扫描新包并更新数据库
cat > /usr/local/bin/update-repo.sh << 'SCRIPT'
#!/bin/bash
set -e
REPO_DIR="/srv/repo/custom/x86_64"
DB_FILE="$REPO_DIR/custom.db.tar.gz"
cd "$REPO_DIR"
# 查找所有包文件
mapfile -t pkgs < <(find . -maxdepth 1 -name '*.pkg.tar.zst' -printf '%f\n' | sort -V)
# 重建数据库
rm -f "$DB_FILE" "$DB_FILE.sig" "$DB_FILE.old"
repo-add --sign "$DB_FILE" "${pkgs[@]}"
echo "仓库更新完成,包含 ${#pkgs[@]} 个包"
SCRIPT
chmod +x /usr/local/bin/update-repo.sh4. mkarchroot —— 干净编译环境
4.1 安装与创建
sudo pacman -S devtools
# 创建 chroot 根目录
mkarchroot ~/chroot/root base-devel
# 参数说明:
# - ~/chroot/root 是 chroot 的根目录
# - base-devel 是安装在 chroot 中的基础包组
# - 首次创建需要下载,约 1-2GB 空间4.2 在 chroot 中构建包
# 进入 chroot 环境
mkarchroot -r ~/chroot/root
# 或使用 makechrootpkg(推荐)
cd ~/pkgbuilds/myapp
makechrootpkg -c -r ~/chroot
# 参数说明:
# -c 清理 chroot(删除上次构建的残留)
# -r ~/chroot 指定 chroot 根目录
# -I <pkg> 安装额外本地包到 chroot
# 以普通用户身份构建(需要 sudo 权限)
sudo makechrootpkg -c -r ~/chroot
# 安装多个本地依赖
makechrootpkg -c -r ~/chroot -I ~/builds/dep1.pkg.tar.zst -I ~/builds/dep2.pkg.tar.zst4.3 更新 chroot
# 更新 chroot 中的包
arch-nspawn ~/chroot/root pacman -Syu4.4 多 chroot 管理
# 为不同架构或不同目的创建多个 chroot
sudo mkarchroot ~/chroot/root-x86_64 base-devel
sudo mkarchroot ~/chroot/root-testing base-devel testing-meta
# 切换 chroot 中的仓库
# 编辑 ~/chroot/root-*/etc/pacman.conf 和 ~/chroot/root-*/etc/pacman.d/mirrorlist
# 列出所有 chroot
ls ~/chroot/4.5 自动化 CI 构建
# CI 脚本示例
cat > /usr/local/bin/ci-build.sh << 'EOF'
#!/bin/bash
set -euo pipefail
PKGBUILD_DIR="$1"
CHROOT_DIR="$HOME/chroot/root"
OUTPUT_DIR="$HOME/builds/output"
# 确保 chroot 存在
if [ ! -d "$CHROOT_DIR/usr" ]; then
mkarchroot "$CHROOT_DIR" base-devel
fi
# 更新 chroot
arch-nspawn "$CHROOT_DIR" pacman -Syu --noconfirm
# 构建
cd "$PKGBUILD_DIR"
sudo makechrootpkg -c -r "$CHROOT_DIR"
# 复制构建产物
mkdir -p "$OUTPUT_DIR"
cp *.pkg.tar.zst "$OUTPUT_DIR/"
echo "构建完成: $(ls $OUTPUT_DIR/*.pkg.tar.zst)"
EOF
chmod +x /usr/local/bin/ci-build.sh5. 离线安装包制作
5.1 下载包及全部依赖
# 方法 1:使用 pacman 下载但不安装
mkdir -p /srv/offline-repo
sudo pacman -Syw --cachedir /srv/offline-repo \
base linux linux-firmware grub efibootmgr \
networkmanager vim openssh
# 方法 2:递归下载所有依赖
pactree -lu base linux linux-firmware networkmanager vim | \
xargs -I {} sudo pacman -Sw --cachedir /srv/offline-repo --noconfirm {}5.2 创建离线仓库
# 生成仓库数据库
repo-add /srv/offline-repo/offline.db.tar.gz \
/srv/offline-repo/*.pkg.tar.zst
# 打包为归档
tar -cf /tmp/offline-repo.tar -C /srv offline-repo/
# 制作 U 盘离线仓库
dd if=/dev/zero of=/tmp/offline-repo.img bs=1M count=4096
mkfs.ext4 /tmp/offline-repo.img
sudo mkdir /mnt/repo && sudo mount /tmp/offline-repo.img /mnt/repo
sudo cp -r /srv/offline-repo/* /mnt/repo/
sudo umount /mnt/repo5.3 使用离线仓库
# 在目标机器上挂载离线仓库
sudo mount /dev/sdb1 /mnt/repo
# 配置 pacman 使用本地仓库
echo -e '\n[offline]\nSigLevel = Optional TrustAll\nServer = file:///mnt/repo' | \
sudo tee -a /etc/pacman.conf
# 正常使用
sudo pacman -Sy
sudo pacstrap /mnt base linux linux-firmware6. archinstall 自动化
6.1 生成默认配置
# 启动 archinstall,配置完后会保存配置
archinstall --config /tmp/user_configuration.json6.2 配置文件结构
{
"config_version": "2.7.0",
"bootloader": "grub-install",
"hostname": "archserver",
"kernels": ["linux", "linux-lts"],
"locale_config": {
"kb_layout": "us",
"sys_enc": "UTF-8",
"sys_lang": "zh_CN.UTF-8"
},
"mirror_config": {
"custom_mirrors": [
"https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch",
"https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch"
]
},
"network_config": {"type": "nm"},
"ntp": true,
"packages": ["vim", "git", "htop", "docker", "openssh", "tmux"],
"services": ["sshd", "NetworkManager", "docker"],
"timezone": "Asia/Shanghai",
"version": "2.7.0"
}6.3 无人值守安装
# 从配置文件安装
archinstall --config /srv/http/auto-config.json --silent
# PXE 场景:通过内核参数传入配置 URL
# archinstall --config http://192.168.1.1/auto-config.json --silent7. CI/CD 自动化构建 ISO
7.1 GitHub Actions
# .github/workflows/build-iso.yml
name: Build Custom Arch ISO
on:
push:
branches: [main]
schedule:
- cron: '0 2 1 * *'
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
container:
image: archlinux:latest
options: --privileged
steps:
- uses: actions/checkout@v4
- name: Install build tools
run: |
pacman -Syu --noconfirm
pacman -S --noconfirm archiso git
- name: Build ISO
run: |
mkarchiso -v -w /tmp/iso-build -o /tmp/iso-out ./archiso/
- name: Checksums
run: |
cd /tmp/iso-out
sha256sum *.iso > SHA256SUMS
cat SHA256SUMS
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: arch-custom-iso
path: /tmp/iso-out/*7.2 本地自动化脚本
#!/bin/bash
# build-iso-local.sh
set -euo pipefail
PROFILE_DIR="./archiso"
OUT_DIR="./output"
LOG_FILE="./build-$(date +%Y%m%d-%H%M%S).log"
echo "=== 构建开始: $(date) ===" | tee "$LOG_FILE"
if [ ! -f "$PROFILE_DIR/profiledef.sh" ]; then
echo "错误: 未找到 profiledef.sh" | tee -a "$LOG_FILE"
exit 1
fi
mkdir -p "$OUT_DIR"
sudo mkarchiso -v -w /tmp/iso-build -o "$OUT_DIR" "$PROFILE_DIR" 2>&1 | tee -a "$LOG_FILE"
cd "$OUT_DIR"
sha256sum *.iso > SHA256SUMS
ls -lh *.iso | tee -a "$LOG_FILE"
echo "构建完成!" | tee -a "$LOG_FILE"8. 实战应用场景
| 场景 | 方案 | 核心工具 |
|---|---|---|
| 团队标准化 Linux | 自定义 ISO | archiso + airootfs |
| 批量服务器部署 | PXE + 自动化 | dnsmasq + nginx + archinstall |
| 离线局域网部署 | 离线仓库 ISO | pacstrap + repo-add |
| 软件包分发 | 私有 HTTP 仓库 | repo-add + nginx |
| 安全打包审计 | 干净 chroot 构建 | mkarchroot + makechrootpkg |
| 持续集成 | CI/CD 自动构建 | GitHub Actions + archiso |
9. 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 构建失败:找不到包 | 包名错误或仓库未同步 | pacman -Sy 检查包名 |
| ISO 无法启动 | 引导配置错误 | 检查 grub/syslinux 配置,QEMU 测试 |
| 空间不足 | /tmp 分区太小 | 用 -w 指定其他分区 |
| 仓库数据库损坏 | repo-add 中断 | 删除 .db.tar.gz 重建 |
| PXE 客户端无 IP | DHCP 配置错误 | 检查 dnsmasq 日志 |
| chroot 构建失败 | 依赖不全 | 用 -I 安装本地依赖 |
10. 相关资源
- 官方 archiso 文档: https://wiki.archlinux.org/title/Archiso
- devtools 文档: https://wiki.archlinux.org/title/DeveloperWiki:Building_in_a_clean_chroot
- repo-add 手册: https://man.archlinux.org/man/repo-add.8
- archinstall 文档: https://wiki.archlinux.org/title/Archinstall
- 官方下载: https://archlinux.org/download/
- 清华镜像: https://mirrors.tuna.tsinghua.edu.cn/archlinux/
- Arch 安装指南
- pacman 包管理高级
- AUR 打包与上传
- 跨发行版系统打包总论