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