Running guix package manager on top of Fedora Silverblue
Written by Sebastian Dümcke on
Tags: guix
I love the ideas behind guix, in particular the outlook to have a fully declarative system that can be reproduced on any new hardware. However, when I was playing around with guix in a virtual machine in the past, I managed to bork the system so that neither a reconfigure nor a roll-back was possible. Following the IRC channel over the past years I noticed that there are regularly issues brought up inhibiting upgrading a system or requiring manual intervention. To summarize: my impression is that guix as an operating system is lacking stability. However that should not deter you from using guix as a package manager, which already brings many great features and improvements over any other package manager, which I might present in a separate post
A few years back I have discovered Fedora Silverblue, an atomic, immutable operating system, which shares many attributes with guix. It also allows for roll-back and is somewhat declarative, in that a specific commit of the underlying OSTree defines the complete set of software installed on the system (modulo overlays). I have been using it for some time and really like it. So far every update went smoothly even when upgrading across 2 major versions. However, since Fedora Silverblue is immutable, meaning all mount points that do not contain user data are read-only, installing packages is burdensome. Luckily, I found that in combination with the guix package manager we get the best of both worlds: a rock solid base system and the ability to install any packages in any version at the same time.
Due to the immutable nature of Silverblue and its focus on FHS
compatibilty, a few steps are necessary to install guix. We will
install the store to /var/gnustore
(/var
is mutable in Silverblue)
and bind mount it to /gnu/store
to ensure we can use substitutes.
First we need to set SELinux to permissive mode. While there is documentation for SE Linux support, I could not manage to make it run under SELinux. So open vi /etc/selinux/config
and set SELINUX=permissive
Then download the latest binary release from guix and perform the following steps (mirroring what the install script does):
#unpack the guix archive on host GUIX_ARCHIVE=5i530v4c67iyq49qji2v2wxdgf5cdq5l-guix-binary.tar.xz tar xvf $GUIX_ARCHIVE #mv gnu/store to /var/gnustore and guix to /var/guix sudo mv gnu/store /var/gnustore sudo mv var/guix /var/
Add the group and users for the guix daemon
#configure groups and users on host sudo groupadd --system guixbuild for i in $(seq -w 1 10); do sudo useradd -g guixbuild -G guixbuild \ -d /var/empty -s /usr/sbin/nologin \ -c "Guix build user $i" --system \ guixbuilder$i; done
Add two systemD mount services to create the bind mount /var/gnustore -> /gnu/store
for guix. The file names are indicated in the comment.
#/etc/systemd/system/mkdir-rootfs@.service [Unit] Description=Enable mount points in / for ostree DefaultDependencies=no ConditionPathExists=!%f [Service] Type=oneshot ExecStartPre=chattr -i / ExecStart=mkdir -p '%f' ExecStopPost=chattr +i /
#/etc/systemd/system/gnu-store.mount [Unit] Description=Read-only /gnu/store for GNU Guix adapted to Silverblue After=mkdir-rootfs@gnu-store.service Wants=mkdir-rootfs@gnu-store.service Before=guix-daemon.service [Install] WantedBy=guix-daemon.service [Mount] What=/var/gnustore Where=/gnu/store Type=none Options=bind,ro
We also copy over the guix-daemon systemD service from the guix tarball to our system.
sudo cp /var/guix/profiles/per-user/root/current-guix/lib/systemd/system/guix-daemon.service /etc/systemd/system
Now we override this service definition to ensure it runs after the bind mount was created by running sudo systemctl edit guix-daemon
and adding the following:
[Unit] Wants=gnu-store.mount After=gnu-store.mount
I had some issues with the guix-daemon being loaded before the bind mount without these overrides.
Now we can enable and start the guix daemon service: sudo systemctl --now enable guix-daemon
Activate substitute servers then run guix pull, both using the root version of guix. This should then install a local guix.
sudo /var/guix/profiles/per-user/root/current-guix/bin/guix archive --authorize < /var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub sudo /var/guix/profiles/per-user/root/current-guix/bin/guix archive --authorize < /var/guix/profiles/per-user/root/current-guix/share/guix/bordeaux.guix.gnu.org.pub /var/guix/profiles/per-user/root/current-guix/bin/guix pull
After setting and sourcing the GUIX_PROFILE
variable to our local guix we have a running guix on our system:
GUIX_PROFILE="/var/home/user/.config/guix/current" . "$GUIX_PROFILE/etc/profile"
Optional: add the shell completions
#install shell completion for i in /var/guix/profiles/per-user/root/current-guix/etc/bash_completion.d/* do sudo ln -sf $i /etc/bash_completion.d/$(basename $i) done