Browse Source

system: Add "guix system docker-image" command.

* gnu/system/vm.scm (system-docker-image): New procedure.
* guix/scripts/system.scm (system-derivation-for-action): Add a case for
  docker-image, and in that case, call system-docker-image.
  (show-help): Document docker-image.
  (guix-system): Parse arguments for docker-image.
* doc/guix.texi (Invoking guix system): Document "guix system
* gnu/system/examples/docker-image.tmpl: New file.
Chris Marusich 4 years ago
No known key found for this signature in database GPG Key ID: DD409A15D822469D
  1. 36
  2. 47
  3. 105
  4. 12


@ -20385,12 +20385,18 @@ containing at least the kernel, initrd, and bootloader data files must
be created. The @code{--image-size} option can be used to specify the
size of the image.
@cindex System images, creation in various formats
@cindex Creating system images in various formats
@item vm-image
@itemx disk-image
Return a virtual machine or disk image of the operating system declared
in @var{file} that stands alone. By default, @command{guix system}
estimates the size of the image needed to store the system, but you can
use the @option{--image-size} option to specify a value.
@itemx docker-image
Return a virtual machine, disk image, or Docker image of the operating
system declared in @var{file} that stands alone. By default,
@command{guix system} estimates the size of the image needed to store
the system, but you can use the @option{--image-size} option to specify
a value. Docker images are built to contain exactly what they need, so
the @option{--image-size} option is ignored in the case of
You can specify the root file system type by using the
@option{--file-system-type} option. It defaults to @code{ext4}.
@ -20408,6 +20414,28 @@ using the following command:
# dd if=$(guix system disk-image my-os.scm) of=/dev/sdc
@end example
When using @code{docker-image}, a Docker image is produced. Guix builds
the image from scratch, not from a pre-existing Docker base image. As a
result, it contains @emph{exactly} what you define in the operating
system configuration file. You can then load the image and launch a
Docker container using commands like the following:
image_id="$(docker load < guixsd-docker-image.tar.gz)"
docker run -e GUIX_NEW_SYSTEM=/var/guix/profiles/system \\
--entrypoint /var/guix/profiles/system/profile/bin/guile \\
$image_id /var/guix/profiles/system/boot
@end example
This command starts a new Docker container from the specified image. It
will boot the GuixSD system in the usual manner, which means it will
start any services you have defined in the operating system
configuration. Depending on what you run in the Docker container, it
may be necessary to give the container additional permissions. For
example, if you intend to build software using Guix inside of the Docker
container, you may need to pass the @option{--privileged} option to
@code{docker run}.
@item container
Return a script to run the operating system declared in @var{file}
within a container. Containers are a set of lightweight isolation


@ -0,0 +1,47 @@
;; This is an operating system configuration template for a "Docker image"
;; setup, so it has barely any services at all.
(use-modules (gnu))
(host-name "komputilo")
(timezone "Europe/Berlin")
(locale "en_US.utf8")
;; This is where user accounts are specified. The "root" account is
;; implicit, and is initially created with the empty password.
(users (cons (user-account
(name "alice")
(comment "Bob's sister")
(group "users")
(supplementary-groups '("wheel"
"audio" "video"))
(home-directory "/home/alice"))
;; Globally-installed packages.
(packages %base-packages)
;; Because the system will run in a Docker container, we may omit many
;; things that would normally be required in an operating system
;; configuration file. These things include:
;; * bootloader
;; * file-systems
;; * services such as mingetty, udevd, slim, networking, dhcp
;; Either these things are simply not required, or Docker provides
;; similar services for us.
;; This will be ignored.
(bootloader (bootloader-configuration
(bootloader grub-bootloader)
(target "does-not-matter")))
;; This will be ignored, too.
(file-systems (list (file-system
(device "does-not-matter")
(mount-point "/")
(type "does-not-matter"))))
;; Guix is all you need!
(services (list (guix-service))))


