Guix package management on Ubuntu

Recently I've been using Guix to run the latest versions of applications on top of Ubuntu. Guix is an advanced package manager that has a rolling release and advanced capabilities like transactions. This gives me the advantage of Ubuntu's hardware testing and QA for the core [1] , while also being able to use the latest versions of applications through Guix. It also means I can minimise Flatpak/Snap packages which I find inelegant and annoying. This post covers some of the benefits of Guix and covers basic usage.

The first thing to know is that Guix is both a package manager and an entire Linux [2] distribution. I'm using it as a package manager on top of Ubuntu (22.04 LTS). Guix is worth considering if you want:

Unsurprisingly there are trade-offs in this approach that are worth knowing about:

Wow, that section is a lot longer than I was expecting! Lets get to installing Guix. Rather than installing on our main machine I'm going to cover how to install it in a container/VM on Ubuntu 22.04 LTS. That way we can play around with it without any risk to our main system.

Creating a system container for Guix

On Ubuntu the system containers (LXC/LXD) capabilities are installed by default so it's easy to get started. In this example my main machine is called ``dev-host``, and the container instance we'll install Guix inside is called ``guix-host1`` - the prompt shows where we're running the command.

  • Set-up LXD

    Lets first start by checking that we're on LXD 5.0 or greater. If you haven't used LXD then you'll need to init it:

    dev-host:$ snap info lxd
    [lots of output]
    tracking:     5.0/stable/ubuntu-22.04
    [lots of output]
    dev-host:$ lxd init

    I'm not going to cover how to configure LXD, if you accept the defaults it should work. If you're stuck there's lots of great information on the LXD forums and in the documentation.

    As we noted above Guix uses a lot of disk space, so make sure that the LXD storage pool is pointing to a location where there's plenty of available space.

    dev-host:$ lxc storage list
  • Start a container for Guix

    We're now ready to start our container instance.

    # check that the user is in the lxd group
    dev-host:$ groups
    <user> adm cdrom sudo dip plugdev lxd
    # list the available ubuntu images
    dev-host:$ lxc image list images: ubuntu
    # create a container instance called guix-host1
    dev-host:$ lxc launch ubuntu:22.04 guix-host1
    # check that it's now running
    dev-host:$ lxc list

    At this point we have a container instance (guix-host1) running, so we now need to connect to it.

  • Add a normal user to the container

    We could just install Guix using the root user in the container, but that would be a very realistic test of how it would work on a normal host. We'll create a normal user and SSH into the container as if it was a remote host.

    # connect to the container instance
    dev-host:$ lxc shell guix-host1
    # remove the default ubuntu user and add our normal username
    # we also want this user to be able to do sudo commands
    root@guix-host1:# deluser ubuntu
    root@guix-host1:# adduser <username>
    root@guix-host1:# usermod -aG sudo <username>
  • Install the SSH server

    We install the SSH server and set-up our users .ssh directory so we can copy the public key in.

    root@guix-host1:# apt install openssh-server -y
    # edit /etc/ssh/sshd_config and allow PubkeyAuthentication
    PubkeyAuthentication yes
    # restart the SSHD server
    root@guix-host1:# sudo systemctl restart ssh.service
    # create the ssh config directory for our normal user
    root@guix-host1:# su <username>
    user@guix-host1:$ mkdir /home/<username>/.ssh
    # Disconnect from the LXC instance
    user@guix-host1:$ exit
  • Push the users public key to the container

    The next step is to push the key to the container instance.

    dev-host:$ lxc file push ~.ssh/ guix-host1/home/steve/.ssh/authorised_keys

    At this point you should be able to SSH into the container using the IP address that shows when running lxc ls.

  • Configure name resolution

    It's a bit annoying using the IP address, so we'll set up name resolution so we can use the containers name to SSH into it:

    # check the IP address and range that the bridged network is using
    dev-host:$ lxc network get lxdbr0 ipv4.address
    dev-host:$ lxd network get lxdbr0 dns.domain

    The default is for LXD to set-up a bridged network (lxdbr0) so we check this to see the IP address and whether it has a domain associated (none by default). We can then tell systemd-resolvd about it by doing the following:

    dev-host:$ sudo resolvectl dns lxdbr0
    dev-host:$ sudo resolvectl domain lxdbr0 '~lxd'
    # if we've been successful we can now do name resolution
    dev-host:$ ping guix-host1.lxd

    That was a lot of steps, but now the system container is ready and we can install Guix.

Installing Guix in a Container

