guix: pack: Build layered images.
* guix/scripts/pack.scm (docker-image, guix-pack, %default-options, %docker-format-options, show-docker-format-options/detailed): Handle '--max-layers' option. * doc/guix.texi (Invoking guix pack): Document this. Change-Id: I90660b2421fcdde891f003469fe2e2edaac7da41master
parent
d3d3eedf7f
commit
0cf75c9b2f
|
@ -56,7 +56,7 @@ Copyright @copyright{} 2017 Andy Wingo@*
|
||||||
Copyright @copyright{} 2017, 2018, 2019, 2020, 2023 Arun Isaac@*
|
Copyright @copyright{} 2017, 2018, 2019, 2020, 2023 Arun Isaac@*
|
||||||
Copyright @copyright{} 2017 nee@*
|
Copyright @copyright{} 2017 nee@*
|
||||||
Copyright @copyright{} 2018 Rutger Helling@*
|
Copyright @copyright{} 2018 Rutger Helling@*
|
||||||
Copyright @copyright{} 2018, 2021 Oleg Pykhalov@*
|
Copyright @copyright{} 2018, 2021, 2023 Oleg Pykhalov@*
|
||||||
Copyright @copyright{} 2018 Mike Gerwitz@*
|
Copyright @copyright{} 2018 Mike Gerwitz@*
|
||||||
Copyright @copyright{} 2018 Pierre-Antoine Rouby@*
|
Copyright @copyright{} 2018 Pierre-Antoine Rouby@*
|
||||||
Copyright @copyright{} 2018, 2019 Gábor Boskovits@*
|
Copyright @copyright{} 2018, 2019 Gábor Boskovits@*
|
||||||
|
@ -7441,6 +7441,30 @@ appear multiple times on the command line.
|
||||||
guix pack -f docker --entry-point=bin/guile --entry-point-argument="--help" guile
|
guix pack -f docker --entry-point=bin/guile --entry-point-argument="--help" guile
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
@cindex maximum layers argument, for docker images
|
||||||
|
@item --max-layers=@code{n}
|
||||||
|
Specifies the maximum number of Docker image layers allowed when
|
||||||
|
building an image.
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix pack -f docker --max-layers=100 guile
|
||||||
|
@end example
|
||||||
|
|
||||||
|
This option allows you to limit the number of layers in a Docker image.
|
||||||
|
Docker images are comprised of multiple layers, and each layer adds to
|
||||||
|
the overall size and complexity of the image. By setting a maximum
|
||||||
|
number of layers, you can control the following effects:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item Disk Usage:
|
||||||
|
Increasing the number of layers can help optimize the disk space
|
||||||
|
required to store multiple images built with a similar package graph.
|
||||||
|
|
||||||
|
@item Pulling:
|
||||||
|
When transferring images between different nodes or systems, having more
|
||||||
|
layers can reduce the time required to pull the image.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
@item --expression=@var{expr}
|
@item --expression=@var{expr}
|
||||||
@itemx -e @var{expr}
|
@itemx -e @var{expr}
|
||||||
Consider the package @var{expr} evaluates to.
|
Consider the package @var{expr} evaluates to.
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
;;; Copyright © 2020 Eric Bavier <bavier@posteo.net>
|
;;; Copyright © 2020 Eric Bavier <bavier@posteo.net>
|
||||||
;;; Copyright © 2022 Alex Griffin <a@ajgrf.com>
|
;;; Copyright © 2022 Alex Griffin <a@ajgrf.com>
|
||||||
;;; Copyright © 2023 Graham James Addis <graham@addis.org.uk>
|
;;; Copyright © 2023 Graham James Addis <graham@addis.org.uk>
|
||||||
|
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
#:use-module (guix scripts build)
|
#:use-module (guix scripts build)
|
||||||
#:use-module (guix transformations)
|
#:use-module (guix transformations)
|
||||||
#:use-module ((guix self) #:select (make-config.scm))
|
#:use-module ((guix self) #:select (make-config.scm))
|
||||||
|
#:use-module ((guix docker) #:select (%docker-image-max-layers))
|
||||||
#:use-module (gnu compression)
|
#:use-module (gnu compression)
|
||||||
#:use-module (gnu packages)
|
#:use-module (gnu packages)
|
||||||
#:use-module (gnu packages bootstrap)
|
#:use-module (gnu packages bootstrap)
|
||||||
|
@ -204,10 +206,10 @@ target the profile's @file{bin/env} file:
|
||||||
arg))))
|
arg))))
|
||||||
|
|
||||||
(define (entry-point-argument-spec-option-parser opt name arg result)
|
(define (entry-point-argument-spec-option-parser opt name arg result)
|
||||||
"A SRFI-37 opion parser for the --entry-point-argument option. The spec
|
"A SRFI-37 option parser for the --entry-point-argument option. The spec
|
||||||
takes multiple occurances. The entries are used in the exec form for the
|
takes multiple occurrences. The entries are used in the exec form for the
|
||||||
docker entry-point. The values are used as parameters in conjunction with
|
docker entry-point. The values are used as parameters in conjunction with the
|
||||||
the --entry-point option which is used as the first value in the exec form."
|
--entry-point option which is used as the first value in the exec form."
|
||||||
(let ((entry-point-argument (assoc-ref result 'entry-point-argument)))
|
(let ((entry-point-argument (assoc-ref result 'entry-point-argument)))
|
||||||
(alist-cons 'entry-point-argument
|
(alist-cons 'entry-point-argument
|
||||||
(append entry-point-argument (list arg))
|
(append entry-point-argument (list arg))
|
||||||
|
@ -517,12 +519,15 @@ added to the pack."
|
||||||
localstatedir?
|
localstatedir?
|
||||||
(symlinks '())
|
(symlinks '())
|
||||||
(archiver tar)
|
(archiver tar)
|
||||||
(extra-options '()))
|
(extra-options '())
|
||||||
"Return a derivation to construct a Docker image of PROFILE. The
|
max-layers)
|
||||||
image is a tarball conforming to the Docker Image Specification, compressed
|
"Return a derivation to construct a Docker image of PROFILE. The image is a
|
||||||
with COMPRESSOR. It can be passed to 'docker load'. If TARGET is true, it
|
tarball conforming to the Docker Image Specification, compressed with
|
||||||
must a be a GNU triplet and it is used to derive the architecture metadata in
|
COMPRESSOR. It can be passed to 'docker load'. If TARGET is true, it must a
|
||||||
the image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument."
|
be a GNU triplet and it is used to derive the architecture metadata in the
|
||||||
|
image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument. If
|
||||||
|
MAX-LAYERS is not false, the image will be splitted in up to MAX-LAYERS
|
||||||
|
layers."
|
||||||
(define database
|
(define database
|
||||||
(and localstatedir?
|
(and localstatedir?
|
||||||
(file-append (store-database (list profile))
|
(file-append (store-database (list profile))
|
||||||
|
@ -576,18 +581,24 @@ the image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument."
|
||||||
(define (form-entry-point prefix entry-point entry-point-argument)
|
(define (form-entry-point prefix entry-point entry-point-argument)
|
||||||
;; Construct entry-point parameter for build-docker-image. The
|
;; Construct entry-point parameter for build-docker-image. The
|
||||||
;; first entry is constructed by prefixing the entry-point with
|
;; first entry is constructed by prefixing the entry-point with
|
||||||
;; the supplied index subsequent entries are taken from the
|
;; the supplied index, subsequent entries are taken from the
|
||||||
;; --entry-point-argument options.
|
;; --entry-point-argument options.
|
||||||
(and=> entry-point
|
(and=> entry-point
|
||||||
(lambda (entry-point)
|
(lambda (entry-point)
|
||||||
(cons* (string-append prefix "/" entry-point)
|
(cons* (string-append prefix "/" entry-point)
|
||||||
entry-point-argument))))
|
entry-point-argument))))
|
||||||
|
|
||||||
(setenv "PATH" #+(file-append archiver "/bin"))
|
(setenv "PATH"
|
||||||
|
(string-join `(#+(file-append archiver "/bin")
|
||||||
|
#+@(if max-layers
|
||||||
|
(list (file-append gzip "/bin"))
|
||||||
|
'()))
|
||||||
|
":"))
|
||||||
|
|
||||||
(let-keywords '#$extra-options #f
|
(let-keywords '#$extra-options #f
|
||||||
((image-tag #f)
|
((image-tag #f)
|
||||||
(entry-point-argument #f))
|
(entry-point-argument #f)
|
||||||
|
(max-layers #f))
|
||||||
|
|
||||||
(build-docker-image #$output
|
(build-docker-image #$output
|
||||||
(map store-info-item
|
(map store-info-item
|
||||||
|
@ -609,7 +620,8 @@ the image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument."
|
||||||
#:compressor
|
#:compressor
|
||||||
#+(compressor-command compressor)
|
#+(compressor-command compressor)
|
||||||
#:creation-time
|
#:creation-time
|
||||||
(make-time time-utc 0 1)))))))
|
(make-time time-utc 0 1)
|
||||||
|
#:max-layers max-layers))))))
|
||||||
|
|
||||||
(gexp->derivation (string-append name ".tar"
|
(gexp->derivation (string-append name ".tar"
|
||||||
(compressor-extension compressor))
|
(compressor-extension compressor))
|
||||||
|
@ -1287,6 +1299,7 @@ last resort for relocation."
|
||||||
(verbosity . 1)
|
(verbosity . 1)
|
||||||
(symlinks . ())
|
(symlinks . ())
|
||||||
(entry-point-argument . ())
|
(entry-point-argument . ())
|
||||||
|
(max-layers . ,%docker-image-max-layers)
|
||||||
(compressor . ,(first %compressors))))
|
(compressor . ,(first %compressors))))
|
||||||
|
|
||||||
(define %formats
|
(define %formats
|
||||||
|
@ -1324,7 +1337,11 @@ last resort for relocation."
|
||||||
(define %docker-format-options
|
(define %docker-format-options
|
||||||
(list (required-option 'image-tag)
|
(list (required-option 'image-tag)
|
||||||
(option '(#\A "entry-point-argument") #t #f
|
(option '(#\A "entry-point-argument") #t #f
|
||||||
entry-point-argument-spec-option-parser)))
|
entry-point-argument-spec-option-parser)
|
||||||
|
(option '("max-layers") #t #f
|
||||||
|
(lambda (opt name arg result)
|
||||||
|
(alist-cons 'max-layers (string->number* arg)
|
||||||
|
result)))))
|
||||||
|
|
||||||
(define (show-docker-format-options)
|
(define (show-docker-format-options)
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
|
@ -1336,9 +1353,12 @@ last resort for relocation."
|
||||||
Use the given NAME for the Docker image repository
|
Use the given NAME for the Docker image repository
|
||||||
|
|
||||||
-A, --entry-point-argument=COMMAND/PARAMETER
|
-A, --entry-point-argument=COMMAND/PARAMETER
|
||||||
Value(s) to use for the Docker EntryPoint arguments.
|
Value(s) to use for the Docker ENTRYPOINT arguments.
|
||||||
Multiple instances are accepted. This is only valid
|
Multiple instances are accepted. This is only valid
|
||||||
in conjunction with the --entry-point option"))
|
in conjunction with the --entry-point option
|
||||||
|
|
||||||
|
--max-layers=N
|
||||||
|
Number of image layers"))
|
||||||
(newline)
|
(newline)
|
||||||
(exit 0))
|
(exit 0))
|
||||||
|
|
||||||
|
@ -1651,7 +1671,9 @@ Create a bundle of PACKAGE.\n"))
|
||||||
(list #:image-tag
|
(list #:image-tag
|
||||||
(assoc-ref opts 'image-tag)
|
(assoc-ref opts 'image-tag)
|
||||||
#:entry-point-argument
|
#:entry-point-argument
|
||||||
(assoc-ref opts 'entry-point-argument)))
|
(assoc-ref opts 'entry-point-argument)
|
||||||
|
#:max-layers
|
||||||
|
(assoc-ref opts 'max-layers)))
|
||||||
('deb
|
('deb
|
||||||
(list #:control-file
|
(list #:control-file
|
||||||
(process-file-arg opts 'control-file)
|
(process-file-arg opts 'control-file)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
;;; Copyright © 2017-2021, 2023 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2017-2021, 2023 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
|
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
|
||||||
;;; Copyright © 2021, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
;;; Copyright © 2021, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
||||||
|
;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -29,6 +30,7 @@
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
#:use-module (guix modules)
|
#:use-module (guix modules)
|
||||||
#:use-module (guix utils)
|
#:use-module (guix utils)
|
||||||
|
#:use-module ((guix build utils) #:select (%store-directory))
|
||||||
#:use-module (gnu packages)
|
#:use-module (gnu packages)
|
||||||
#:use-module ((gnu packages base) #:select (libc-utf8-locales-for-target))
|
#:use-module ((gnu packages base) #:select (libc-utf8-locales-for-target))
|
||||||
#:use-module (gnu packages bootstrap)
|
#:use-module (gnu packages bootstrap)
|
||||||
|
@ -250,6 +252,54 @@
|
||||||
(mkdir #$output)))))))
|
(mkdir #$output)))))))
|
||||||
(built-derivations (list check))))
|
(built-derivations (list check))))
|
||||||
|
|
||||||
|
(unless store (test-skip 1))
|
||||||
|
(test-assertm "docker-layered-image + localstatedir"
|
||||||
|
(mlet* %store-monad
|
||||||
|
((guile (set-guile-for-build (default-guile)))
|
||||||
|
(profile -> (profile
|
||||||
|
(content (packages->manifest (list %bootstrap-guile)))
|
||||||
|
(hooks '())
|
||||||
|
(locales? #f)))
|
||||||
|
(tarball (docker-image "docker-pack" profile
|
||||||
|
#:symlinks '(("/bin/Guile" -> "bin/guile"))
|
||||||
|
#:localstatedir? #t
|
||||||
|
#:max-layers 100))
|
||||||
|
(check (gexp->derivation
|
||||||
|
"check-tarball"
|
||||||
|
(with-imported-modules '((guix build utils))
|
||||||
|
#~(begin
|
||||||
|
(use-modules (guix build utils)
|
||||||
|
(ice-9 match))
|
||||||
|
|
||||||
|
(define bin
|
||||||
|
(string-append "." #$profile "/bin"))
|
||||||
|
|
||||||
|
(define store
|
||||||
|
(string-append "." #$(%store-directory)))
|
||||||
|
|
||||||
|
(setenv "PATH" (string-append #$%tar-bootstrap "/bin"))
|
||||||
|
(mkdir "base")
|
||||||
|
(with-directory-excursion "base"
|
||||||
|
(invoke "tar" "xvf" #$tarball))
|
||||||
|
|
||||||
|
(match (find-files "base" "layer.tar")
|
||||||
|
((layers ...)
|
||||||
|
(for-each (lambda (layer)
|
||||||
|
(invoke "tar" "xvf" layer)
|
||||||
|
(invoke "chmod" "--recursive" "u+w" store))
|
||||||
|
layers)))
|
||||||
|
|
||||||
|
(when
|
||||||
|
(and (file-exists? (string-append bin "/guile"))
|
||||||
|
(file-exists? "var/guix/db/db.sqlite")
|
||||||
|
(file-is-directory? "tmp")
|
||||||
|
(string=? (string-append #$%bootstrap-guile "/bin")
|
||||||
|
(readlink bin))
|
||||||
|
(string=? (string-append #$profile "/bin/guile")
|
||||||
|
(readlink "bin/Guile")))
|
||||||
|
(mkdir #$output)))))))
|
||||||
|
(built-derivations (list check))))
|
||||||
|
|
||||||
(unless store (test-skip 1))
|
(unless store (test-skip 1))
|
||||||
(test-assertm "squashfs-image + localstatedir"
|
(test-assertm "squashfs-image + localstatedir"
|
||||||
(mlet* %store-monad
|
(mlet* %store-monad
|
||||||
|
|
Reference in New Issue