2023-07-15 20:37:59 +00:00
|
|
|
#+TITLE: Guix Builder
|
|
|
|
#+AUTHOR: Collin J. Doering
|
|
|
|
|
|
|
|
#+begin_abstract
|
|
|
|
This repository defines a minimal OCI container containing guix and a few other tools useful
|
|
|
|
for CI/CD jobs. The container is expected to be run from a system that already has the
|
|
|
|
~guix-daemon~ installed and running, and is most useful in the context of existing CI/CD
|
|
|
|
tools that already use an existing OCI container runtime (eg. docker, podman, etc..).
|
|
|
|
#+end_abstract
|
|
|
|
|
|
|
|
* Prerequisites
|
|
|
|
|
|
|
|
- ~guix-daemon~ installed and running on the host
|
|
|
|
- ~dockerd~ to build and run the produced image
|
|
|
|
- ~direnv~ (optional)
|
|
|
|
|
|
|
|
* Repository Structure
|
|
|
|
|
|
|
|
- ~channels.scm~ :: [[*Guix Channel File][Guix Channel File]].
|
|
|
|
- ~Dockerfile~ :: From scratch image that uses guix pack tar.gz output.
|
|
|
|
- ~Makefile~ :: Various make targets to build and run the guix-builder OCI image.
|
|
|
|
- ~manifest-dev.scm~ :: Packages required for development.
|
|
|
|
- ~manifest.scm~ :: Packages to be installed in the OCI image.
|
|
|
|
- ~.gitignore~ :: Files ignored by git.
|
|
|
|
- ~README.org~ :: Org-mode[fn:1] documentation.
|
|
|
|
- ~shell.sh~ :: Launch a containerized development shell.
|
|
|
|
|
|
|
|
** Guix Channel File
|
|
|
|
|
|
|
|
Guix channels[fn:2] allow for Guix to be customized and extended. They are also critical for
|
|
|
|
replicating a Guix system[fn:3]. To ensure reproducibility, a ~channels.scm~ file is provided
|
|
|
|
in this repository that is expected to be used during deployment. It pins external guix
|
|
|
|
channels to specific versions.
|
|
|
|
|
|
|
|
* Setup development environment
|
|
|
|
|
|
|
|
~direnv~ is the preferred and optimal way to enter a development environment. Use ~direnv allow~.
|
|
|
|
|
|
|
|
Alternatively, ~./shell.sh~ can be invoked directly
|
|
|
|
|
|
|
|
* Building the image
|
|
|
|
|
|
|
|
#+begin_src shell
|
|
|
|
make [build]
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
~build~ is optional, as its the default target.
|
|
|
|
|
2024-01-05 02:59:33 +00:00
|
|
|
* Testing and using the image locally
|
|
|
|
|
|
|
|
The easiest way to use and test the guix-builder container image is to use the provide make
|
|
|
|
target.
|
|
|
|
|
|
|
|
#+begin_src shell
|
|
|
|
make run
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
Or, if you want to run in a container with no guix store mounted.
|
|
|
|
|
|
|
|
#+begin_src shell
|
|
|
|
make run-no-store
|
|
|
|
#+end_src
|
|
|
|
|
2023-07-15 20:37:59 +00:00
|
|
|
* Using the image
|
|
|
|
|
|
|
|
Now that the OCI image has been produced, some care must be taken when running it. Namely,
|
|
|
|
the following volumes are expected to be mounted.
|
|
|
|
|
|
|
|
- ~/var/guix/daemon-socket/socket~ :: the ~guix-daemon~ socket
|
|
|
|
- ~/gnu/store~ :: The hosts guix store
|
|
|
|
|
|
|
|
Additionally, for ~guix~ to function appropriately, the ~HOME~ environment variable must be
|
|
|
|
set. This allows guix to store its cache (mandatory for many operations, eg ~guix pull~).
|
|
|
|
Depending on use-case, it is sometimes useful to retain the guix cache between container
|
|
|
|
invocations. To do so, mount a volume to ~$HOME/.cache/guix~ (replacing ~$HOME~ with what it
|
|
|
|
will be set to within the container).
|
|
|
|
|
2023-12-31 20:01:45 +00:00
|
|
|
SSL certificates are included and configured for use in the container (via the ~nss-certs~
|
2024-01-02 03:57:35 +00:00
|
|
|
package). Its not supported to use your hosts certificates, as they may be incompatible with
|
|
|
|
openssl inside of the container.
|
2023-12-31 20:01:45 +00:00
|
|
|
|
2023-07-15 20:37:59 +00:00
|
|
|
A complete example is given below, where the aforementioned volumes are mounted, ~HOME~ is
|
|
|
|
set to ~/tmp~, and a volume for retaining the guix cache between invocations is put in place.
|
|
|
|
The working directory within the container is also set with the ~-w~ option, however this is
|
|
|
|
not required.
|
|
|
|
|
|
|
|
#+begin_src shell
|
|
|
|
docker run --rm -it \
|
|
|
|
-v /var/guix/daemon-socket/socket:/var/guix/daemon-socket/socket \
|
|
|
|
-v /gnu/store:/gnu/store:ro \
|
|
|
|
-v /var/lib/ci/guix-cache:/tmp/.cache/guix \
|
|
|
|
-e HOME=/tmp \
|
|
|
|
-w /tmp \
|
|
|
|
guix-builder:latest
|
|
|
|
#+end_src
|
|
|
|
|
2024-01-05 02:59:33 +00:00
|
|
|
** Using the image with Gitea/Forgejo actions or DroneCI/WoodpeckerCI
|
2023-07-15 20:37:59 +00:00
|
|
|
|
|
|
|
The primary use-case for the image produced by this repository is for ci/cd jobs (mandatorily
|
|
|
|
on a host that is running guix-daemon itself). This allows for the hosts guix store to be
|
|
|
|
reused, allowing for a node-local caching layer, and enabling optimal ci/cd build/deploy
|
|
|
|
times.
|
|
|
|
|
|
|
|
Any ci/cd tool that can run OCI containers should be compatible with this image, though the
|
|
|
|
optimal setup assumes it provides a mechanism to mount volumes and set environment variables
|
|
|
|
(by an administrator). Both DroneCI and WoodpeckerCI allow for this, using
|
2024-01-05 02:59:33 +00:00
|
|
|
~DRONE_RUNNER_VOLUMES~ and ~WOODPECKER_BACKEND_DOCKER_VOLUMES~ respectively. Gitea/Forgejo
|
|
|
|
actions allow it via the ~container.options~ configuration value.
|
2023-07-15 20:37:59 +00:00
|
|
|
|
|
|
|
Note, in WoodpeckerCI, this functionality has not yet made it into a release (see [[https://github.com/woodpecker-ci/woodpecker/pull/1203][PR]]).
|
|
|
|
|
|
|
|
* FAQ
|
|
|
|
|
|
|
|
** Why not produce this image with ~guix pack -f docker ...~ directly?
|
|
|
|
|
|
|
|
One may ask, why not simply produce a OCI container using ~guix pack~ directly? Eg.
|
|
|
|
|
|
|
|
#+begin_src shell
|
|
|
|
guix pack -f docker -S /bin=bin --entry-point=bin/guix -m manifest.scm
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
Well, I'm glad you asked! This produces a container that has the guix store in its default
|
|
|
|
location ~/gnu/store~. Using the same method as described in [[*Using the image with DroneCI / WoodpeckerCI][Using the image with DroneCI /
|
|
|
|
WoodpeckerCI]], this container image works, however it has an implicit constraint: all store
|
|
|
|
items used within the pack must also exist in the hosts guix store. This is because the guix
|
|
|
|
store is volume mounted into the container at runtime, shadowing the already existing
|
|
|
|
~/gnu/store~ directory put in place via ~guix pack~. There are ways one could work around
|
|
|
|
this constraint, however the best solution would be to have a guix container that is
|
|
|
|
independent of the host (as described in this repository).
|
|
|
|
|
|
|
|
** What about running a ~guix-daemon~ within a container (so that builds can be completely isolated)?
|
|
|
|
|
|
|
|
This currently is not possible ... TBD (more detail)
|
|
|
|
|
|
|
|
* Footnotes
|
|
|
|
|
|
|
|
[fn:1] https://orgmode.org/
|
|
|
|
|
|
|
|
[fn:2] https://guix.gnu.org/manual/en/html_node/Channels.html
|
|
|
|
|
|
|
|
[fn:3] https://guix.gnu.org/manual/en/html_node/Replicating-Guix.html
|