~jl2/docker-build

9143eafbae030c7473967d99d52be8c3adb1e2f8 — Jeremiah LaRocco 2 years ago master
Initial commit.
A  => .gitignore +5 -0
@@ 1,5 @@
*.fasl
*.*fsl
*.abcl
*.cls
*.abcl-tmp

A  => LICENSE +13 -0
@@ 1,13 @@
Copyright (c) 2022 Jeremiah LaRocco <jeremiah_larocco@fastmail.com>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

A  => README.md +14 -0
@@ 1,14 @@
# docker-build
### _Jeremiah LaRocco <jeremiah_larocco@fastmail.com>_

This is a project to package Common Lisp applications in Docker.

See ./project.org for more information.

## License

ISC

Copyright (c) 2022 Jeremiah LaRocco <jeremiah_larocco@fastmail.com>



A  => docker-build.asd +26 -0
@@ 1,26 @@
;; docker-build.asd
;;
;; Copyright (c) 2022 Jeremiah LaRocco <jeremiah_larocco@fastmail.com>

;; Permission to use, copy, modify, and/or distribute this software for any
;; purpose with or without fee is hereby granted, provided that the above
;; copyright notice and this permission notice appear in all copies.

;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

(asdf:defsystem #:docker-build
  :description "Package Common Lisp applications in Docker."
  :author "Jeremiah LaRocco <jeremiah_larocco@fastmail.com>"
  :license  "ISC"
  :version "0.0.1"
  :serial t
  :depends-on (#:j-utils #:alexandria #:uiop)
  :components ((:file "package")
               (:file "docker-build"))
  :in-order-to ((test-op (test-op docker-build.test))))

A  => docker-build.lisp +67 -0
@@ 1,67 @@
;; docker-build.lisp
;;
;; Copyright (c) 2022 Jeremiah LaRocco <jeremiah_larocco@fastmail.com>

;; Permission to use, copy, modify, and/or distribute this software for any
;; purpose with or without fee is hereby granted, provided that the above
;; copyright notice and this permission notice appear in all copies.

;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

(in-package :docker-build)

(defun host-lisp ()
  (cons (lisp-implementation-type)
        (lisp-implementation-version)))

(defun make-container (package
                       &key
                         (lisp (host-lisp))
                         (container-name package)
                         (dockerfile (asdf:system-relative-pathname package "Dockerfile"))
                         (evaluate-form 'main)
                         (linux-distro "debian")
                         (extra-lisp-arguments)
                         (port-map)
                         (os-extra-package-list)
                         (lisp-extra-package-list))
  "Create a Dockerfile for running a Lisp package in Docker."
  )

(defun start (package &key (eval nil))
  "Start package in a previously build Docker container."
  )

(defmacro eval-in-docker ((&rest rest
                           &key
                             (package :docker-package)
                             (lisp (host-lisp))
                             (container-name package)
                             (dockerfile (asdf:system-relative-pathname package "Dockerfile"))
                             (linux-distro "debian")
                             (extra-lisp-arguments)
                             (port-map)
                             (os-extra-package-list)
                             (lisp-extra-package-list)
                           )
                          &body body)
  "Evaluate @,body in a specific Common Lisp running in a Docker container.
Creates a Docker container for the Lisp if necessary"

  ;; These are forwarded to make-container via the &rest parameter
  (declare (ignorable lisp container-name dockerfile linux-distro
                      extra-lisp-arguments port-map os-extra-package-list
                      lisp-extra-package-list))

  (let ((args-without-package (remove package (remove :package rest :test #'equal) :test #'equal)))
    (apply #'make-container package args-without-package)
    (start package :eval
           `(list
             (in-package ,package)
             @,body))))

A  => docker-build.test.asd +41 -0
@@ 1,41 @@
;; docker-build.test.asd
;;
;; Copyright (c) 2022 Jeremiah LaRocco <jeremiah_larocco@fastmail.com>

;; Permission to use, copy, modify, and/or distribute this software for any
;; purpose with or without fee is hereby granted, provided that the above
;; copyright notice and this permission notice appear in all copies.

;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

(in-package :cl-user)

(defpackage :docker-build.test-asd
  (:use :cl :asdf))

(in-package :docker-build.test-asd)

(asdf:defsystem #:docker-build.test
  :description "Test docker-build"
  :author "Jeremiah LaRocco <jeremiah_larocco@fastmail.com>"
  :license  "ISC"
  :version "0.0.1"
  :serial t

  :depends-on (:docker-build
               :fiveam)

  :components ((:module "t"
                :components
                ((:file "package"))))

  :perform (test-op
            :after (op c)
            (eval
             (read-from-string "(every #'fiveam::TEST-PASSED-P (5am:run :docker-build))"))))

A  => docker-templates/sbcl.Dockerfile +1 -0
@@ 1,1 @@
FROM debian

A  => package.lisp +24 -0
@@ 1,24 @@
;; package.lisp
;;
;; Copyright (c) 2022 Jeremiah LaRocco <jeremiah_larocco@fastmail.com>

;; Permission to use, copy, modify, and/or distribute this software for any
;; purpose with or without fee is hereby granted, provided that the above
;; copyright notice and this permission notice appear in all copies.

;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

(defpackage :docker-build
  (:nicknames :db)

  (:use #:cl #:j-utils #:alexandria)
  (:export #:make-container
           #:host-lisp
           #:start
           #:eval-in-docker))

A  => project.org +110 -0
@@ 1,110 @@
* docker-build
** About
This is a package to package Common Lisp applications in Docker.

** License
ISC

Copyright (c) 2022 Jeremiah LaRocco <jeremiah_larocco@fastmail.com>

* Idea
Automatically create Docker containers for Common Lisp applications.

Ideally, this would look like:

#+begin_src lisp
  ;; Load Docker Build in the host Lisp
  (ql:quickload :docker-build)

  ;; Build container using the host Lisp
  ;; Docker file goes into (asdf:system-relative-pathname :my-package "Dockerfile")
  (db:make-container :my-package)

  ;; Run it in Docker
  (db:start :my-package)
#+end_src

Another possibility is to specify a Common Lisp implementation:

#+begin_src lisp
  ;; Load Docker Build in the host Lisp
  (ql:quickload :docker-build)

  ;; Build a container using the latest SBCL release
  (db:make-container :my-package
                     :lisp-dialect :sbcl)

  ;; Run it in Docker
  (db:start :my-package)
#+end_src

Some other options that should exist:
#+begin_src lisp
  ;; Load Docker Build in the host Lisp
  (ql:quickload :docker-build)

  ;; Build a container using the latest SBCL release
  (db:make-container :my-package

                     ;; Specific version
                     :lisp :ccl-1.12.1

                     ;; Default is (asdf:system-relative-pathname :my-package "Dockerfile")
                     :dockerfile "~/Dockerfile"

                     ;; Default is '(my-package:main)
                     :evaluate-form '(progn
                                      (format t "Starting my-package!~%")
                                      (my-package:my-lisp-main-function)
                                      (format t "Exitting my-package!~%"))

                     ;; Default is nil ""
                     :extra-lisp-arguments "--noinform --control-stack-size 4 --merge-core-pages"

                     ;; A list of (container . host) pairs that map the container's ports
                     ;; to host ports.  Default is empty
                     :port-map '((80 . 8080)
                                 (5432 . 5432))

                     ;; Default is "debian"
                     :linux-distro "alpine"

                     ;; These both default to empty lists
                     ;; Ideally these should be detected automatically
                     :os-extra-package-list '("libfoo-dev" "libfoo" "clang-12" "libclang-13-dev")
                     :lisp-extra-package-list '(:cl-opengl :cl-autowrap)
                     )

  ;; Run it in Docker with Swank running on port 4567, and then evaluating the above progn.
  ;; Run (slime-connect "localhost" 4567) on the host to connect to the container's REPL
  (db:start :my-package :swank-port 4567)

  ;; Eval in a Docker container
  ;; What should eval-in-docker return 🤔
  (db:eval-in-docker (:clisp)
    (defun fib-4 (n)
      (loop
        :with a integer = 0
        :with b integer = 1
        :for  i integer :below n
        :do (shiftf a b (+ a b))
        :finally (return b)))
   (time (fib 100000)))

#+end_src

(build-container) should be smart enough to automatically detect Lisp dependencies and any required native packages.

It should be smart enough to detect Lisp packages that require special Docker configuration, and assist with that configuration.
For example, a package using the cl-opengl package should have https://medium.com/@benjamin.botto/opengl-and-cuda-applications-in-docker-af0eece000f1 and other OpenGL libraries configured automatically.
A package including a web server or database package should (probably) have ports opened, so some mechanism should help do that.  Maybe prompt for a port, look at a configuration variable, a restart, etc.


* Open Questions

** Which Common Lisp(s) to support?
SBCL, CCL, ABCL, Clisp, etc.
Maybe use https://github.com/fukamachi/dockerfiles

* Plan
** TODO Everything

A  => t/package.lisp +30 -0
@@ 1,30 @@
;; package.lisp
;;
;; Copyright (c) 2022 Jeremiah LaRocco <jeremiah_larocco@fastmail.com>

;; Permission to use, copy, modify, and/or distribute this software for any
;; purpose with or without fee is hereby granted, provided that the above
;; copyright notice and this permission notice appear in all copies.

;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

(in-package :cl-user)
(defpackage :docker-build.test
  (:use :cl
        :fiveam
        :alexandria
        :docker-build))

(in-package :docker-build.test)

(def-suite :docker-build)
(in-suite :docker-build)

;; (test hello
;;   (is-true (hello)))