modules/containers: a hacc-specific containers module #11

Manually merged
stuebinm merged 1 commit from hacc.containers into main 2024-04-27 21:12:52 +00:00
10 changed files with 134 additions and 135 deletions

View file

@ -38,33 +38,20 @@
system = "x86_64-linux";
config.allowUnfree = true;
};
evalConfig = config: (nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
config
{
nixpkgs.pkgs = pkgs.lib.mkForce pkgs;
imports = [ modules.nopersist profiles.container ];
}
];
specialArgs = {
# some of our modules import each other, and evalConfig is used for containers
inherit modules evalConfig;
sources = inputs;
};
}).config.system.build.toplevel;
in {
nixosConfigurations.parsons = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./parsons/configuration.nix
./modules/buildinfo.nix
./modules/containers.nix
sops-nix.nixosModules.sops
{ nixpkgs.pkgs = pkgs; }
];
specialArgs = {
sources = inputs;
inherit modules evalConfig;
inherit modules profiles;
inherit (nixpkgs.lib) nixosSystem;
};
};

View file

@ -14,12 +14,5 @@
'';
};
# I /suspect/ this is not actually needed.
# TODO: find spoons to deal with potential breakage, test removing this
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
system.stateVersion = lib.mkDefault "21.05";
}

95
modules/containers.nix Normal file
View file

@ -0,0 +1,95 @@
{ config, lib, pkgs, modules, profiles, sources, nixosSystem, ... }:
let
mkIPv4 = index: local:
"192.168.${if local then "100" else "101"}.${toString index}";
mkIPv6 = index: local:
"fd00::${if local then "100" else "101"}:${toString index}";
evalConfig = nixosConfig: (nixosSystem {
inherit (config.nixpkgs) system;
modules = [
nixosConfig
modules.nopersist
profiles.container
{ nixpkgs.pkgs = lib.mkForce pkgs; }
];
specialArgs = {
inherit modules sources;
};
}).config.system.build.toplevel;
in {
options.hacc.containers = with lib.options;
mkOption {
description = ''
hacc-specific containers. These are a thin wrapper around "normal" nixos containers:
- they automatically get an IPv4/IPv6 address assigned
(note that these are not guaranteed to be stable across config changes,
so please use {option}`containers.<name>.hostAddress` & friends to
reference them elsewhere)
- they set a couple default options (e.g. ephemeral, autoStart, privateNetwork)
- they are evaluated with our own version of {nix}`evalConfig`, which includes a
couple more modules by default, use our version of `nixpkgs`, and includes the
{nix}`profiles.containers` profile setting sane defaults for containers.
'';
default = { };
type = with lib.types;
types.attrsOf (types.submodule {
options = {
bindToPersist = mkOption {
default = true;
type = types.bool;
description =
"Wether to mount /persist/containers/<name> at /persist into this container.";
};
bindSecrets = mkOption {
default = false;
type = types.bool;
description =
"Whether to mount /run/secrets/<name> at /secrets into this container.";
};
config = mkOption {
type = types.unspecified;
description =
"The container's config, to be evaluated with our own {nix}`evalConfig`.";
};
};
});
};
# wrapped into imap1, which enumerates the containers; IP addresses are then
# simply assigned based on the order the containers are in the list.
config.containers = lib.mkMerge (lib.imap1
(index: { name, value }: let container = value; in {
${name} = {
hostAddress = mkIPv4 index false;
localAddress = mkIPv4 index true;
hostAddress6 = mkIPv6 index false;
localAddress6 = mkIPv6 index true;
privateNetwork = true;
autoStart = true;
ephemeral = true;
bindMounts = lib.mkMerge [
(lib.mkIf container.bindToPersist {
"/persist" = {
hostPath = "/persist/containers/${name}";
isReadOnly = false;
};
})
(lib.mkIf container.bindSecrets {
"/secrets" = {
hostPath = "/run/secrets/${name}";
isReadOnly = true;
};
})
];
path = evalConfig container.config;
};
}) (lib.attrsToList config.hacc.containers));
}

View file

