diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 5f900e5..37eb06f 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -244,13 +244,12 @@ Nope, it’s just Nix and Docker Compose under the hood. === What about garbage collection? Arion removes the need for garbage collecting docker images, delegating -this task to Nix. +this task to Nix when using `service.useHostStore`. -Arion creates a garbage collection root and cleans it up after -completing the command. This means that `arion up` without `-d` is safe -with respect to garbage collection. A deployment that is more serious -than local development must leave a GC root on the deployment host. This -use case is not supported as of now. +Arion creates a garbage collection root that it cleans up after completing +the command. This means that `arion up -d` should not be used with `useHostStore` +in production. Instead, disable `useHostStore`, which will use `dockerTools` to +generate images that can be used in production. === Why is my container not running latest code? diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..4e92b89 --- /dev/null +++ b/flake.lock @@ -0,0 +1,25 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1601906239, + "narHash": "sha256-P1jBYbYeFswig/0FKbgh+BpVhh9iurD3m0T2ae4gdx8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c2bb4af48d26ed091e5674394bacbf8d488c7939", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d711a13 --- /dev/null +++ b/flake.nix @@ -0,0 +1,42 @@ +{ + description = "Arion - use Docker Compose via Nix"; + + outputs = { self, nixpkgs }: + let + lib = import (nixpkgs + "/lib"); + systems = [ + "aarch64-linux" + "x86_64-darwin" + "x86_64-linux" + ]; + arionFromPkgs = pkgs: import ./nix/arion.nix { inherit pkgs; }; + in { + + # The overlay is currently the recommended way to integrate arion, + # because its arion attribute behaves just like Nixpkgs. + overlay = final: prev: { + arion = arionFromPkgs final; + }; + + packages = lib.genAttrs systems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + arion = arionFromPkgs pkgs; + }); + + # Does not include the eval and build functions like you may expect from Nixpkgs. + defaultPackage = lib.genAttrs systems (system: + self.packages.${system}.arion + ); + + lib = { + eval = import ./src/nix/eval-composition.nix; + build = args@{...}: + let composition = self.lib.eval args; + in composition.config.out.dockerComposeYaml; + }; + + }; +} diff --git a/nix/arion.nix b/nix/arion.nix index b53b1f4..e43fd9e 100644 --- a/nix/arion.nix +++ b/nix/arion.nix @@ -1,42 +1,13 @@ +# Like the upstreamable expression but wired up for the local arion. { pkgs ? import ./. {} , lib ? pkgs.lib +, haskell ? pkgs.haskell , haskellPackages ? pkgs.haskellPackages , arion-compose ? import ./haskell-arion-compose.nix { inherit pkgs haskellPackages; } +, runCommand ? pkgs.runCommand }: - -let - inherit (pkgs.haskell.lib) justStaticExecutables overrideCabal; - - srcDir = ../src; - eval = import (srcDir + "/nix/eval-composition.nix"); - build = args@{...}: - let composition = eval args; - in composition.config.out.dockerComposeYaml; - -in - justStaticExecutables (overrideCabal arion-compose (o: { - buildTools = o.buildTools ++ [pkgs.makeWrapper]; - passthru = o.passthru // { - inherit eval build; - }; - pname = "arion"; # Cover up the needlessly long Haskell package name - - # PYTHONPATH - # - # We close off the python module search path! - # - # Accepting directories from the environment into the search path - # tends to break things. Docker Compose does not have a plugin - # system as far as I can tell, so I don't expect this to break a - # feature, but rather to make the program more robustly self- - # contained. - - postInstall = ''${o.postInstall or ""} - mkdir -p $out/libexec - mv $out/bin/arion $out/libexec - makeWrapper $out/libexec/arion $out/bin/arion \ - --unset PYTHONPATH \ - --prefix PATH : ${lib.makeBinPath [ pkgs.docker-compose ]} \ - ; - ''; - })) +import ./upstreamable/default.nix { + inherit pkgs lib haskell runCommand; + haskellPackages = haskellPackages // { inherit arion-compose; }; + evalSrc = ./..; +} diff --git a/nix/upstreamable/default.nix b/nix/upstreamable/default.nix new file mode 100644 index 0000000..a06b42d --- /dev/null +++ b/nix/upstreamable/default.nix @@ -0,0 +1,90 @@ +args@ +{ pkgs +, lib +, haskellPackages +, haskell +, runCommand + + # Allow this expression file to be used more efficiently in situations where + # the sources are more readily available. Unpacking haskellPackages.arion-compose.src + # is not always the best choice for arion.eval. +, evalSrc ? null +}: + +let + + /* This derivation builds the arion tool. + + It is based on the arion-compose Haskell package, but adapted and extended to + - have the correct name + - have a smaller closure size + - have functions to use Arion from inside Nix: arion.eval and arion.build + - make it self-contained by including docker-compose + */ + arion = + justStaticExecutables ( + overrideCabal + arion-compose + cabalOverrides + ); + + inherit (haskell.lib) justStaticExecutables overrideCabal; + + inherit (haskellPackages) arion-compose; + + cabalOverrides = o: { + buildTools = (o.buildTools or []) ++ [pkgs.makeWrapper]; + passthru = (o.passthru or {}) // { + inherit eval build; + }; + # Patch away the arion-compose name. Unlike the Haskell library, the program + # is called arion (arion was already taken on hackage). + pname = "arion"; + src = arion-compose.src; + + # PYTHONPATH + # + # We close off the python module search path! + # + # Accepting directories from the environment into the search path + # tends to break things. Docker Compose does not have a plugin + # system as far as I can tell, so I don't expect this to break a + # feature, but rather to make the program more robustly self- + # contained. + + postInstall = ''${o.postInstall or ""} + mkdir -p $out/libexec + mv $out/bin/arion $out/libexec + makeWrapper $out/libexec/arion $out/bin/arion \ + --unset PYTHONPATH \ + --prefix PATH : ${lib.makeBinPath [ pkgs.docker-compose ]} \ + ; + ''; + }; + + # Unpacked sources for evaluation by `eval` + evalSrc' = args.evalSrc or (runCommand "arion-src" {} + "mkdir $out; tar -C $out --strip-components=1 -xf ${arion-compose.src}"); + + /* Function for evaluating a composition + + Re-uses this Nixpkgs evaluation instead of `arion-pkgs.nix`. + + Returns the module system's `config` and `options` variables. + */ + eval = args@{...}: + import (evalSrc' + "/src/nix/eval-composition.nix") + ({ inherit pkgs; } // args); + + /* Function to derivation of the docker compose yaml file + NOTE: The output will change: https://github.com/hercules-ci/arion/issues/82 + + This function is particularly useful on CI. On Nixpkgs >= 20.09 this will + not store the image tarballs but executables to produce them reliably via + streamLayeredImage. + */ + build = args@{...}: + let composition = eval args; + in composition.config.out.dockerComposeYaml; + +in arion