Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
* xref:index.adoc[Getting Started]
* xref:options.adoc[Arion Options]
* xref:deployment.adoc[Deployment]
68 changes: 68 additions & 0 deletions docs/modules/ROOT/pages/deployment.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
= Deployment with Arion

Arion projects can be deployed in Nix-like or Docker-like ways.

== Docker images

When you disable `useHostStore`, arion will build images, which can be deployed
to any Docker host, including non-NixOS hosts.

=== Remote Docker socket

NOTE: Access to a Docker socket is equivalent to root access on the host.

Docker supports authentication via TLS client certificates.

The xref:hercules-ci-effects:ROOT:reference/nix-functions/runArion.adoc[runArion Effect] uses this technique.

Because this technique works with a single Docker host, it does not need a registry.

=== Upload to registry

You can either use `arion push` or write custom push logic using the `arion cat`
command, the `eval` function on the `arion` package, or the `lib.eval` function
on the flake to retrieve the images defined in a project.

== NixOS module

Arion projects can be deployed as part of a NixOS configuration. This ties the
project revision to the system configuration revision, which can be good or bad
thing, depending on your deployment strategy. At a low level, a benefit is that
no store paths need to be copied locally and remote NixOS deployments can use
Nix's copy-closure algorithm for efficient transfers, and transparent binary
caches rather than an inherently stateful Docker registry solution.

Extend your NixOS configuration by adding the configuration elements to an
existing configuration. You could create a new module file for it, if your
choice of `imports` allows it.

NOTE: This deployment method does NOT use an `arion-pkgs.nix` file, but reuses
the host `pkgs`.

```nix
{
imports = [
# Pick one of:
# - niv
((import ./nix/sources.nix).arion + "/nixos-module.nix")
# - flakes (where arion is a flake input)
arion.nixosModules.arion
# - other
arionPath + "/nixos-module.nix")
];

virtualisation.arion = {
backend = "podman-socket"; # or "docker"
projects.example.settings = {
# Specify you project here, or import it from a file.
# NOTE: This does NOT use ./arion-pkgs.nix, but defaults to NixOS' pkgs.
imports = [ ./arion-compose.nix ];
};
};
}
```

See also:

- xref:hercules-ci-effects:ROOT:reference/nix-functions/runNixOS.adoc[runNixOS Effect]
- xref:hercules-ci-effects:ROOT:reference/nix-functions/runNixOps2.adoc[runNixOps2 Effect]
2 changes: 1 addition & 1 deletion docs/modules/ROOT/partials/NixOSOptions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ Type:: string
Default::
+
----
{"_type":"literalExample","text":"config.service.name"}
{"_type":"literalExpression","text":"config.service.name"}
----


Expand Down
2 changes: 2 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,7 @@
in composition.config.out.dockerComposeYaml;
};

nixosModules.arion = ./nixos-module.nix;

};
}
8 changes: 4 additions & 4 deletions nix/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixos-unstable": {
"branch": "nixos-unstable",
"branch": "master",
"description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to",
"homepage": "https://github.com/NixOS/nixpkgs",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c6c4a3d45ab200f17805d2d86a1ff1cc7ca2b186",
"sha256": "1f6q98vx3sqxcn6qp5vpy00223r9hy93w9pxq65h9gdwzy3w4qxv",
"rev": "f8232491252438cd70b93554e31fe8238a573636",
"sha256": "019bz8dxp9d30ghmi9v0inn0p7mj3mia69lkh5cyivhhp1i0cs5i",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/c6c4a3d45ab200f17805d2d86a1ff1cc7ca2b186.tar.gz",
"url": "https://github.com/NixOS/nixpkgs/archive/f8232491252438cd70b93554e31fe8238a573636.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz",
"version": ""
},
Expand Down
110 changes: 110 additions & 0 deletions nixos-module.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
{ config, lib, pkgs, ... }:
let
inherit (lib)
attrValues
mkIf
mkOption
mkMerge
types
;

cfg = config.virtualisation.arion;

projectType = types.submoduleWith {
modules = [ projectModule ];
};

projectModule = { config, name, ... }: {
options = {
settings = mkOption {
description = ''
Arion project definition, otherwise known as arion-compose.nix contents.

See <link xlink:href="https://docs.hercules-ci.com/arion/options/">https://docs.hercules-ci.com/arion/options/</link>.
'';
type = arionSettingsType;
visible = "shallow";
};
_systemd = mkOption { internal = true; };
};
config = {
_systemd.services."arion-${name}" = {
wantedBy = [ "multi-user.target" ];
after = [ "sockets.target" ];

path = [
cfg.package
cfg.docker.client.package
];
environment.ARION_PREBUILT = config.settings.out.dockerComposeYaml;
script = ''
echo 1>&2 "docker compose file: $ARION_PREBUILT"
arion --prebuilt-file "$ARION_PREBUILT" up
'';
};
};
};

arionSettingsType =
(cfg.package.eval { modules = [ ]; }).type or (
throw "lib.evalModules did not produce a type. Please upgrade Nixpkgs to nixos-unstable or >=nixos-21.11"
);

