-
-
Notifications
You must be signed in to change notification settings - Fork 239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support --installroot
#1308
Comments
Attempts with ParuPreparation is a bit more involved vs earlier alternative tooling mentioned, but this is mostly specific to # `base-devel` + `git` packages needed for AUR support:
$ pacman --noconfirm -Syu git >/dev/null
# Installing AUR packages as root is forbidden, create a user as a workaround:
$ useradd --system --create-home --shell /usr/bin/nologin automated
# Grant passwordless sudo access for the `automated` user:
# NOTE: Alternatively only permit passwordless for the commands used:
# - Basic support: `NOPASSWD: /usr/bin/pacman`
# - `--chroot` support: `NOPASSWD: ^/usr/bin/(pacman|install|mkarchroot|cp|arch-nspawn)$`
$ printf 'automated ALL=(ALL) NOPASSWD: ALL\n' | tee /etc/sudoers.d/50-passwordless
# Get Paru (quicker than manually building):
$ PARU_URL=https://github.com/Morganamilo/paru/releases/download/v2.0.4/paru-v2.0.4-x86_64.tar.zst \
&& curl -fsSL "${PARU_URL}" \
| tar --extract --zstd --directory /usr/local/bin paru
# Equivalent to the current `paru-bin` AUR package:
$ paru --version
paru v2.0.4 - libalpm v15.0.0
# NOTE: Installing a package to `--root` requires pacman DB initialized:
$ mkdir -p /rootfs/var/lib/pacman/ && pacman --root /rootfs -Sy
sudo --user automated paru --root /rootfs --noconfirm -S vscodium-bin This doesn't quite work though, TLDR is:
With
|
With
|
let mut cmd = Command::new(&self.sudo); | |
cmd.arg("arch-nspawn") | |
.arg("-C") | |
.arg(tmp.path()) | |
.arg("-M") | |
.arg(&self.makepkg_conf) | |
.arg(dir); |
I presently don't have access to an Arch Linux host or guest (other than via a container), but presumably that feature may handle the buildtime deps failure shown in the prior comment with paru --root
? (assuming these two options are compatible together?).
This is how --chroot
fails in the container (host is Fedora 40 with Podman):
# Requires `mkarchroot` provided via `devtools` package:
$ sudo --user automated paru --chroot --noconfirm -S vscodium-bin >/dev/null
error: can not use chroot builds: devtools is not installed
$ pacman --noconfirm -Syu devtools >/dev/null
# 1st time:
$ sudo --user automated paru --chroot --noconfirm -S vscodium-bin >/dev/null
unshare: unshare failed: Operation not permitted
==> ERROR: Failed to install all packages
error: failed to run: sudo mkarchroot -C /tmp/.tmpIzQydV -M /etc/makepkg.conf /var/lib/aurbuild/x86_64/root base-devel
The error differs when run again:
# 2nd time:
$ sudo --user automated paru --chroot --noconfirm -S vscodium-bin >/dev/null
cp: cannot create directory '/var/lib/aurbuild/x86_64/root/var/lib/pacman/sync': No such file or directory
==> ERROR: '/var/lib/aurbuild/x86_64/root' does not appear to be an Arch chroot.
error: failed to run: sudo arch-nspawn -C /tmp/.tmpW3MrW2 -M /etc/makepkg.conf /var/lib/aurbuild/x86_64/root --bind /var/cache/pacman/pkg/ pacman -Syu --noconfirm
Even when /var/lib/aurbuild/x86_64/root/var/lib/pacman/sync
is created it still fails detection as an "Arch chroot":
# Again but with the directory created:
$ mkdir -p /var/lib/aurbuild/x86_64/root/var/lib/pacman/sync
$ sudo --user automated paru --chroot --noconfirm -S vscodium-bin >/dev/null
==> ERROR: '/var/lib/aurbuild/x86_64/root' does not appear to be an Arch chroot.
error: failed to run: sudo arch-nspawn -C /tmp/.tmpFbpgmJ -M /etc/makepkg.conf /var/lib/aurbuild/x86_64/root --bind /var/cache/pacman/pkg/ pacman -Syu --noconfirm
Since this would later defer arch-nspawn
to calling systemd-nspawn
(Format: arch-nspawn <args> <chroot dir> <systemd-nspawn args>
) and the container is not running systemd as PID 1 (not really viable for Docker AFAIK?), this approach for --chroot
is likely incompatible.
paru --chroot
troubleshooting notes
arch-nspawn
seems to rely on an "Arch chroot" being created (via mkarchroot
guide, mkarchroot
source) which when run manually also fails, as unshare --mount
requires granting the non-default capability CAP_SYS_ADMIN
:
$ podman run --rm -it \
--env CHROOT=/tmp/rootfs \
archlinux:base-devel bash
$ pacman --noconfirm -Syu devtools >/dev/null \
&& mkdir $CHROOT && mkarchroot $CHROOT/root glibc >/devnull
error: restricting filesystem access failed because the landlock ruleset could not be applied!
unshare: unshare failed: Operation not permitted
==> ERROR: Failed to install all packages
Usage of mount
seems to be restricted (even when the required CAP_SYS_ADMIN
was already granted). AFAIK when capabilities alone are insufficient the cause tends to be security mechanisms like:
- Seccomp (syscall restriction, managed by seccomp policy profiles that vary by container runtime)
- LSMs (which provide MAC to restrict resource access), such as AppArmor and SELinux.
In this case the failure appears to be due to SELinux, which would need --security-opt label:disable
to opt-out (a similar solution for AppArmor may also require opt-out of seccomp?):
# With `SYS_ADMIN` capability added
$ podman run --rm -it \
--cap-add SYS_ADMIN \
--env CHROOT=/tmp/rootfs \
archlinux:base-devel bash
$ pacman --noconfirm -Syu devtools >/dev/null \
&& mkdir $CHROOT && mkarchroot $CHROOT/root glibc >/devnull
==> Creating install root at /tmp/rootfs/root
mount: /tmp/rootfs/root/proc: cannot mount proc read-only.
dmesg(1) may have more information after failed mount system call.
==> ERROR: failed to setup chroot /tmp/rootfs/root
==> ERROR: Failed to install all packages
Now the problem is missing pacman.conf
and makepkg.conf
which can be copied via supported args to mkarchroot
:
# With `--security-opt` added
$ podman run --rm -it \
--cap-add SYS_ADMIN \
--security-opt label:disable \
--env CHROOT=/tmp/rootfs \
archlinux:base-devel bash
$ pacman --noconfirm -Syu devtools >/dev/null \
&& mkdir $CHROOT && mkarchroot $CHROOT/root glibc >/devnull
Initializing machine ID from random generator.
error: config file /tmp/rootfs/root/etc/pacman.conf could not be read: No such file or directory
error parsing '/tmp/rootfs/root/etc/pacman.conf'
error: config file /tmp/rootfs/root/etc/pacman.conf could not be read: No such file or directory
error parsing '/tmp/rootfs/root/etc/pacman.conf'
sed: can't read /tmp/rootfs/root/etc/pacman.conf: No such file or directory
grep: /tmp/rootfs/root/etc/makepkg.conf: No such file or directory
Failed to parse --bind(-ro)= argument : Invalid argument
Also needs CAP_AUDIT_CONTROL
:
# With `mkarchroot -C path -M path` added
$ podman run --rm -it \
--cap-add SYS_ADMIN \
--security-opt label:disable \
--env CHROOT=/tmp/rootfs \
archlinux:base-devel bash
$ pacman --noconfirm -Syu devtools >/dev/null \
&& mkdir $CHROOT && mkarchroot -C /etc/pacman.conf -M /etc/makepkg.conf $CHROOT/root glibc >/devnull
Initializing machine ID from random generator.
Failed to reset audit login UID. This probably means that your kernel is too
old and you have audit enabled. Note that the auditing subsystem is known to
be incompatible with containers on old kernels. Please make sure to upgrade
your kernel or to off auditing with 'audit=0' on the kernel command line before
using systemd-nspawn. Sleeping for 5s... (Operation not permitted)
Failed to allocate scope: Unit devtools-.slice failed to load properly, please adjust/correct and reload service manager: Invalid argument
Attempted to remove disk file system under "/run/systemd/nspawn/propagate/arch-nspawn-346", and we can't allow that.
# Regarding the `systemd-nspawn` audit error,
# The kernel is not old.. This error is actually from missing `CAP_AUDIT_CONTROL`.
$ uname -a
Linux 375bc7bfc33e 6.10.6-200.fc40.x86_64 #1 SMP PREEMPT_DYNAMIC Mon Aug 19 14:09:30 UTC 2024 x86_64 GNU/Linux
dbus-uuidgen
is needed to populate /etc/machine-id
? (the Arch chroot generates it's own /etc/machine-id
regardless):
# With `AUDIT_CONTROL` capability added
$ podman run --rm -it \
--cap-add SYS_ADMIN,AUDIT_CONTROL \
--security-opt label:disable \
--env CHROOT=/tmp/rootfs \
archlinux:base-devel bash
$ pacman --noconfirm -Syu devtools >/dev/null \
&& mkdir $CHROOT && mkarchroot -C /etc/pacman.conf -M /etc/makepkg.conf $CHROOT/root glibc >/devnull
Initializing machine ID from random generator.
Failed to retrieve machine ID: No such file or directory
Attempted to remove disk file system under "/run/systemd/nspawn/propagate/arch-nspawn-311", and we can't allow that.
$ cat /etc/machine-id
cat: /etc/machine-id: No such file or directory
Now we have a failure related to interacting via DBUS:
# With `dbus-uuidgen` added
$ podman run --rm -it \
--cap-add SYS_ADMIN,AUDIT_CONTROL \
--security-opt label:disable \
--env CHROOT=/tmp/rootfs \
archlinux:base-devel bash
$ pacman --noconfirm -Syu devtools >/dev/null \
&& dbus-uuidgen --ensure=/etc/machine-id \
&& mkdir $CHROOT && mkarchroot -C /etc/pacman.conf -M /etc/makepkg.conf $CHROOT/root glibc >/devnull
Initializing machine ID from random generator.
Failed to open bus: No such file or directory
Attempted to remove disk file system under "/run/systemd/nspawn/propagate/arch-nspawn-454", and we can't allow that.
# DBUS socket was created, but DBUS is not running:
$ ls /run/dbus
containers
$ ps -ax | grep dbus
350 pts/0 S+ 0:00 grep dbus
# DBUS on the host system:
$ exit
$ ps -ax | grep dbus
719 ? Ss 0:40 /usr/bin/dbus-broker-launch --scope system --audit
726 ? S 53:54 dbus-broker --log 4 --controller 9 --machine-id 6c8d4e00f69f439e82010ed67591a30f --max-bytes 536870912 --max-fds 4096 --max-matches 131072 --audit
3746378 pts/0 S+ 0:00 grep --color=auto dbus
Bind mount the expected socket (NOTE: Bind mounting the entire directory as read-only would prevent the container creating the /run/dbus/containers
directory):
# With `--volume` added
$ podman run --rm -it \
--cap-add SYS_ADMIN,AUDIT_CONTROL \
--security-opt label:disable \
--volume /run/dbus/system_bus_socket:/run/dbus/system_bus_socket:ro \
--env CHROOT=/tmp/rootfs \
archlinux:base-devel bash
$ pacman --noconfirm -Syu devtools >/dev/null \
&& dbus-uuidgen --ensure=/etc/machine-id \
&& mkdir $CHROOT && mkarchroot -C /etc/pacman.conf -M /etc/makepkg.conf $CHROOT/root glibc >/devnull
Initializing machine ID from random generator.
Failed to allocate scope: Unit devtools-.slice failed to load properly, please adjust/correct and reload service manager: Invalid argument
Attempted to remove disk file system under "/run/systemd/nspawn/propagate/arch-nspawn-597", and we can't allow that.
NOTE: If instead running the container with --volume /run/dbus:/run/dbus:rw
, you'll get the same output with an additional error after the Invalid argument
line: Parent died too early
(even when using the exact same /etc/machine-id
as the host).
NOTE: The error "Failed to allocate scope" seems to be reported in this 2017 bug report for devtools
arch-nspawn
command, regarding the args for systemd-nspawn
. However as --keep-unit
isn't compatible with slices, modifying the arch-nspawn
shell script as they suggest won't help.
This specific snippet from the arch-nspawn
script shows the default systemd-nspawn
args declared:
# /usr/sbin/arch-nspawn
nspawn_args=(
--quiet
--directory="$working_dir"
--setenv="PATH=/usr/local/sbin:/usr/local/bin:/usr/bin"
--register=no
--slice="devtools-$(systemd-escape "${SUDO_USER:-$USER}")"
--machine="arch-nspawn-$$"
--as-pid2
--console=autopipe
--timezone=off
)
We can see that the --slice
arg defining the name devtools-.slice
was intended to include a user as a suffix.
Both SUDO_USER
and USER
environment variables are populated when sudo
is called as root (according to the sudoers
man page). Since they're obviously not set, either one of those needs to be set in advance or instead leverage using sudo
(as one might when using paru
).
# With `USER=root` added
$ podman run --rm -it \
--cap-add SYS_ADMIN,AUDIT_CONTROL \
--security-opt label:disable \
--volume /run/dbus/system_bus_socket:/run/dbus/system_bus_socket:ro \
--env CHROOT=/tmp/rootfs \
archlinux:base-devel bash
$ pacman --noconfirm -Syu devtools >/dev/null \
&& dbus-uuidgen --ensure=/etc/machine-id \
&& mkdir $CHROOT && USER=root mkarchroot -C /etc/pacman.conf -M /etc/makepkg.conf $CHROOT/root glibc >/devnull
Initializing machine ID from random generator.
Failed to get our control group: Protocol driver not attached
Attempted to remove disk file system under "/run/systemd/nspawn/propagate/arch-nspawn-2550", and we can't allow that.
The "Failed to get our control group: Protocol driver not attached" error is from systemd-nspawn
. I have no clue how to progress from this point, this is probably as far as you can "easily" get with Docker?
This complication compared to the support from alternative package managers should be demonstrated quite clearly above. Granted this seems to only be an issue for packages that are built, not only installed (which AFAIK is only what the other package managers support).
|
I don't expect much progress addressing this request as the feature is probably quite niche for users of Paru.
Feel free to close this issue. I have detailed everything below as a form of documentation, not all of it was straight-forward to troubleshoot, so it may help others.
The
--chroot
feature seems like the wrong approach, even if it's bugs were resolved.paru --root
is roughly equivalent and works, so long as there is no buildtime deps for an AUR package.Additionally, Arch's packages aren't exactly tailored to be minimal in size (
glibc
is 50MB, mainly excess in/usr/{include,lib,share}
), due to packages not being split as much or having-dev
/-devel
variants for headers (I am aware thatpacman.conf
can take a similar approach to thechisel
tool but manually via declaringNoExtract
patterns, although excluding/usr/include/*
this way doesn't work if you have buildtime deps).Details
This feature request is similar to an attempt by a user described here with
--root
.The intent is to install packages to a new rootfs location without any package manager or other packages that weren't part of the package resolution.
That rootfs could then be used as a minimal container image for running a service:
As I've detailed below
pacman
seems to provide similar functionality with--root
, although this needs some extra workarounds with Paru for AUR packages.Paru could improve:
--root
by automating the preparation required to use--root
.makedepends
?), there's already--removemake
which I assume could be paired with it.--chroot
feature is broken, it seems necessary to runchmod 644 /var/lib/aurbuild/x86_64/root/etc/pacman.conf
to leverage it (only seems to be used with AUR packages). If it was also intended to be a clean root environment each time, that doesn't seem to be the case (see thecado-nfs-git
notes below).Reference - Equivalent feature support in other package managers
In Fedora (dnf) and OpenSUSE (zypper), these RPM package managers support this feature via
--installroot
:One disadvantage with Zypper is due to some default security constraints to container environments (reduced capabilities/privilege for the root user than the actual root user on the host), the way it installs packages with this feature doesn't always go smoothly. DNF doesn't have this issue AFAIK.
Canonical has been working on a similar tool
chisel
, for their DEB packages that is also focused on the bare minimum package contents. Fedora and OpenSUSE with the--installroot
approach for Python 3.12 instead would bring in glibc and other necessary deps and weighs in at 80-100MB. For comparisonchisel
is 27MB:nix
can sort of do the same, but doesn't play as well in a container environment with maintainers refusing to support a--installroot
equivalent feature (instead deferring to their internal image builder tooling, rather than creating an image vianix
within a container).The text was updated successfully, but these errors were encountered: