at master 7.5 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7with lib; 8let 9 cfg = config.services.victoriametrics; 10 settingsFormat = pkgs.formats.yaml { }; 11 12 startCLIList = [ 13 "${cfg.package}/bin/victoria-metrics" 14 "-storageDataPath=/var/lib/${cfg.stateDir}" 15 "-httpListenAddr=${cfg.listenAddress}" 16 17 ] 18 ++ lib.optionals (cfg.retentionPeriod != null) [ "-retentionPeriod=${cfg.retentionPeriod}" ] 19 ++ cfg.extraOptions; 20 prometheusConfigYml = checkedConfig ( 21 settingsFormat.generate "prometheusConfig.yaml" cfg.prometheusConfig 22 ); 23 24 checkedConfig = 25 file: 26 if cfg.checkConfig then 27 pkgs.runCommand "checked-config" { nativeBuildInputs = [ cfg.package ]; } '' 28 ln -s ${file} $out 29 ${lib.escapeShellArgs startCLIList} -promscrape.config=${file} -dryRun 30 '' 31 else 32 file; 33in 34{ 35 options.services.victoriametrics = { 36 enable = lib.mkOption { 37 type = lib.types.bool; 38 default = false; 39 description = '' 40 Whether to enable VictoriaMetrics in single-node mode. 41 42 VictoriaMetrics is a fast, cost-effective and scalable monitoring solution and time series database. 43 ''; 44 }; 45 package = mkPackageOption pkgs "victoriametrics" { }; 46 47 listenAddress = mkOption { 48 default = ":8428"; 49 type = types.str; 50 description = '' 51 TCP address to listen for incoming http requests. 52 ''; 53 }; 54 55 stateDir = mkOption { 56 type = types.str; 57 default = "victoriametrics"; 58 description = '' 59 Directory below `/var/lib` to store VictoriaMetrics metrics data. 60 This directory will be created automatically using systemd's StateDirectory mechanism. 61 ''; 62 }; 63 64 retentionPeriod = mkOption { 65 type = types.nullOr types.str; 66 default = null; 67 example = "15d"; 68 description = '' 69 How long to retain samples in storage. 70 The minimum retentionPeriod is 24h or 1d. See also -retentionFilter 71 The following optional suffixes are supported: s (second), h (hour), d (day), w (week), y (year). 72 If suffix isn't set, then the duration is counted in months (default 1) 73 ''; 74 }; 75 76 basicAuthUsername = lib.mkOption { 77 default = null; 78 type = lib.types.nullOr lib.types.str; 79 description = '' 80 Basic Auth username used to protect VictoriaMetrics instance by authorization 81 ''; 82 }; 83 84 basicAuthPasswordFile = lib.mkOption { 85 default = null; 86 type = lib.types.nullOr lib.types.path; 87 description = '' 88 File that contains the Basic Auth password used to protect VictoriaMetrics instance by authorization 89 ''; 90 }; 91 92 prometheusConfig = lib.mkOption { 93 type = lib.types.submodule { freeformType = settingsFormat.type; }; 94 default = { }; 95 example = literalExpression '' 96 { 97 scrape_configs = [ 98 { 99 job_name = "postgres-exporter"; 100 metrics_path = "/metrics"; 101 static_configs = [ 102 { 103 targets = ["1.2.3.4:9187"]; 104 labels.type = "database"; 105 } 106 ]; 107 } 108 { 109 job_name = "node-exporter"; 110 metrics_path = "/metrics"; 111 static_configs = [ 112 { 113 targets = ["1.2.3.4:9100"]; 114 labels.type = "node"; 115 } 116 { 117 targets = ["5.6.7.8:9100"]; 118 labels.type = "node"; 119 } 120 ]; 121 } 122 ]; 123 } 124 ''; 125 description = '' 126 Config for prometheus style metrics. 127 See the docs: <https://docs.victoriametrics.com/vmagent/#how-to-collect-metrics-in-prometheus-format> 128 for more information. 129 ''; 130 }; 131 132 extraOptions = mkOption { 133 type = types.listOf types.str; 134 default = [ ]; 135 example = literalExpression '' 136 [ 137 "-loggerLevel=WARN" 138 ] 139 ''; 140 description = '' 141 Extra options to pass to VictoriaMetrics. See the docs: 142 <https://docs.victoriametrics.com/single-server-victoriametrics/#list-of-command-line-flags> 143 or {command}`victoriametrics -help` for more information. 144 ''; 145 }; 146 147 checkConfig = lib.mkOption { 148 type = lib.types.bool; 149 default = true; 150 description = '' 151 Check configuration. 152 153 If you use credentials stored in external files (`environmentFile`, etc), 154 they will not be visible and it will report errors, despite a correct configuration. 155 ''; 156 }; 157 }; 158 159 config = lib.mkIf cfg.enable { 160 161 assertions = [ 162 { 163 assertion = 164 (cfg.basicAuthUsername == null && cfg.basicAuthPasswordFile == null) 165 || (cfg.basicAuthUsername != null && cfg.basicAuthPasswordFile != null); 166 message = "Both basicAuthUsername and basicAuthPasswordFile must be set together to enable basicAuth functionality, or neither should be set."; 167 } 168 ]; 169 170 systemd.services.victoriametrics = { 171 description = "VictoriaMetrics time series database"; 172 wantedBy = [ "multi-user.target" ]; 173 after = [ "network.target" ]; 174 startLimitBurst = 5; 175 176 serviceConfig = { 177 ExecStart = lib.escapeShellArgs ( 178 startCLIList 179 ++ lib.optionals (cfg.prometheusConfig != { }) [ "-promscrape.config=${prometheusConfigYml}" ] 180 ++ lib.optional (cfg.basicAuthUsername != null) "-httpAuth.username=${cfg.basicAuthUsername}" 181 ++ lib.optional ( 182 cfg.basicAuthPasswordFile != null 183 ) "-httpAuth.password=file://%d/basic_auth_password" 184 ); 185 186 DynamicUser = true; 187 LoadCredential = lib.optionals (cfg.basicAuthPasswordFile != null) [ 188 "basic_auth_password:${cfg.basicAuthPasswordFile}" 189 ]; 190 191 RestartSec = 1; 192 Restart = "on-failure"; 193 RuntimeDirectory = "victoriametrics"; 194 RuntimeDirectoryMode = "0700"; 195 StateDirectory = cfg.stateDir; 196 StateDirectoryMode = "0700"; 197 198 # Increase the limit to avoid errors like 'too many open files' when merging small parts 199 LimitNOFILE = 1048576; 200 201 # Hardening 202 DeviceAllow = [ "/dev/null rw" ]; 203 DevicePolicy = "strict"; 204 LockPersonality = true; 205 MemoryDenyWriteExecute = true; 206 NoNewPrivileges = true; 207 PrivateDevices = true; 208 PrivateTmp = true; 209 PrivateUsers = true; 210 ProtectClock = true; 211 ProtectControlGroups = true; 212 ProtectHome = true; 213 ProtectHostname = true; 214 ProtectKernelLogs = true; 215 ProtectKernelModules = true; 216 ProtectKernelTunables = true; 217 ProtectProc = "invisible"; 218 ProtectSystem = "full"; 219 RemoveIPC = true; 220 RestrictAddressFamilies = [ 221 "AF_INET" 222 "AF_INET6" 223 "AF_UNIX" 224 ]; 225 RestrictNamespaces = true; 226 RestrictRealtime = true; 227 RestrictSUIDSGID = true; 228 SystemCallArchitectures = "native"; 229 SystemCallFilter = [ 230 "@system-service" 231 "~@privileged" 232 ]; 233 }; 234 235 postStart = 236 let 237 bindAddr = 238 (lib.optionalString (lib.hasPrefix ":" cfg.listenAddress) "127.0.0.1") + cfg.listenAddress; 239 in 240 lib.mkBefore '' 241 until ${lib.getBin pkgs.curl}/bin/curl -s -o /dev/null http://${bindAddr}/ping; do 242 sleep 1; 243 done 244 ''; 245 }; 246 }; 247}