@ -1,19 +1,8 @@
{ config, lib, pkgs, evalConfig, ... }:
{ config, lib, pkgs, ... }:
{
containers.forgejo = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.10";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/forgejo";
isReadOnly = false;
};
};
path = evalConfig ({ config, lib, pkgs, ... }: {
hacc.containers.forgejo = {
config = { lib, pkgs, ... }: {
system.stateVersion = "21.11";
environment.systemPackages = [ pkgs.forgejo ];
@ -79,7 +68,7 @@
services.openssh = {
enable = true;
listenAddresses = [ {
addr = "192.168.100.10";
addr = config.containers.forgejo.localAddress;
port = 22;
} ];
settings = {
@ -87,7 +76,7 @@
AcceptEnv = "GIT_PROTOCOL";
};
};
});
};
};
services.nginx.virtualHosts."git.infra4future.de" = {

View file

@ -1,4 +1,4 @@
{ config, lib, pkgs, evalConfig, ... }:
{ config, lib, pkgs, ... }:
{
@ -6,20 +6,11 @@
"hedgedoc-hacc/env" = {};
};
containers.pad-hacc = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.5";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/pad-hacc";
isReadOnly = false;
};
"/secrets".hostPath = "/run/secrets/hedgedoc-hacc";
};
path = evalConfig ({ config, lib, ... }: {
containers.pad-hacc.bindMounts = {
"/secrets".hostPath = "/run/secrets/hedgedoc-hacc";
};
hacc.containers.pad-hacc = {
config = { config, lib, ... }: {
services.hedgedoc = {
enable = true;
settings = {
@ -78,7 +69,7 @@
location = "/persist/backups/postgres";
};
hacc.bindToPersist = [ "/var/lib/hedgedoc" ];
});
};
};
services.nginx.virtualHosts."pad.hacc.earth" = {
enableACME = true;

View file

@ -1,19 +1,8 @@
{ config, lib, pkgs, evalConfig, ... }:
{ config, lib, pkgs, ... }:
{
containers.pad-i4f = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.6";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/pad-i4f";
isReadOnly = false;
};
};
path = evalConfig ({ config, lib, ... }: {
hacc.containers.pad-i4f = {
config = { config, lib, ... }: {
services.hedgedoc = {
enable = true;
settings = {
@ -57,7 +46,7 @@
location = "/persist/backups/postgres";
};
hacc.bindToPersist = [ "/var/lib/hedgedoc" ];
});
};
};
services.nginx.virtualHosts."pad.infra4future.de" = {

View file

@ -1,26 +1,14 @@
{ config, pkgs, lib, evalConfig, ...}:
{ config, pkgs, lib, ...}:
{
sops.secrets = {
"mattermost/env" = {};
};
containers.mattermost = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.3";
ephemeral = true;
hacc.containers.mattermost = {
bindSecrets = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/mattermost";
isReadOnly = false;
};
"/secrets".hostPath = "/run/secrets/mattermost";
};
path = evalConfig ({ config, lib, pkgs, ... }: {
config = { config, lib, pkgs, ... }: {
systemd.services.mattermost.serviceConfig.EnvironmentFile =
lib.mkForce "/secrets/env";
@ -218,7 +206,7 @@
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
});
};
};
services.nginx.virtualHosts."mattermost.infra4future.de" = {

View file

@ -1,19 +1,8 @@
{ config, lib, pkgs, evalConfig, ... }:
{ config, lib, pkgs, ... }:
{
containers.nextcloud = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.2";
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/nextcloud";
isReadOnly = false;
};
};
path = evalConfig ({ config, lib, pkgs, ... }: {
hacc.containers.nextcloud = {
config = { config, lib, pkgs, ... }: {
environment.systemPackages = [ pkgs.htop ];
services.nextcloud = {
@ -82,7 +71,7 @@
requires = ["postgresql.service"];
after = ["postgresql.service"];
};
});
};
};
services.nginx.virtualHosts."cloud.infra4future.de" = {

View file

@ -1,4 +1,4 @@
{ config, lib, pkgs, evalConfig, ... }:
{ config, lib, pkgs, ... }:
let
tracktrain-config = ''
@ -25,14 +25,14 @@ in
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://192.168.42.41:4000";
proxyPass = "http://${config.containers.tracktrain.localAddress}:4000";
proxyWebsockets = true;
};
# note: this shadows the /metrics endpoint of tracktrain
# in case you remove this, please consider putting something
# else here to keep it from being publicly scrapable
locations."/metrics/" = {
proxyPass = "http://192.168.42.41:2342";
proxyPass = "http://${config.containers.tracktrain.localAddress}:2342";
proxyWebsockets = true;
extraConfig = ''
rewrite ^/metrics/(.*) /$1 break;
@ -40,21 +40,10 @@ in
};
};
containers.tracktrain = {
privateNetwork = true;
hostAddress = "192.168.42.40";
localAddress = "192.168.42.41";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/tracktrain";
isReadOnly = false;
};
"/secrets".hostPath = "/run/secrets/tracktrain";
};
hacc.containers.tracktrain = {
bindSecrets = true;
path = evalConfig ({ config, lib, pkgs, ... }: {
config = { config, lib, pkgs, ... }: {
system.stateVersion = "21.11";
users.users.tracktrain = {
@ -151,7 +140,7 @@ in
systemd.services.grafana.serviceConfig.EnvironmentFile =
"/secrets/env";
hacc.bindToPersist = [ "/var/lib/grafana" ];
});
};
};
}

View file

@ -1,19 +1,8 @@
{ config, lib, pkgs, evalConfig, ... }:
{ config, lib, pkgs, ... }:
{
containers.uffd = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.9";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/uffd";
isReadOnly = false;
};
};
path = evalConfig ({ config, lib, pkgs, ... }: {
hacc.containers.uffd = {
config = { config, lib, pkgs, ... }: {
services.uwsgi = {
enable = true;
plugins = [ "python3" ];
@ -29,7 +18,7 @@
hook-pre-app = "exec:FLASK_APP=${pkgs.uffd}/lib/python3.10/site-packages/uffd flask db upgrade";
};
};
});
};
};
services.nginx.virtualHosts."login.infra4future.de" = {
enableACME = true;