diff --git a/README.md b/README.md index 7f3ca08..9b66f82 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,13 @@ My main objective was to have a "light" definition for the containers and to be # Usage ## Prepare the infra constants -- `cp infra/constants.nix.template infra/constants.nix` -- adapt `infra/constants.nix` to match your needs -- touch `infra/ips.nix` +- `cp lib/constants.nix.template lib/constants.nix` +- adapt `lib/constants.nix` to match your needs +- touch `lib/ips.nix` - remove both these files from `.gitignore` and `git add` them. ## Build NixOS template -- modify `infra/lxc-template.nix` as needed +- modify `lib/lxc-template.nix` as needed - run `build-template` - template available in `nixos-template/tarball/` (.tar.xz to be uploaded to Proxmox) @@ -34,19 +34,19 @@ TODO Script the Proxmox Template upload if possible. - run `tofu init` ## Adapt NixOS / Terraform modules building -- edit `lib/containers.nix` to change how a container definition is translated to TF / NixOS config (in particular check the template name) +- edit `lib/container_build.nix` to change how a container definition is translated to TF / NixOS config (in particular check the template name) ## Create containers definitions -- `cp containers/lxc-cont.nix.template containers/lxc-#NAME#.nix` -- edit `containers/lxc-#NAME#.nix` as needed +- run `add-lxc [name] [id]` +- edit `lxc/#NAME#.nix` as needed - run `build-terraform-json` - run `tofu plan` and review the plan - run `tofu apply`, hopefully without errors -- run `deploy #NAME#` +- run `deploy-lxc #NAME#` ## Update container -- edit `containers/lxc-#NAME#.nix` as needed +- edit `lxc/#NAME#.nix` as needed - if the container specs have changed, do all as above -- otherwise you can just run `deploy #NAME#` +- otherwise you can just run `deploy-lxc #NAME#` diff --git a/lib/containers.nix b/container_build.nix similarity index 61% rename from lib/containers.nix rename to container_build.nix index 45c7f63..29f1dfe 100644 --- a/lib/containers.nix +++ b/container_build.nix @@ -1,13 +1,13 @@ -{ def, ... }: +{ def, lib, ... }: let - infra = import ../infra/constants.nix; + infra = import ./constants.nix; hostname = def.hostname; memory = def.memory or 512; cores = def.cores or 1; container_id = def.container_id; disk = def.disk or "4G"; - swap = def.swap or null; # TODO: Implement + swap = def.swap or 512; services = def.services or { }; open_ports = def.open_ports or [ ]; other_packages = def.other_packages or [ ]; @@ -18,6 +18,7 @@ let template = def.template or infra.nixos_template_name; unprivileged = def.unprivileged or true; tags = def.tags or ""; + additional_tf_modules = def.additional_tf_modules or [ ]; in { terraformResource = { @@ -40,30 +41,41 @@ in storage = "local-lvm"; size = disk; }; + swap = swap; vmid = container_id; tags = "terraform;${tags}"; - }; + }; # // each additional_tf_modules ? nixosModule = { config, pkgs, ... }: { imports = [ - ../infra/lxc-template.nix + ./lxc-template.nix ] ++ extraModules; networking.hostName = hostname; networking.firewall.allowedTCPPorts = open_ports; - services = services; - environment.etc = etc; + services = + services + // lib.optionalAttrs (logging_enabled) { + alloy = { + enable = true; + extraFlags = [ + "--server.http.listen-addr=0.0.0.0:12345" + "--disable-reporting" + ]; + }; + }; + environment.etc = + etc + // lib.optionalAttrs (logging_enabled) { + "alloy/config.alloy".text = (import ./config/alloy/config.alloy.nix).out; + "alloy/metrics.alloy".text = + if (logging_metrics_enabled) then + (import ./config/alloy/metrics.alloy.nix { inherit container_id; }).out + else + ""; + }; environment.systemPackages = other_packages; - # logging things... - # # logs configuration ... - # # environment.etc."alloy/config.alloy" = '' loki blabla ''; - # # environment.etc."alloy/metrics.alloy" = '' prometheus blabla ''; - # # - # # -> services.alloy.extraFlags = [ - # # "--server.http.listen-addr=127.0.0.1:12346" - # # "--disable-reporting" - # # ] }; } diff --git a/flake.nix b/flake.nix index ba60da2..d44c6c9 100644 --- a/flake.nix +++ b/flake.nix @@ -29,13 +29,13 @@ pkgs = nixpkgs.legacyPackages.${system}; lib = pkgs.lib; - containersMapping = import ./infra/ips.nix; + containersMapping = import ./lib/ips.nix; containers = import ./lxc { inherit pkgs containersMapping; }; - lxc-def = import ./infra/lxc-template.nix; + lxc-def = import ./lib/lxc-template.nix; - infra = import ./infra/constants.nix; + infra = import ./lib/constants.nix; nixosConfigurations = lib.mapAttrs ( _: def: @@ -45,7 +45,7 @@ } ) containers; - terraformCfg = import ./infra; + terraformCfg = import ./lib/infra.nix; terraformResources = { resource.proxmox_lxc = lib.mapAttrs (_: def: def.terraformResource) containers; @@ -93,19 +93,19 @@ if ! [[ "$2" =~ ^[0-9]+$ ]]; then echo "Error: invalid container ID '$2', should be a number" && exit fi - if ! [ -f infra/ips.nix ]; then - echo "{" > infra/ips.nix - echo "}" >> infra/ips.nix + if ! [ -f lib/ips.nix ]; then + echo "{" > lib/ips.nix + echo "}" >> lib/ips.nix fi - if ! [[ -z "`grep "[^0-9]$2[^0-9]" infra/ips.nix`" ]]; then + if ! [[ -z "`grep "[^0-9]$2[^0-9]" lib/ips.nix`" ]]; then echo "Error: container ID '$2' already used" && exit fi if [ -f lxc/$1.nix ]; then echo "Error: container definition '$1' already exists" && exit fi - sed -i "s#}# $1 = $2;#" infra/ips.nix - echo "}" >> infra/ips.nix - cp lxc/container.nix.template lxc/$1.nix + sed -i "s#}# $1 = $2;#" lib/ips.nix + echo "}" >> lib/ips.nix + cp lib/container.nix.template lxc/$1.nix git add lxc/$1.nix echo "Entry added to infra/ips.nix" echo "Container template copied to lxc/$1.nix, please edit it" @@ -113,7 +113,8 @@ scripts.deploy-lxc.exec = '' if [ -f lxc/$1.nix ]; then - CONTID=`grep -E "$1 ?=" infra/ips.nix | cut -d '=' -f 2 | grep -o '\<[0-9]*\>' ` + CONTID=`grep -E "$1 ?=" lib/ips.nix | cut -d '=' -f 2 | grep -o '\<[0-9]*\>' ` + # TODO Verify mapping exists... echo "Redeploying LXC on container '$1' ('$CONTID')" nixos-rebuild switch --flake .#$1 --target-host root@${infra.ip_prefix}$CONTID echo "Done." diff --git a/lib/config/alloy/config.alloy.nix b/lib/config/alloy/config.alloy.nix new file mode 100644 index 0000000..95fd006 --- /dev/null +++ b/lib/config/alloy/config.alloy.nix @@ -0,0 +1,15 @@ +let + infra = import ../../constants.nix; +in +{ + out = '' + logging { + level = "warning" + } + loki.write "grafana_loki" { + endpoint { + url = "http://${infra.loki_addr}/loki/api/v1/push" + } + } + ''; +} diff --git a/lib/config/alloy/metrics.alloy.nix b/lib/config/alloy/metrics.alloy.nix new file mode 100644 index 0000000..b964439 --- /dev/null +++ b/lib/config/alloy/metrics.alloy.nix @@ -0,0 +1,47 @@ +{ container_id, ... }: +let + infra = import ../../constants.nix; +in +{ + out = '' + prometheus.exporter.unix "default" { + include_exporter_metrics = true + disable_collectors = ["mdadm"] + } + + prometheus.scrape "default" { + targets = array.concat( + prometheus.exporter.unix.default.targets, + [{ + // Self-collect metrics + job = "alloy", + __address__ = "127.0.0.1:12345", + }], + ) + + forward_to = [prometheus.relabel.filter_metrics.receiver] + scrape_interval = "60s" + } + + prometheus.relabel "filter_metrics" { + rule { + action = "drop" + source_labels = [ "env" ] + regex = "dev" + } + rule { + action = "replace" + regex = "127\\.0\\.0\\.1" + target_label = "instance" + replacement = "${infra.build_ip container_id}" + } + forward_to = [prometheus.remote_write.metrics_service.receiver] + } + + prometheus.remote_write "metrics_service" { + endpoint { + url = "http://${infra.prometheus_addr}/api/v1/write" + } + } + ''; +} diff --git a/infra/constants.nix.template b/lib/constants.nix.template similarity index 67% rename from infra/constants.nix.template rename to lib/constants.nix.template index e4315cc..319a277 100644 --- a/infra/constants.nix.template +++ b/lib/constants.nix.template @@ -1,14 +1,28 @@ +let + ip_prefix = "10.0.0."; +in { # Centralizes the IP to the gateway for the containers. gateway_ip = "10.0.0.1"; # Builders for IP addresses, given a container id. - ip_prefix = "10.0.0."; + ip_prefix = ip_prefix; cidr = "24"; build_ip = id: "${ip_prefix}${toString id}"; build_ip_cidr = id: "${ip_prefix}${toString id}/${cidr}"; + loki_addr = "10.0.0.42:3100"; + prometheus_addr = "10.0.0.42:9090"; + reverse_proxy_addr = "10.0.0.50"; + + domains = { + exposed = ".mydomain.tld"; + internal = ".local"; + }; + # Your deployer's host + master_login = "admin"; + master_htpasswd = "$2$10$pouet.pouet"; master_public_ssh_key = "ssh-ed25519 [...] me@here"; # Default timezone for the containers diff --git a/lxc/container.nix.template b/lib/container.nix.template similarity index 66% rename from lxc/container.nix.template rename to lib/container.nix.template index 2a092c2..bdee5d6 100644 --- a/lxc/container.nix.template +++ b/lib/container.nix.template @@ -1,6 +1,6 @@ { pkgs, containersMapping, ... }: let - infra = import ../infra/constants.nix; + infra = import ../lib/constants.nix; in { # OPTIONAL int cores: number of CPU (default = 1) @@ -38,4 +38,20 @@ in # OPTIONAL bool logging.metrics.enable: whether to enable the Alloy metrics configuration (=> Prometheus) logging.metrics.enable = true; + + # OPTIONAL string template: template file to use (default defined in infra/constants.nix) + template = null; + + # OPTIONAL bool unprivileged: whether the container should be unprivileged (default true) + unprivileged = true; + + # OPTIONAL string tags: ';'-separated tags, appended to "terraform" (default empty) + tags = ""; + + # OPTIONAL list of paths additional_tf_modules: list of modules to merge into the tf ressource module (default []) + # Not implemented + additional_tf_modules = []; + + # OPTIONAL bool exposed: whether this host should be exposed by the reverse proxy. + exposed = false; } diff --git a/infra/default.nix b/lib/infra.nix similarity index 100% rename from infra/default.nix rename to lib/infra.nix diff --git a/infra/lxc-template.nix b/lib/lxc-template.nix similarity index 89% rename from infra/lxc-template.nix rename to lib/lxc-template.nix index 9a11976..afad949 100644 --- a/infra/lxc-template.nix +++ b/lib/lxc-template.nix @@ -25,11 +25,6 @@ in coreutils ]; services.openssh.enable = true; - services.chrony = { - enable = true; - enableNTS = true; - servers = [ "time.cloudflare.com" ]; - }; nix.settings = { experimental-features = [ "nix-command" @@ -49,6 +44,7 @@ in openssh.authorizedKeys.keys = [ infra.master_public_ssh_key ]; + initialPassword = "nixos"; }; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; diff --git a/lxc/default.nix b/lxc/default.nix index 3f94eb3..b02564d 100644 --- a/lxc/default.nix +++ b/lxc/default.nix @@ -2,7 +2,7 @@ let lib = pkgs.lib; - containerBuild = import ../lib/containers.nix; + containerBuild = import ../lib/container_build.nix; containersFiles = builtins.readDir ./.; @@ -10,7 +10,7 @@ let lib.mapAttrs ( name: type: if type == "regular" && name != "default.nix" && lib.hasSuffix ".nix" name then - import ./${name} { inherit containersMapping pkgs; } + import ./${name} { inherit name containersMapping pkgs; } else null ) containersFiles @@ -26,7 +26,7 @@ let hostname = hostname; container_id = containersMapping.${hostname}; }; - result = containerBuild { inherit def; }; + result = containerBuild { inherit def lib; }; in { name = hostname;