Arch Linux 自定义系统打包与分发

掌握 archiso 构建自定义 Live ISO、搭建私有仓库、mkarchroot 干净编译环境——从个人定制到企业级部署。


1. 核心工具概览

工具用途安装
mkarchiso构建自定义 Live ISOpacman -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 archiso

2.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
EOF

2.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.service

2.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.service

2.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"
)
EOF

2.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-build

2.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@localhost

2.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.sh

3. 自定义仓库 —— 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 custom

3.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.gz

3.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/myapp

3.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 8080

3.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.sh

4. 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.zst

4.3 更新 chroot

# 更新 chroot 中的包
arch-nspawn ~/chroot/root pacman -Syu

4.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.sh

5. 离线安装包制作

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/repo

5.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-firmware

6. archinstall 自动化

6.1 生成默认配置

# 启动 archinstall,配置完后会保存配置
archinstall --config /tmp/user_configuration.json

6.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 --silent

7. 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自定义 ISOarchiso + airootfs
批量服务器部署PXE + 自动化dnsmasq + nginx + archinstall
离线局域网部署离线仓库 ISOpacstrap + 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 客户端无 IPDHCP 配置错误检查 dnsmasq 日志
chroot 构建失败依赖不全-I 安装本地依赖

10. 相关资源