1 { config, lib, pkgs, ... }:
4 cfg = config.services.nomad;
5 format = pkgs.formats.json { };
11 enable = mkEnableOption (lib.mdDoc "Nomad, a distributed, highly available, datacenter-aware scheduler");
16 defaultText = literalExpression "pkgs.nomad";
17 description = lib.mdDoc ''
18 The package used for the Nomad agent and CLI.
22 extraPackages = mkOption {
23 type = types.listOf types.package;
25 description = lib.mdDoc ''
26 Extra packages to add to {env}`PATH` for the Nomad agent process.
28 example = literalExpression ''
29 with pkgs; [ cni-plugins ]
33 dropPrivileges = mkOption {
36 description = lib.mdDoc ''
37 Whether the nomad agent should be run as a non-root nomad user.
41 enableDocker = mkOption {
44 description = lib.mdDoc ''
45 Enable Docker support. Needed for Nomad's docker driver.
47 Note that the docker group membership is effectively equivalent
48 to being root, see https://github.com/moby/moby/issues/9976.
52 extraSettingsPaths = mkOption {
53 type = types.listOf types.path;
55 description = lib.mdDoc ''
56 Additional settings paths used to configure nomad. These can be files or directories.
58 example = literalExpression ''
59 [ "/etc/nomad-mutable.json" "/run/keys/nomad-with-secrets.json" "/etc/nomad/config.d" ]
63 extraSettingsPlugins = mkOption {
64 type = types.listOf (types.either types.package types.path);
66 description = lib.mdDoc ''
67 Additional plugins dir used to configure nomad.
69 example = literalExpression ''
70 [ "<pluginDir>" "pkgs.<plugins-name>"]
78 description = lib.mdDoc ''
79 Configuration for Nomad. See the [documentation](https://www.nomadproject.io/docs/configuration)
82 Notes about `data_dir`:
84 If `data_dir` is set to a value other than the
85 default value of `"/var/lib/nomad"` it is the Nomad
86 cluster manager's responsibility to make sure that this directory
87 exists and has the appropriate permissions.
89 Additionally, if `dropPrivileges` is
90 `true` then `data_dir`
91 *cannot* be customized. Setting
92 `dropPrivileges` to `true` enables
93 the `DynamicUser` feature of systemd which directly
94 manages and operates on `StateDirectory`.
96 example = literalExpression ''
98 # A minimal config example:
101 bootstrap_expect = 1; # for demo; no fault tolerance
113 config = mkIf cfg.enable {
114 services.nomad.settings = {
115 # Agrees with `StateDirectory = "nomad"` set below.
116 data_dir = mkDefault "/var/lib/nomad";
120 etc."nomad.json".source = format.generate "nomad.json" cfg.settings;
121 systemPackages = [ cfg.package ];
124 systemd.services.nomad = {
125 description = "Nomad";
126 wantedBy = [ "multi-user.target" ];
127 wants = [ "network-online.target" ];
128 after = [ "network-online.target" ];
129 restartTriggers = [ config.environment.etc."nomad.json".source ];
131 path = cfg.extraPackages ++ (with pkgs; [
132 # Client mode requires at least the following:
138 serviceConfig = mkMerge [
140 DynamicUser = cfg.dropPrivileges;
141 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
142 ExecStart = "${cfg.package}/bin/nomad agent -config=/etc/nomad.json" +
143 concatMapStrings (path: " -config=${path}") cfg.extraSettingsPaths +
144 concatMapStrings (path: " -plugin-dir=${path}/bin") cfg.extraSettingsPlugins;
145 KillMode = "process";
146 KillSignal = "SIGINT";
148 LimitNPROC = "infinity";
149 OOMScoreAdjust = -1000;
150 Restart = "on-failure";
152 TasksMax = "infinity";
154 (mkIf cfg.enableDocker {
155 SupplementaryGroups = "docker"; # space-separated string
157 (mkIf (cfg.settings.data_dir == "/var/lib/nomad") {
158 StateDirectory = "nomad";
163 StartLimitIntervalSec = 10;
170 assertion = cfg.dropPrivileges -> cfg.settings.data_dir == "/var/lib/nomad";
171 message = "settings.data_dir must be equal to \"/var/lib/nomad\" if dropPrivileges is true";
175 # Docker support requires the Docker daemon to be running.
176 virtualisation.docker.enable = mkIf cfg.enableDocker true;