To install the Guix package manager go to their download area and grab the right binary: for me that is GNU Guix 1.3.0 Binary. It's worth reading through their installation instructions to make sure nothing has changed.

  • Run the GUIX installer

    The installer is fairly straightforward it will ask some basic questions and then set-up the Guix build daemon.

    # ssh into the guix container
    dev-host:$ ssh guix-host1.lxd
    user@guix-host1:$ cd /tmp
    user@guix-host1:$ wget
    user@guix-host1:$ chmod +x
    # run the installer
    user@guix-host1:$ sudo /tmp/
    # restart the guix daemon
    user@guix-host1:$ sudo systemctl status guix-daemon.service

    It's worth knowing that the way Guix works is to run a single build daemon on the host which has a store with all the packages in it that have been build/downloaded onto this host. Each time a user runs a command they're interacting with this store via the daemon..

  • Check the env variables

    The Guix installer configures the users shell with a default profile, this is stored in $GUIX_PROFILE. Disconnect and reconnect to the container to check that the environment variables are being sourced correctly.

    # check env vars are being sourced
    user@guix-host1:$ exit
    dev-host:$ ssh guix-host1.lxd
    user@guix-host1:$ echo $GUIX_PROFILE
    # check that the GUIX command is part of PATH
    user@guix-host1$ guix show hello
    [output with information about the hello package]

    Guix requires the ability to write to the /gnu/store directory, but this is not allowed by a system container normally. If you try to do any command that writes to the package store it will error:

    user@guix-host1$ guix install hello
    guix install: error: remounting /gnu/store writeable: Permission denied
  • Allow writing to /gnu/store

    We can allow the container to write to /gnu/store by removing the confines that the AppArmor profile has on it: there's probably an elegant way to do this where you just allow it to write to /gnu/store, but this works!

    user@guix-host1$ exit
    # on our dev host we stop the container and edit the configuration
    dev-host:$ lxc stop guix-host1
    dev-host:$ lxc config set guix-host1 raw.lxc "lxc.apparmor.profile=unconfined"
    dev-host:$ guix start guix-host1
    dev-host:$ ssh guix-host1.lxd
  • Install Locale for the Guix build daemon

    Before we start playing with Guix we need to install a locale which the Guix build daemon can use. If we don't do this it leaves an annoying error in the systemctl status message: although I don't think it's actually harmful.

    # install the locales into the root users default profile
    user@guix-host1:$ sudo -i guix install glibc-locales
    user@guix-host1:$ sudo systemctl restart guix-daemon.service
    user@guix-host1:$ sudo systemctl status guix-daemon.service
  • Install Guix locale for our user

    The same thing applies for the normal user, Guix needs to know the locale that it's using.

    user@guix-host1:$ guix install glibc-locales
    user@guix-host1:$ localectl set-locale en_GB.UTF-8

    As I'm using GB English I set it to en_GB.UTF-8, if you're not sure what it should be you can check how it's configured on your main machine. To check that it's actually worked disconnect and reconnect to the container:

    user@guix-host1: exit
    dev-host:$ ssh guix-host1.lxd
    # If the Guix Locale path is configured we're all set
    user@guix-host1:$ echo $GUIX_LOCPATH
  • Install Name Service Cache Daemon (NSCD)

    I have no idea what NSCD does, and can find some content saying that it can cause problems. However, the Guix manual has a section for Application Set-up which says it should be installed.

    user@guix-host1:$ sudo apt install nscd
  • Update the Guix build daemon

    The version of the Guix daemon that we installed is probably out of date compared to the latest version in the repository and consequently the commands that Guix understands. The build daemon runs the guix command that is installed by the root user. So to update the daemon we update roots guix package definitions.

    user@guix-host1:$ sudo -i guix pull
    [this will take a while as it downloads the updated repository]
    user@guix-host1:$ sudo systemctl restart guix-daemon.service
    user@guix-hsot1:$ sudo systemctl status guix-daemon.service
  • Upgrade Guix for our normal user

    Now we need to update the package list for our normal user and upgrade any packages we've installed. We do this with:

    # see which packages we have installed - should be just glibc-locales
    user@guix-host1:$ guix package --list-installed
    glibc-locales   2.33    out     /gnu/store/ixzmi6614baf4w37qfjgqrv8hwsl8jcv-glibc-locales-2.33
    # update the definitions from the Guix repository
    user@guix-host1:$ guix pull
    # read any news
    user@guix-host1:$ guix pull --news
    user@guix-host1:$ guix pull --news --details
    # update any packages
    user@guix-host1:$ guix upgrade

Trouble Shooting Guix installation

If you have problems with the installer then the extensive manual is the place to start as it's very comprehensive. Some things I've seen:

  • Make sure you can write to /gnu
    If you can't create or write to the /gnu directory the installation process will fail. For a system container this means we have to remove the AppArmor profile that is preventing this - see the command above.
  • Make sure that /gnu doesn't already exist
    If the installer finds /gnu/store or /gnu it will fail as it thinks there's an existing installation.
  • Make sure executables are allowed in /tmp
    When I installed Guix on a main host I couldn't get the installer to run correctly and then had problems later on running Guix: eventually I tracked this down to now allowing executables in /tmp.

Final Thoughts

Congratulations, you now have Guix installed inside an Ubuntu 22.04 LTS system container (lxd). You're ready to start using Guix. But, wow this is quite long enough for a single blog post, so I'm going to stop here! If you're not ready to stop - how about continuing by reading the Guix Reference manual and then come along to the second part.

If you successfully install Guix, or have problems I'd love to hear from you either way!

[1]I use the core kernel, ubuntu-minimal, X Windows (ubuntu-desktop) and XFCE Desktop from Ubuntu: I want thse to be stable and they don't need to change. My user-space programs like utilities and graphical programs are all from Guix.
[2]If your first thought was, "He should have said GNU/Linux there" then beware that this post is likely to have other areas where I haven't obeyed the FSF's orthodoxy, and where I focus on pragmatism over principle. On your blog you can do what you want.
[3]See the Reproducible builds site for more and compare Guix capabilities to the SLSA requirements.

Posted in Tech Sunday 26 September 2021
Tagged with tech ubuntu guix