@ -23,6 +23,7 @@
(define-module (gnu system vm)
#:use-module (guix config)
#:use-module (guix docker)
#:use-module (guix store)
#:use-module (guix gexp)
#:use-module (guix derivations)
@ -30,6 +31,7 @@
#:use-module (guix monads)
#:use-module (guix records)
#:use-module (guix modules)
#:use-module (guix scripts pack)
#:use-module (guix utils)
#:use-module (guix hash)
#:use-module (guix base32)
@ -39,7 +41,9 @@
#:use-module (gnu packages base)
#:use-module (gnu packages bootloaders)
#:use-module (gnu packages cdrom)
#:use-module (gnu packages compression)
#:use-module (gnu packages guile)
#:autoload (gnu packages gnupg) (libgcrypt)
#:use-module (gnu packages gawk)
#:use-module (gnu packages bash)
#:use-module (gnu packages less)
@ -76,6 +80,7 @@
@ -377,6 +382,106 @@ the image."
#:disk-image-format disk-image-format
#:references-graphs inputs))
(define* (system-docker-image os
(name "guixsd-docker-image")
"Build a docker image. OS is the desired <operating-system>. NAME is the
base name to use for the output file. When REGISTER-CLOSURES? is not #f,
register the closure of OS with Guix in the resulting Docker image. This only
makes sense when you want to build a GuixSD Docker image that has Guix
installed inside of it. If you don't need Guix (e.g., your GuixSD Docker
image just contains a web server that is started by the Shepherd), then you
should set REGISTER-CLOSURES? to #f."
(define not-config?
(('guix 'config) #f)
(('guix rest ...) #t)
(('gnu rest ...) #t)
(rest #f)))
(define config
;; (guix config) module for consumption by (guix gcrypt).
(scheme-file "gcrypt-config.scm"
(define-module (guix config)
#:export (%libgcrypt))
;; XXX: Work around <>.
(eval-when (expand load eval)
(define %libgcrypt
#+(file-append libgcrypt "/lib/libgcrypt"))))))
(mlet %store-monad ((os-drv (operating-system-derivation os #:container? #t))
(name -> (string-append name ".tar.gz"))
(graph -> "system-graph"))
(define build
(with-imported-modules `(,@(source-module-closure '((guix docker)
(guix build utils)
(gnu build vm))
#:select? not-config?)
(guix build store-copy)
((guix config) => ,config))
;; Guile-JSON is required by (guix docker).
(string-append #+guile-json "/share/guile/site/"
(use-modules (guix docker)
(guix build utils)
(gnu build vm)
(srfi srfi-19)
(guix build store-copy))
(let* ((inputs '#$(append (list tar)
(if register-closures?
(list guix)
;; This initializer requires elevated privileges that are
;; not normally available in the build environment (e.g.,
;; it needs to create device nodes). In order to obtain
;; such privileges, we run it as root in a VM.
(initialize (root-partition-initializer
#:closures '(#$graph)
#:register-closures? #$register-closures?
#:system-directory #$os-drv
;; De-duplication would fail due to
;; cross-device link errors, so don't do it.
#:deduplicate? #f))
;; Even as root in a VM, the initializer would fail due to
;; lack of privileges if we use a root-directory that is on
;; a file system that is shared with the host (e.g., /tmp).
(root-directory "/guixsd-system-root"))
(set-path-environment-variable "PATH" '("bin" "sbin") inputs)
(mkdir root-directory)
(initialize root-directory)
(string-append "/xchg/" #$name) ;; The output file.
(cons* root-directory
(call-with-input-file (string-append "/xchg/" #$graph)
#:compressor '(#+(file-append gzip "/bin/gzip") "-9n")
#:creation-time (make-time time-utc 0 1)
#:transformations `((,root-directory -> "")))))))
;; The VM's initrd Guile doesn't support dlopen, but our "build" gexp
;; needs to be run by a Guile that can dlopen libgcrypt. The following
;; hack works around that problem by putting the "build" gexp into an
;; executable script (created by program-file) which, when executed, will
;; run using a Guile that supports dlopen. That way, the VM's initrd
;; Guile can just execute it via invoke, without using dlopen. See:
(with-imported-modules `((guix build utils))
(use-modules (guix build utils))
;; If we use execl instead of invoke here, the VM will crash with a
;; kernel panic.
(invoke #$(program-file "build-docker-image" build))))
#:make-disk-image? #f
#:single-file-output? #t
#:references-graphs `((,graph ,os-drv)))))
;;; VM and disk images.


@ -1,7 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <>
;;; Copyright © 2016 Alex Kost <>
;;; Copyright © 2016, 2017 Chris Marusich <>
;;; Copyright © 2016, 2017, 2018 Chris Marusich <>
;;; Copyright © 2017 Mathieu Othacehe <>
;;; This file is part of GNU Guix.
@ -701,7 +701,9 @@ checking this by themselves in their 'check' procedure."
("iso9660" "image.iso")
(_ "disk-image"))
#:disk-image-size image-size
#:file-system-type file-system-type))))
#:file-system-type file-system-type))
(system-docker-image os #:register-closures? #t))))
(define (maybe-suggest-running-guix-pull)
"Suggest running 'guix pull' if this has never been done before."
@ -904,6 +906,8 @@ Some ACTIONS support additional ARGS.\n"))
vm-image build a freestanding virtual machine image\n"))
(display (G_ "\
disk-image build a disk image, suitable for a USB stick\n"))
(display (G_ "\
docker-image build a Docker image\n"))
(display (G_ "\
init initialize a root file system to run GNU\n"))
(display (G_ "\
@ -1142,7 +1146,7 @@ argument list and OPTS is the option alist."
(case action
((build container vm vm-image disk-image reconfigure init
extension-graph shepherd-graph list-generations roll-back
switch-generation search)
switch-generation search docker-image)
(alist-cons 'action action result))
(else (leave (G_ "~a: unknown action~%") action))))))
@ -1171,7 +1175,7 @@ argument list and OPTS is the option alist."
(exit 1))
(case action
((build container vm vm-image disk-image reconfigure)
((build container vm vm-image disk-image docker-image reconfigure)
(unless (or (= count 1)
(and expr (= count 0)))