feat(monitoring): cloudflared metrics

This commit is contained in:
arcnmx 2024-06-24 12:11:07 -07:00
parent 1d19f0821d
commit ec7e322e2d
10 changed files with 124 additions and 29 deletions

View file

@ -1,38 +1,67 @@
{ let
tunnelModule = {pkgs, config, lib, ...}: let
inherit (lib.options) mkOption mkEnableOption;
settingsFormat = pkgs.formats.json {};
in {
options = with lib.types; {
extraArgs = mkOption {
type = listOf str;
default = [];
};
extraTunnel = {
enable =
mkEnableOption "extra tunnels"
// {
default = config.extraTunnel.ingress != {};
};
ingress = mkOption {
inherit (settingsFormat) type;
default = {};
};
};
};
};
in {
pkgs, pkgs,
config, config,
utils, utils,
gensokyo-zone,
lib, lib,
... ...
}: let }: let
inherit (lib.attrsets) mapAttrsToList mapAttrs' nameValuePair filterAttrsRecursive; inherit (lib.attrsets) mapAttrsToList mapAttrs' nameValuePair filterAttrsRecursive;
inherit (lib.lists) singleton; inherit (lib.lists) singleton;
inherit (lib.modules) mkIf mkMerge mkForce; inherit (lib.modules) mkIf mkMerge mkForce;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption;
cfg = config.services.cloudflared; cfg = config.services.cloudflared;
settingsFormat = pkgs.formats.json {};
in { in {
options.services.cloudflared = with lib.types; { options.services.cloudflared = with lib.types; {
tunnels = let metricsPort = mkOption {
tunnelModule = {config, ...}: { type = nullOr port;
options = { default = null;
extraTunnel = { };
enable = metricsBind = mkOption {
mkEnableOption "extra tunnels" type = str;
// { default = "127.0.0.1";
default = config.extraTunnel.ingress != {}; };
}; extraArgs = mkOption {
ingress = mkOption { type = listOf str;
inherit (settingsFormat) type; default = [];
default = {}; };
}; tunnels = mkOption {
}; type = attrsOf (submoduleWith {
modules = [tunnelModule];
shorthandOnlyDefinesConfig = true;
specialArgs = {
inherit pkgs utils gensokyo-zone;
}; };
}; });
in };
mkOption { };
type = attrsOf (submodule tunnelModule); config.services.cloudflared = {
}; extraArgs = mkIf (cfg.metricsPort != null) [
"--metrics" "${cfg.metricsBind}:${toString cfg.metricsPort}"
];
}; };
config.systemd.services = let config.systemd.services = let
filterConfig = filterAttrsRecursive (_: v: ! builtins.elem v [null [] {}]); filterConfig = filterAttrsRecursive (_: v: ! builtins.elem v [null [] {}]);
@ -44,29 +73,38 @@ in {
in in
mkIf cfg.enable (mapAttrs' (uuid: tunnel: let mkIf cfg.enable (mapAttrs' (uuid: tunnel: let
RuntimeDirectory = "cloudflared-tunnel-${uuid}"; RuntimeDirectory = "cloudflared-tunnel-${uuid}";
configPath = "/run/${RuntimeDirectory}/config.yml";
settings = { settings = {
tunnel = uuid; tunnel = uuid;
credentials-file = tunnel.credentialsFile; credentials-file = tunnel.credentialsFile;
warp-routing = filterConfig tunnel.warp-routing;
originRequest = filterConfig tunnel.originRequest;
ingress = ingress =
mapAttrsToList mapIngress tunnel.ingress mapAttrsToList mapIngress tunnel.ingress
++ mapAttrsToList mapIngress tunnel.extraTunnel.ingress ++ mapAttrsToList mapIngress tunnel.extraTunnel.ingress
++ singleton {service = tunnel.default;}; ++ singleton {service = tunnel.default;};
}; };
configPath =
if tunnel.extraTunnel.enable
then "/run/${RuntimeDirectory}/config.yml"
else pkgs.writeText "cloudflared.yml" (builtins.toJSON settings);
args = [
"--config=${configPath}"
"--no-autoupdate"
] ++ cfg.extraArgs ++ tunnel.extraArgs;
in in
nameValuePair "cloudflared-tunnel-${uuid}" (mkMerge [ nameValuePair "cloudflared-tunnel-${uuid}" (mkMerge [
{ {
after = mkIf config.services.tailscale.enable ["tailscale-autoconnect.service"]; after = mkIf config.services.tailscale.enable ["tailscale-autoconnect.service"];
serviceConfig = { serviceConfig = {
RestartSec = 10; RestartSec = 10;
ExecStart = mkForce [
"${cfg.package}/bin/cloudflared tunnel ${utils.escapeSystemdExecArgs args} run"
];
}; };
} }
(mkIf tunnel.extraTunnel.enable { (mkIf tunnel.extraTunnel.enable {
serviceConfig = { serviceConfig = {
inherit RuntimeDirectory; inherit RuntimeDirectory;
ExecStart = mkForce [
"${cfg.package}/bin/cloudflared tunnel --config=${configPath} --no-autoupdate run"
];
ExecStartPre = [ ExecStartPre = [
(pkgs.writeShellScript "cloudflared-tunnel-${uuid}-prepare" '' (pkgs.writeShellScript "cloudflared-tunnel-${uuid}-prepare" ''
${utils.genJqSecretsReplacementSnippet settings configPath} ${utils.genJqSecretsReplacementSnippet settings configPath}

View file

@ -0,0 +1,43 @@
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
in {
config.exports.services.cloudflared = {config, systemConfig, ...}: let
assertMetrics = nixosConfig: let
cfg = nixosConfig.services.cloudflared;
metricsPort =
if config.ports.metrics.enable
then config.ports.metrics.port
else null;
in {
assertion = metricsPort == cfg.metricsPort;
message = "metricsPort mismatch";
};
in {
displayName = mkAlmostOptionDefault "Cloudflare Tunnel/${systemConfig.name}";
nixos = {
serviceAttr = "cloudflared";
assertions = mkIf config.enable [
assertMetrics
];
};
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = {
metrics = {
port = mkAlmostOptionDefault 3011;
protocol = "http";
status = {
enable = true;
gatus.http = {
statusCondition = mkAlmostOptionDefault "[STATUS] == 404";
};
};
prometheus.exporter.enable = mkAlmostOptionDefault true;
};
};
};
}

View file

@ -3,9 +3,8 @@
gensokyo-zone, gensokyo-zone,
... ...
}: let }: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
inherit (lib.lists) all imap0; inherit (lib.lists) all imap0;
inherit (lib.trivial) id; inherit (lib.trivial) id;
in { in {

View file

@ -7,7 +7,16 @@
cfg = config.services.cloudflared; cfg = config.services.cloudflared;
in { in {
config = { config = {
services.cloudflared.enable = mkDefault true; services.cloudflared = {
enable = mkDefault true;
metricsPort = mkDefault 3011;
metricsBind = "[::]";
};
networking.firewall = mkIf cfg.enable {
interfaces.lan.allowedTCPPorts = mkIf (cfg.metricsPort != null) [
cfg.metricsPort
];
};
boot.kernel.sysctl = mkIf (!config.boot.isContainer && cfg.enable) { boot.kernel.sysctl = mkIf (!config.boot.isContainer && cfg.enable) {
# https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes # https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes
"net.core.rmem_max" = mkDefault 2500000; "net.core.rmem_max" = mkDefault 2500000;

View file

@ -19,6 +19,7 @@
exports = { exports = {
services = { services = {
tailscale.enable = true; tailscale.enable = true;
cloudflared.enable = true;
samba.enable = true; samba.enable = true;
syncplay.enable = true; syncplay.enable = true;
vouch-proxy = { vouch-proxy = {

View file

@ -12,6 +12,7 @@ _: {
keycloak.enable = true; keycloak.enable = true;
vouch-proxy.enable = true; vouch-proxy.enable = true;
vaultwarden.enable = true; vaultwarden.enable = true;
cloudflared.enable = true;
nginx = { nginx = {
enable = true; enable = true;
ports.proxied.enable = true; ports.proxied.enable = true;

View file

@ -23,6 +23,7 @@ _: {
}; };
exports = { exports = {
services = { services = {
cloudflared.enable = true;
}; };
}; };
} }

View file

@ -13,6 +13,7 @@ _: {
enable = true; enable = true;
ports.proxied.enable = true; ports.proxied.enable = true;
}; };
cloudflared.enable = true;
plex.enable = true; plex.enable = true;
invidious.enable = true; invidious.enable = true;
deluge.enable = true; deluge.enable = true;

View file

@ -13,6 +13,7 @@ _: {
enable = true; enable = true;
ports.proxied.enable = true; ports.proxied.enable = true;
}; };
cloudflared.enable = true;
tailscale.enable = true; tailscale.enable = true;
home-assistant.enable = true; home-assistant.enable = true;
zigbee2mqtt.enable = true; zigbee2mqtt.enable = true;

View file

@ -13,6 +13,7 @@ _: {
enable = true; enable = true;
ports.proxied.enable = true; ports.proxied.enable = true;
}; };
cloudflared.enable = true;
unifi.enable = true; unifi.enable = true;
mosquitto.enable = true; mosquitto.enable = true;
dnsmasq.enable = true; dnsmasq.enable = true;