cluster/services/ways: support multiple backends via consul services

This commit is contained in:
Max Headroom 2024-07-04 17:03:39 +02:00
parent c484a2cf02
commit a39ef182d4
2 changed files with 87 additions and 27 deletions

View file

@ -1,13 +1,18 @@
{ cluster, depot, lib, ... }: { cluster, config, depot, lib, pkgs, ... }:
let let
inherit (depot.lib.meta) domain; inherit (depot.lib.meta) domain;
externalWays = lib.filterAttrs (_: cfg: !cfg.internal) cluster.config.ways; externalWays = lib.filterAttrs (_: cfg: !cfg.internal) cluster.config.ways;
consulServiceWays = lib.filterAttrs (_: cfg: cfg.useConsul) cluster.config.ways;
consulHttpAddr = "${config.services.consul.extraConfig.addresses.http or "127.0.0.1"}:${toString (config.services.consul.extraConfig.ports.http or 8500)}";
in in
{ {
services.nginx.virtualHosts = lib.mapAttrs' (name: cfg: { services.nginx = {
virtualHosts = lib.mapAttrs' (name: cfg: {
name = if cfg.internal then "${name}.internal.${domain}" else "${name}.${domain}"; name = if cfg.internal then "${name}.internal.${domain}" else "${name}.${domain}";
value = { ... }: { value = { ... }: {
imports = [ imports = [
@ -33,6 +38,11 @@ in
}; };
}) cluster.config.ways; }) cluster.config.ways;
appendHttpConfig = lib.mkIf (consulServiceWays != {}) ''
include /run/consul-template/nginx-ways-*.conf;
'';
};
security.acme.certs = lib.mapAttrs' (name: cfg: { security.acme.certs = lib.mapAttrs' (name: cfg: {
name = "${name}.${domain}"; name = "${name}.${domain}";
value = { value = {
@ -41,6 +51,33 @@ in
}; };
}) externalWays; }) externalWays;
services.consul-template.instances.ways = lib.mkIf (consulServiceWays != {}) {
user = "nginx";
group = "nginx";
settings = {
consul.address = "http://${consulHttpAddr}";
template = [
{
source = let
upstreams = lib.mapAttrsToList (_: cfg: ''
upstream ${cfg.nginxUpstreamName} {
{{ range $i, $e := service "${cfg.consulService}~_agent" -}}
server {{ .Address }}:{{ .Port }}{{ if ne $i 0 }} backup{{ end }};
{{end}}
}
'') consulServiceWays;
in pkgs.writeText "ways-upstreams.ctmpl" (lib.concatStringsSep "\n" upstreams);
destination = "/run/consul-template/nginx-ways-upstreams.conf";
exec.command = [
"${config.services.nginx.package}/bin/nginx"
"-s" "reload"
"-g" "pid /run/nginx/nginx.pid;"
];
}
];
};
};
consul.services.ways-proxy = { consul.services.ways-proxy = {
unit = "nginx"; unit = "nginx";
mode = "external"; mode = "external";

View file

@ -1,4 +1,4 @@
{ lib, name, ... }: { lib, name, options, ... }:
with lib; with lib;
@ -20,15 +20,38 @@ with lib;
type = types.str; type = types.str;
}; };
consulService = mkOption {
type = types.str;
};
healthCheckPath = mkOption { healthCheckPath = mkOption {
type = types.path; type = types.path;
default = "/.well-known/ways/internal-health-check"; default = "/.well-known/ways/internal-health-check";
}; };
useConsul = mkOption {
type = types.bool;
internal = true;
default = false;
};
nginxUpstreamName = mkOption {
type = types.str;
internal = true;
};
extras = mkOption { extras = mkOption {
description = "Extra configuration to pass to the nginx virtual host submodule."; description = "Extra configuration to pass to the nginx virtual host submodule.";
type = types.deferredModule; type = types.deferredModule;
default = {}; default = {};
}; };
}; };
config = lib.mkMerge [
(lib.mkIf options.consulService.isDefined {
useConsul = true;
nginxUpstreamName = "ways_upstream_${builtins.hashString "md5" options.consulService.value}";
target = "http://${options.nginxUpstreamName.value}";
})
];
} }