diff --git a/docker_swarm/playbooks/stacks.yml b/docker_swarm/playbooks/stacks.yml index 862a97a..ced4d6c 100644 --- a/docker_swarm/playbooks/stacks.yml +++ b/docker_swarm/playbooks/stacks.yml @@ -3,6 +3,7 @@ hosts: manager roles: - {role: traefik, tags: traefik} + - {role: freshrss, tags: freshrss} - {role: forgejo, tags: forgejo} - {role: radicale, tags: radicale} - {role: hedgedoc, tags: hedgedoc} diff --git a/docker_swarm/roles/traefik/services.yml b/docker_swarm/roles/traefik/services.yml index 8f75e2a..5a99eed 100644 --- a/docker_swarm/roles/traefik/services.yml +++ b/docker_swarm/roles/traefik/services.yml @@ -3,7 +3,9 @@ http: k3s: loadBalancer: servers: - - url: http://jefke.dmz + # TODO: This WILL break when the cluster is reprovisioned and another IP addrss is chosen. + # The load balancer service for Traefik is automatically provisioned by k3s, unsure how to statically assign the IP address. + - url: http://192.168.40.101 esrom: loadBalancer: servers: diff --git a/flake.lock b/flake.lock index 33b0b4a..fa0e44f 100644 --- a/flake.lock +++ b/flake.lock @@ -189,6 +189,41 @@ "type": "github" } }, + "flake-utils_4": { + "inputs": { + "systems": "systems_6" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "id": "flake-utils", + "type": "indirect" + } + }, + "flake-utils_5": { + "inputs": { + "systems": "systems_7" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -220,15 +255,16 @@ "treefmt": "treefmt" }, "locked": { - "lastModified": 1705801181, - "narHash": "sha256-vH+n5qMnwFCx3LMON2hQMi9PjMpmTraGYXe1czJTfAg=", - "owner": "hall", + "lastModified": 1711308696, + "narHash": "sha256-Epx4yztlFp3mNPhMKWgiiSp6Q067pxW9o50ak6WFwxg=", + "owner": "pizzapim", "repo": "kubenix", - "rev": "76b8053b27b062b11f0c9b495050cc55606ac9dc", + "rev": "4ee31f48510b89743d83b7681faea1077fe925b7", "type": "github" }, "original": { - "owner": "hall", + "owner": "pizzapim", + "ref": "fix-protocol", "repo": "kubenix", "type": "github" } @@ -255,6 +291,66 @@ "type": "github" } }, + "nix-github-actions": { + "inputs": { + "nixpkgs": [ + "nixhelm", + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1698974481, + "narHash": "sha256-yPncV9Ohdz1zPZxYHQf47S8S0VrnhV7nNhCawY46hDA=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "4bb5e752616262457bc7ca5882192a564c0472d2", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-github-actions", + "type": "github" + } + }, + "nix-kube-generators": { + "locked": { + "lastModified": 1702548734, + "narHash": "sha256-2pREm/iZ1FyyFuukt/B3nud2NYTUImy5vqc2tESoP9g=", + "owner": "farcaller", + "repo": "nix-kube-generators", + "rev": "fb7a70a8cd76aa76fdf3281123582693aec486a7", + "type": "github" + }, + "original": { + "owner": "farcaller", + "repo": "nix-kube-generators", + "type": "github" + } + }, + "nixhelm": { + "inputs": { + "flake-utils": "flake-utils_4", + "nix-kube-generators": "nix-kube-generators", + "nixpkgs": [ + "nixpkgs" + ], + "poetry2nix": "poetry2nix" + }, + "locked": { + "lastModified": 1711242197, + "narHash": "sha256-UWOb8Aj10O8XshwKA6xVivU0wFfQwVNqLERocVXRgUk=", + "owner": "farcaller", + "repo": "nixhelm", + "rev": "8523ddbdf40f833d3c1421546767513ca57bceea", + "type": "github" + }, + "original": { + "owner": "farcaller", + "repo": "nixhelm", + "type": "github" + } + }, "nixos-hardware": { "locked": { "lastModified": 1710783728, @@ -319,6 +415,31 @@ "type": "github" } }, + "poetry2nix": { + "inputs": { + "flake-utils": "flake-utils_5", + "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "nixhelm", + "nixpkgs" + ], + "systems": "systems_8", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1702365004, + "narHash": "sha256-IRFvmyP1uk1hchRVxaXTqu6YoZCvMM/NVtUf2hD2Tag=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "c12ac880114d52a3cad5fa02b00f2e2090e89982", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "poetry2nix", + "type": "github" + } + }, "root": { "inputs": { "agenix": "agenix", @@ -328,6 +449,7 @@ "flake-utils": "flake-utils_2", "kubenix": "kubenix", "microvm": "microvm", + "nixhelm": "nixhelm", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable" @@ -423,6 +545,50 @@ "type": "github" } }, + "systems_6": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_7": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_8": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "id": "systems", + "type": "indirect" + } + }, "treefmt": { "inputs": { "nixpkgs": [ @@ -444,6 +610,28 @@ "type": "github" } }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixhelm", + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1699786194, + "narHash": "sha256-3h3EH1FXQkIeAuzaWB+nK0XK54uSD46pp+dMD3gAcB4=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "e82f32aa7f06bbbd56d7b12186d555223dc399d1", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, "utils": { "inputs": { "systems": "systems_2" diff --git a/flake.nix b/flake.nix index 76a0d4b..d3137c5 100644 --- a/flake.nix +++ b/flake.nix @@ -29,7 +29,12 @@ }; kubenix = { - url = "github:hall/kubenix"; + url = "github:pizzapim/kubenix/fix-protocol"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + nixhelm = { + url = "github:farcaller/nixhelm"; inputs.nixpkgs.follows = "nixpkgs"; }; }; @@ -47,7 +52,7 @@ ./nix/flake/checks.nix ./nix/flake/deploy.nix ./nix/flake/nixos.nix - ./nix/flake/kubenix.nix + ./nix/flake/kubenix ] // (flake-utils.lib.eachDefaultSystem (system: { formatter = nixpkgs.legacyPackages.${system}.nixfmt; })); diff --git a/kubernetes/kubenix-namespace.yaml b/kubernetes/kubenix-namespace.yaml deleted file mode 100644 index 37ce8b6..0000000 --- a/kubernetes/kubenix-namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: kubenix diff --git a/kubernetes/loadbalancer-test.yaml b/kubernetes/loadbalancer-test.yaml new file mode 100644 index 0000000..dd83b9f --- /dev/null +++ b/kubernetes/loadbalancer-test.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: Service +metadata: + name: loadbalancer-test + # annotations: + # metallb.universe.tf/loadBalancerIPs: 192.168.1.100 +spec: + ports: + - port: 80 + targetPort: 8000 + selector: + app: loadbalancer-test + type: LoadBalancer +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: loadbalancer-test + labels: + app: loadbalancer-test +spec: + replicas: 3 + selector: + matchLabels: + app: loadbalancer-test + template: + metadata: + labels: + app: loadbalancer-test + spec: + containers: + - name: loadbalancer-test + image: mpepping/cyberchef + ports: + - containerPort: 8000 diff --git a/nix/flake/kubenix.nix b/nix/flake/kubenix.nix deleted file mode 100644 index f6b5762..0000000 --- a/nix/flake/kubenix.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ self, flake-utils, kubenix, ... }: flake-utils.lib.eachDefaultSystem - (system: { - kubenix = kubenix.packages.${system}.default.override { - specialArgs.flake = self; - - module = { kubenix, ... }: { - imports = [ kubenix.modules.k8s ]; - kubernetes.kubeconfig = "~/.kube/config"; - kubenix.project = "home"; - - kubernetes.resources = { - deployments.cyberchef.spec = { - replicas = 3; - selector.matchLabels.app = "cyberchef"; - - template = { - metadata.labels.app = "cyberchef"; - - spec = { - containers.cyberchef = { - image = "mpepping/cyberchef"; - - ports = [{ - containerPort = 8000; - protocol = "TCP"; - }]; - }; - }; - }; - }; - - services.cyberchef.spec = { - selector.app = "cyberchef"; - - ports = [{ - protocol = "TCP"; - port = 80; - targetPort = 8000; - }]; - }; - - ingresses.cyberchef.spec = { - ingressClassName = "traefik"; - - rules = [{ - host = "cyberchef.kun.is"; - - http.paths = [{ - path = "/"; - pathType = "Prefix"; - - backend.service = { - name = "cyberchef"; - port.number = 80; - }; - }]; - }]; - }; - }; - }; - }; - }) diff --git a/nix/flake/kubenix/default.nix b/nix/flake/kubenix/default.nix new file mode 100644 index 0000000..312fd52 --- /dev/null +++ b/nix/flake/kubenix/default.nix @@ -0,0 +1,114 @@ +{ self, flake-utils, kubenix, nixhelm, ... }: flake-utils.lib.eachDefaultSystem + (system: { + kubenix = kubenix.packages.${system}.default.override { + specialArgs.flake = self; + + module = { kubenix, ... }: { + imports = [ + kubenix.modules.k8s + kubenix.modules.helm + # ./freshrss.nix + ]; + kubernetes.kubeconfig = "~/.kube/config"; + kubenix.project = "home"; + + kubernetes = { + # namespace = "kubenix"; + + customTypes = { + # HACK: These are dummy custom types. + # This is needed, because the CRDs imported as a chart are not available as Nix modules. + # There is no nix-based validation on resources defined using these types! + # See: https://github.com/hall/kubenix/issues/34 + ipAddressPool = { + attrName = "ipAddressPools"; + group = "metallb.io"; + version = "v1beta1"; + kind = "IPAddressPool"; + }; + + l2Advertisement = { + attrName = "l2Advertisements"; + group = "metallb.io"; + version = "v1beta1"; + kind = "L2Advertisement"; + }; + }; + + resources = { + # namespaces = { + # kubenix = { }; + + # metallb-system.metadata.labels = { + # "pod-security.kubernetes.io/enforce" = "privileged"; + # "pod-security.kubernetes.io/audit" = "privileged"; + # "pod-security.kubernetes.io/warn" = "privileged"; + # }; + # }; + + deployments.cyberchef.spec = { + replicas = 3; + selector.matchLabels.app = "cyberchef"; + + template = { + metadata.labels.app = "cyberchef"; + + spec = { + containers.cyberchef = { + image = "mpepping/cyberchef"; + + ports = [{ + containerPort = 8000; + protocol = "TCP"; + }]; + }; + }; + }; + }; + + services.cyberchef.spec = { + selector.app = "cyberchef"; + + ports = [{ + protocol = "TCP"; + port = 80; + targetPort = 8000; + }]; + }; + + ingresses.cyberchef.spec = { + ingressClassName = "traefik"; + + rules = [{ + host = "cyberchef.kun.is"; + + http.paths = [{ + path = "/"; + pathType = "Prefix"; + + backend.service = { + name = "cyberchef"; + port.number = 80; + }; + }]; + }]; + }; + + ipAddressPools.main = { + # metadata.namespace = "metallb-system"; + spec.addresses = [ "192.168.40.100-192.168.40.254" ]; + }; + + # l2Advertisements.main.metadata.namespace = "metallb-system"; + l2Advertisements.main.metadata = { }; + }; + + helm.releases.metallb = { + chart = nixhelm.chartsDerivations.${system}.metallb.metallb; + # namespace = "metallb-system"; + includeCRDs = true; + }; + }; + }; + }; + }) diff --git a/nix/flake/kubenix/freshrss.nix b/nix/flake/kubenix/freshrss.nix new file mode 100644 index 0000000..62d8b08 --- /dev/null +++ b/nix/flake/kubenix/freshrss.nix @@ -0,0 +1,97 @@ +{ + kubernetes.resources = { + configMaps.freshrss.data = { + TZ = "Europe/Amsterdam"; + CRON_MIN = "2,32"; + ADMIN_EMAIL = "pim@kunis.nl"; + PUBLISHED_PORT = "443"; + }; + + secrets.freshrss.stringData.adminPassword = "ref+file:///home/pim/.config/home/vals.yaml"; + + persistentVolumeClaims.freshrss.spec = { + accessModes = [ "ReadWriteOnce" ]; + storageClassName = "local-path"; + resources.requests.storage = "1Mi"; + }; + + deployments.freshrss = { + metadata.labels.app = "freshrss"; + + spec = { + selector.matchLabels.app = "freshrss"; + + template = { + metadata.labels.app = "freshrss"; + + spec = { + containers.freshrss = { + image = "freshrss/freshrss:edge"; + + ports = [{ + containerPort = 80; + protocol = "TCP"; + }]; + + envFrom = [{ configMapRef.name = "freshrss"; }]; + env = [ + { + name = "ADMIN_PASSWORD"; + valueFrom.secretKeyRef = { + name = "freshrss"; + key = "adminPassword"; + }; + } + { + name = "ADMIN_API_PASSWORD"; + valueFrom.secretKeyRef = { + name = "freshrss"; + key = "adminPassword"; + }; + } + ]; + + volumeMounts = [{ + name = "data"; + mountPath = "/var/www/FreshRSS/data"; + }]; + }; + + volumes = [{ + name = "data"; + persistentVolumeClaim.claimName = "freshrss"; + }]; + }; + }; + }; + }; + + services.freshrss.spec = { + selector.app = "freshrss"; + + ports = [{ + protocol = "TCP"; + port = 80; + targetPort = 80; + }]; + }; + + ingresses.freshrss.spec = { + ingressClassName = "traefik"; + + rules = [{ + host = "freshrss.k3s.kun.is"; + + http.paths = [{ + path = "/"; + pathType = "Prefix"; + + backend.service = { + name = "freshrss"; + port.number = 80; + }; + }]; + }]; + }; + }; +} diff --git a/nix/modules/k3s/default.nix b/nix/modules/k3s/default.nix index fe10be3..3a492d8 100644 --- a/nix/modules/k3s/default.nix +++ b/nix/modules/k3s/default.nix @@ -20,7 +20,7 @@ in { services.k3s = { enable = true; role = "server"; - extraFlags = "--tls-san ${config.networking.fqdn} --data-dir ${config.lab.storage.dataMountPoint}/k3s --disable servicelb"; + extraFlags = "--tls-san ${config.networking.fqdn} --disable servicelb"; }; system.activationScripts.k3s-bootstrap.text = @@ -30,7 +30,7 @@ in { }).config.kubernetes.result; in '' - ln -sf ${k3sBootstrapFile} ${config.lab.storage.dataMountPoint}/k3s/server/manifests/k3s-bootstrap.json + ln -sf ${k3sBootstrapFile} /var/lib/rancher/k3s/server/manifests/k3s-bootstrap.json ''; }; }