at 23.11-pre 6.2 kB view raw
1{ config, lib, pkgs, ... }: 2with lib; 3let 4 cfg = config.services.nomad; 5 format = pkgs.formats.json { }; 6in 7{ 8 ##### interface 9 options = { 10 services.nomad = { 11 enable = mkEnableOption (lib.mdDoc "Nomad, a distributed, highly available, datacenter-aware scheduler"); 12 13 package = mkOption { 14 type = types.package; 15 default = pkgs.nomad; 16 defaultText = literalExpression "pkgs.nomad"; 17 description = lib.mdDoc '' 18 The package used for the Nomad agent and CLI. 19 ''; 20 }; 21 22 extraPackages = mkOption { 23 type = types.listOf types.package; 24 default = [ ]; 25 description = lib.mdDoc '' 26 Extra packages to add to {env}`PATH` for the Nomad agent process. 27 ''; 28 example = literalExpression '' 29 with pkgs; [ cni-plugins ] 30 ''; 31 }; 32 33 dropPrivileges = mkOption { 34 type = types.bool; 35 default = true; 36 description = lib.mdDoc '' 37 Whether the nomad agent should be run as a non-root nomad user. 38 ''; 39 }; 40 41 enableDocker = mkOption { 42 type = types.bool; 43 default = true; 44 description = lib.mdDoc '' 45 Enable Docker support. Needed for Nomad's docker driver. 46 47 Note that the docker group membership is effectively equivalent 48 to being root, see https://github.com/moby/moby/issues/9976. 49 ''; 50 }; 51 52 extraSettingsPaths = mkOption { 53 type = types.listOf types.path; 54 default = [ ]; 55 description = lib.mdDoc '' 56 Additional settings paths used to configure nomad. These can be files or directories. 57 ''; 58 example = literalExpression '' 59 [ "/etc/nomad-mutable.json" "/run/keys/nomad-with-secrets.json" "/etc/nomad/config.d" ] 60 ''; 61 }; 62 63 extraSettingsPlugins = mkOption { 64 type = types.listOf (types.either types.package types.path); 65 default = [ ]; 66 description = lib.mdDoc '' 67 Additional plugins dir used to configure nomad. 68 ''; 69 example = literalExpression '' 70 [ "<pluginDir>" pkgs.nomad-driver-nix pkgs.nomad-driver-podman ] 71 ''; 72 }; 73 74 credentials = mkOption { 75 description = lib.mdDoc '' 76 Credentials envs used to configure nomad secrets. 77 ''; 78 type = types.attrsOf types.str; 79 default = { }; 80 81 example = { 82 logs_remote_write_password = "/run/keys/nomad_write_password"; 83 }; 84 }; 85 86 settings = mkOption { 87 type = format.type; 88 default = { }; 89 description = lib.mdDoc '' 90 Configuration for Nomad. See the [documentation](https://www.nomadproject.io/docs/configuration) 91 for supported values. 92 93 Notes about `data_dir`: 94 95 If `data_dir` is set to a value other than the 96 default value of `"/var/lib/nomad"` it is the Nomad 97 cluster manager's responsibility to make sure that this directory 98 exists and has the appropriate permissions. 99 100 Additionally, if `dropPrivileges` is 101 `true` then `data_dir` 102 *cannot* be customized. Setting 103 `dropPrivileges` to `true` enables 104 the `DynamicUser` feature of systemd which directly 105 manages and operates on `StateDirectory`. 106 ''; 107 example = literalExpression '' 108 { 109 # A minimal config example: 110 server = { 111 enabled = true; 112 bootstrap_expect = 1; # for demo; no fault tolerance 113 }; 114 client = { 115 enabled = true; 116 }; 117 } 118 ''; 119 }; 120 }; 121 }; 122 123 ##### implementation 124 config = mkIf cfg.enable { 125 services.nomad.settings = { 126 # Agrees with `StateDirectory = "nomad"` set below. 127 data_dir = mkDefault "/var/lib/nomad"; 128 }; 129 130 environment = { 131 etc."nomad.json".source = format.generate "nomad.json" cfg.settings; 132 systemPackages = [ cfg.package ]; 133 }; 134 135 systemd.services.nomad = { 136 description = "Nomad"; 137 wantedBy = [ "multi-user.target" ]; 138 wants = [ "network-online.target" ]; 139 after = [ "network-online.target" ]; 140 restartTriggers = [ config.environment.etc."nomad.json".source ]; 141 142 path = cfg.extraPackages ++ (with pkgs; [ 143 # Client mode requires at least the following: 144 coreutils 145 iproute2 146 iptables 147 ]); 148 149 serviceConfig = mkMerge [ 150 { 151 DynamicUser = cfg.dropPrivileges; 152 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 153 ExecStart = 154 let 155 pluginsDir = pkgs.symlinkJoin 156 { 157 name = "nomad-plugins"; 158 paths = cfg.extraSettingsPlugins; 159 }; 160 in 161 "${cfg.package}/bin/nomad agent -config=/etc/nomad.json -plugin-dir=${pluginsDir}/bin" + 162 concatMapStrings (path: " -config=${path}") cfg.extraSettingsPaths + 163 concatMapStrings (key: " -config=\${CREDENTIALS_DIRECTORY}/${key}") (lib.attrNames cfg.credentials); 164 KillMode = "process"; 165 KillSignal = "SIGINT"; 166 LimitNOFILE = 65536; 167 LimitNPROC = "infinity"; 168 OOMScoreAdjust = -1000; 169 Restart = "on-failure"; 170 RestartSec = 2; 171 TasksMax = "infinity"; 172 LoadCredential = lib.mapAttrsToList (key: value: "${key}:${value}") cfg.credentials; 173 } 174 (mkIf cfg.enableDocker { 175 SupplementaryGroups = "docker"; # space-separated string 176 }) 177 (mkIf (cfg.settings.data_dir == "/var/lib/nomad") { 178 StateDirectory = "nomad"; 179 }) 180 ]; 181 182 unitConfig = { 183 StartLimitIntervalSec = 10; 184 StartLimitBurst = 3; 185 }; 186 }; 187 188 assertions = [ 189 { 190 assertion = cfg.dropPrivileges -> cfg.settings.data_dir == "/var/lib/nomad"; 191 message = "settings.data_dir must be equal to \"/var/lib/nomad\" if dropPrivileges is true"; 192 } 193 ]; 194 195 # Docker support requires the Docker daemon to be running. 196 virtualisation.docker.enable = mkIf cfg.enableDocker true; 197 }; 198}