目标
snapd 有自己的官方 core 包,这个 core 包可以看做是一个基础的 rootfs。现有的业务程序依赖一个特定版本的 rootfs,不能在官方的 snap core 包上运行,需要用现有的 rootfs 制作一个 snap core 包来使用。
尝试构建一个第三方的 core 包的过程
初步编写的 snapcraft.yaml 文件内容:
name: test-rootfs
version: '1'
summary: Runtime environment based on vpp container
description: |
The base snap based on the Ubuntu 22.04 release.
type: base
architectures:
- amd64
assumes:
- snapd2.55.5
confinement: strict
grade: stable
environment:
LD_LIBRARY_PATH: ${SNAP_LIBRARY_PATH}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}:$SNAP/lib:$SNAP/usr/lib:$SNAP/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu
PATH: $SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH
parts:
file-copy:
plugin: dump
source: /root/vpp-rootfs
stage:
- bin
- boot
- dev
- etc
- home
- lib
- lib32
- lib64
- libx32
- media
- mnt
- opt
- run
- sbin
- srv
- tmp
- usr
- var
拷贝 rootfs 文件并执行 snapcraft 构建,尝试上传制作好的包,有如下报错信息:
longyu@longyu-virtual-machine:/tmp$ snapcraft upload --release=stable test-rootfs_1_amd64.snap
Status: processing - (2.0s)
Status: processing
Issues while processing snap:g
- missing required mountpoints: /proc, /root, /sys, /usr/lib/snapd, /usr/local/share/fonts, /usr/share/fonts, /var/cache/fontconfig, /var/lib/snapd, /var/snap
- (NEEDS REVIEW) type 'base' not allowed
- found errors in file output: unusual mode 'rwxr-sr-x' for entry './usr/bin/chage', unusual mode 'rwsr-xr-x' for entry './usr/bin/chfn', unusual mode 'rwsr-xr-x' for entry './usr/bin/chsh', unusual mode 'rwxr-sr-x' for entry './usr/bin/expiry', unusual mode 'rwsr-xr-x' for entry './usr/bin/gpasswd', unusual mode 'rwsr-xr-x' for entry './usr/bin/mount', unusual mode 'rwsr-xr-x' for entry './usr/bin/newgrp', unusual mode 'rwsr-xr-x' for entry './usr/bin/passwd', unusual mode 'rwsr-xr-x' for entry './usr/bin/su', unusual mode 'rwsr-xr-x' for entry './usr/bin/umount', unusual mode 'rwxr-sr-x' for entry './usr/bin/wall', unusual mode 'rwxr-sr-x' for entry './usr/sbin/pam_extrausers_chkpwd', unusual mode 'rwxr-sr-x' for entry './usr/sbin/unix_chkpwd', unusual mode 'rwxrwsr-x' for entry './var/local', unusual mode 'rwxrwsr-x' for entry './var/mail'
Full execution log: '/home/longyu/.local/state/snapcraft/log/snapcraft-20230905-174851.673611.log'
报错信息中有如下三个问题:
- 缺少必要的挂载点如 /proc、/root、/sys 等目录
- base 类型 snap 包需要 REVIEW
- rootfs 中的文件中有特殊权限,如 suid 等
第一个跟第三个问题比较容易解决,第二个问题看上去不太容易整。
本地编译尝试使用本地生成的三方 core 包
修改 yaml 文件,指定使用本地三方 core 包,编译 snap 包时有如下报错信息:
root@ubuntu:/home/longyu/snap/l2fwd/snap# snapcraft --destructive-mode --debug
Failed to install or refresh snap 'test-rootfs'.
'test-rootfs' does not exist or is not available on channel 'latest/stable'.
Use `snap info test-rootfs` to get a list of channels the snap is available on.
网上搜索到的解决方法:
https://snapcraft.io/docs/releasing-your-app
https://snapcraft.io/docs/public-private-unlisted-snaps
总结一下就是将编译生成的包推送到 snap-store 进行 release,实际尝试发现 base 类型的包并不能直接推送,需要指定 reviewer,在 review 通过后才能 release,同时 base 包的目录结构以及部分目录的权限也有要求,需要整改。
如何解决使用本地编译生成的 core 包的问题?
1. 官方使用方式
严格控制 core 包的 release,需要 REVIEW,流程相对复杂。
2. 修改 snapcraft 源码方式
对 snapcraft 的源码并不熟悉,修改代码的成本过高。
3. 手动修改、安装现有的 core 包,替换内容为自定义的 rootfs 内容
- 执行 unsquashfs 解压现有 core 包到指定目录
- 删除解压出来的 rootfs 中的旧目录,保留部分必要的空目录,然后复制新的 rootfs 目录(需要去掉所有使用 suid 执行的程序)
- 执行
mksquashfs rootfs xxx.snap -comp xz
重新生成 snap 包 - 将新生成的 snap 包替换到 /var/lib/snapd/snaps/ 目录中
- 重启系统,重新挂载 snap 包,此时新的 core 包生效
使用如下命令手动拷贝 rootfs:
rm -rf ./bin/
cp ../../bin/ ./ -rf
rm -rf ./bin
cp -rf ../../bin/ ./
rm -rf ./etc/
cp -rf ../../etc/ ./
rm -rf ./run/
cp -rf ../../run/ ./
rm -rf ./usr
cp -rf ../../usr/ ./
rm -rf ./var
cp -rf ../../var/ ./
mkdir ./usr/lib/snapd
mkdir -p ./usr/local/share/fonts ./usr/share/fonts ./var/cache/fontconfig ./var/lib/snapd ./var/snap
cp ./var-bak/lib/snapd/ ./var/lib/ -rf
备注:cp 执行后,suid 权限自动丢失,没有再额外处理权限问题。
执行上述操作后,测试验证可以正常使用。
总结
snap 是一个跨发行版的包管理框架,当实际业务系统有在多个发行版运行的场景时,使用 snap 这样的框架能够实现一次开发无需修改多发行版运行的效果,减少了业务系统适配多个发行版的工作量。
虽然 snap 有着这样的优点,但是特定的业务系统并不一定能够使用到。一般来说业务系统都有自己的依赖,在这个依赖中最基础的是 rootfs。snap 框架虽然也提供了多种不同的 rootfs core 包供用户使用,对于特定的依赖却并不支持,自定义开发也显得困难重重,毕竟很难绕过闭源的 snap store。
从另外一个方面想,直接使用 snap 自己的生态提供的组件能够上述问题,却需要额外的适配工作量,需要根据实际情况进行取舍。