in
{
disabledModules = [ "virtualisation/arion.nix" ];

options = {
virtualisation.arion = {
backend = mkOption {
type = types.enum [ "podman-socket" "docker" ];
description = ''
Which container implementation to use.
'';
};
package = mkOption {
type = types.package;

default = (import ./. { inherit pkgs; }).arion;
description = ''
Arion package to use. This will provide <literal>arion</literal>
executable that starts the project.

It also must provide the arion <literal>eval</literal> function as
an attribute.
'';
};
docker.client.package = mkOption {
type = types.package;
internal = true;
};
projects = mkOption {
type = types.attrsOf projectType;
default = { };
description = ''
Arion projects to be run as a service.
'';
};
};
};

config = mkIf (cfg.projects != { }) (
mkMerge [
{
systemd = mkMerge (map (p: p._systemd) (attrValues cfg.projects));
}
(mkIf (cfg.backend == "podman-socket") {
virtualisation.docker.enable = false;
virtualisation.podman.enable = true;
virtualisation.podman.dockerSocket.enable = true;
virtualisation.podman.defaultNetwork.dnsname.enable = true;

virtualisation.arion.docker.client.package = pkgs.docker-client;
})
(mkIf (cfg.backend == "docker") {
virtualisation.docker.enable = true;
virtualisation.arion.docker.client.package = pkgs.docker;
})
]
);
}
2 changes: 1 addition & 1 deletion src/nix/modules/service/image.nix
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ in
image.name = mkOption {
type = str;
default = config.service.name;
defaultText = lib.literalExample "config.service.name";
defaultText = lib.literalExpression or lib.literalExample "config.service.name";
description = ''
A human readable name for the docker image.

Expand Down
6 changes: 5 additions & 1 deletion tests/arion-test/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ let
};

inherit (lib)
concatMapStringsSep
optionalAttrs
optionalString
;

haveSystemd = usePodman || pkgs.arionTestingFlags.dockerSupportsSystemd;

concatPathLines = paths: concatMapStringsSep "\n" (x: "${x}") paths;

in
{
name = "arion-test";
Expand All @@ -39,7 +42,8 @@ in
nix.useSandbox = false;

virtualisation.writableStore = true;
virtualisation.pathsInNixDB = [
# Switch to virtualisation.additionalPaths when dropping all NixOS <= 21.05.
environment.etc."extra-paths-for-test".text = concatPathLines [
# Pre-build the image because we don't want to build the world
# in the vm.
(preEval [ ../../examples/minimal/arion-compose.nix ]).config.out.dockerComposeYaml
Expand Down
23 changes: 22 additions & 1 deletion tests/default.nix
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
{ pkgs ? import ../pkgs.nix, arionTestingFlags ? {} }:
let
inherit (pkgs) nixosTest recurseIntoAttrs arion;
inherit (pkgs) nixosTest recurseIntoAttrs arion lib;

hasEvalModulesType = (lib.evalModules { modules = [ {} ]; })?type;

in

recurseIntoAttrs {

test = nixosTest ./arion-test;

nixosModuleWithDocker =
lib.optionalAttrs
hasEvalModulesType
(
import ./nixos-virtualization-arion-test/test.nix pkgs {
virtualisation.arion.backend = "docker";
}
);

nixosModuleWithPodman =
lib.optionalAttrs
(hasEvalModulesType && arionTestingFlags.nixosHasPodmanDockerSocket)
(
import ./nixos-virtualization-arion-test/test.nix pkgs {
virtualisation.arion.backend = "podman-socket";
}
);

testWithPodman =
if arionTestingFlags.nixosHasPodmanDockerSocket
then nixosTest (pkgs.callPackage ./arion-test { usePodman = true; })
Expand Down
6 changes: 6 additions & 0 deletions tests/nixos-virtualization-arion-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

# NixOS module test

This tests the NixOS module.

The images used here are experimental and not meant for production.
60 changes: 60 additions & 0 deletions tests/nixos-virtualization-arion-test/arion-compose.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{ pkgs, ... }: {
project.name = "whale";

docker-compose.raw = {
volumes.zookeeper = { };
volumes.kafka = { };
};

services.kafka = {
service.useHostStore = true;
# service.volumes = [
# {
# type = "volume";
# source = "kafka";
# target = "/data";
# # volume.nocopy = true;
# }
# ];
service.ports = [ "9092:9092" ];
service.depends_on = [ "zookeeper" ];
image.contents = [
(pkgs.runCommand "root" { } ''
mkdir -p $out/bin
ln -s ${pkgs.runtimeShell} $out/bin/sh
'')
];
image.command = [
"${pkgs.apacheKafka}/bin/kafka-server-start.sh"
"${./kafka/server.properties}"
];
};

services.zookeeper = {
service.useHostStore = true;
service.ports = [ "2181:2181" ];
# service.volumes = [
# {
# type = "volume";
# source = "zookeeper";
# target = "/data";
# # volume.nocopy = true;
# }
# ];
image.contents = [
(pkgs.buildEnv {
name = "root";
paths = [
# pkgs.sed
pkgs.busybox
];
})
];
image.command = [
"${pkgs.zookeeper.override { jre = pkgs.jdk8_headless; }}/bin/zkServer.sh"
"--config"
"${./zookeeper}"
"start-foreground"
];
};
}
6 changes: 6 additions & 0 deletions tests/nixos-virtualization-arion-test/arion-pkgs.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# NOTE: This isn't used in the module!
import <nixpkgs> {
# We specify the architecture explicitly. Use a Linux remote builder when
# calling arion from other platforms.
system = "x86_64-linux";
}
Loading