{ description = "kupyter – rootless Kubernetes dev shell"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils, }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = import nixpkgs { inherit system; }; get-all = pkgs.writeShellApplication { name = "get-all"; runtimeInputs = [ pkgs.kubectl ]; text = ''kubectl get pods -A''; }; cluster-start = pkgs.writeShellApplication { name = "cluster-start"; runtimeInputs = [ pkgs.kind pkgs.kubectl ]; text = '' kind create cluster --name kupyter --wait 60s kubectl config use-context kind-kupyter echo "✓ Cluster ready" kubectl cluster-info ''; }; cluster-stop = pkgs.writeShellApplication { name = "cluster-stop"; runtimeInputs = [ pkgs.kind ]; text = '' kind delete cluster --name kupyter rm -f .kubeconfig echo "✓ Cluster deleted, kubeconfig cleared" ''; }; tls-init = pkgs.writeShellApplication { name = "tls-init"; runtimeInputs = [ pkgs.openssl pkgs.kubectl ]; text = '' openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout tls.key \ -out tls.crt \ -subj "/CN=jupyterhub.local/O=kupyter" kubectl create namespace jupyterhub --dry-run=client -o yaml | kubectl apply -f - kubectl create secret tls jupyterhub-tls \ --cert=tls.crt \ --key=tls.key \ --namespace jupyterhub echo "✓ TLS secret stored in jupyterhub namespace" ''; }; helm-repos = pkgs.writeShellApplication { name = "helm-repos"; runtimeInputs = [ pkgs.kubernetes-helm ]; text = '' helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo add jupyterhub https://hub.jupyter.org/helm-chart/ helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add ngshare https://libretexts.github.io/ngshare-helm-repo/ helm repo add prometheus https://prometheus-community.github.io/helm-charts helm repo update echo "✓ all helm repos added and updated" ''; }; ingress-install = pkgs.writeShellApplication { name = "ingress-install"; runtimeInputs = [ pkgs.kubernetes-helm pkgs.kubectl ]; text = '' helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx \ --create-namespace \ --set controller.service.type=NodePort \ --set controller.service.nodePorts.http=30080 \ --set controller.service.nodePorts.https=30443 echo "✓ ingress-nginx installed" kubectl get pods -n ingress-nginx ''; }; jupyterhub-install = pkgs.writeShellApplication { name = "jupyterhub-install"; runtimeInputs = [ pkgs.kubernetes-helm pkgs.kubectl ]; text = '' kubectl create namespace jupyterhub --dry-run=client -o yaml | kubectl apply -f - kubectl create configmap hub-logos \ --from-file=jupyterhub-80.png=./kupyter-notebook/logo.png \ --from-file=jupyterhub.svg=./kupyter-notebook/logo.svg \ --namespace jupyterhub \ --dry-run=client -o yaml | kubectl apply -f - helm upgrade --install jupyterhub jupyterhub/jupyterhub \ --namespace jupyterhub \ --values config.yaml kubectl apply -f jupyterhub-ingress.yaml echo "✓ jupyterhub installing" kubectl get pods -n jupyterhub ''; }; db-install = pkgs.writeShellApplication { name = "db-install"; runtimeInputs = [ pkgs.kubernetes-helm pkgs.kubectl ]; text = '' helm upgrade --install jupyterhub-db bitnami/postgresql \ --namespace jupyterhub \ --set auth.username=jupyterhub \ --set auth.password=jupyterhub \ --set auth.database=jupyterhub echo "✓ postgres installing" kubectl get pods -n jupyterhub ''; }; notebook-build = pkgs.writeShellApplication { name = "notebook-build"; runtimeInputs = [ pkgs.podman pkgs.kind ]; text = '' podman build -t kupyter-notebook:latest ./kupyter-notebook podman save kupyter-notebook:latest -o /tmp/kupyter-notebook.tar kind load image-archive /tmp/kupyter-notebook.tar --name kupyter rm /tmp/kupyter-notebook.tar echo "✓ image built and loaded into cluster" ''; }; hub-build = pkgs.writeShellApplication { name = "hub-build"; runtimeInputs = [ pkgs.podman pkgs.kind ]; text = '' podman build -t kupyter-hub:latest -f Dockerfile.hub . podman save kupyter-hub:latest -o /tmp/kupyter-hub.tar kind load image-archive /tmp/kupyter-hub.tar --name kupyter rm /tmp/kupyter-hub.tar echo "✓ hub image built and loaded" ''; }; ngshare-install = pkgs.writeShellApplication { name = "ngshare-install"; runtimeInputs = [ pkgs.kubernetes-helm pkgs.kubectl ]; text = '' helm upgrade --install ngshare ngshare/ngshare \ --namespace jupyterhub \ --set ngshare.token=822235aaaf83f0232c799fe948cbb1594b01d7d7b11af051871cc2d3fcb08fe8 \ --set ngshare.hub_api_token=822235aaaf83f0232c799fe948cbb1594b01d7d7b11af051871cc2d3fcb08fe8 \ --set ngshare.admins="admin,ngshare-setup" \ --values ngshare-values.yaml echo "Waiting for ngshare..." kubectl wait pod \ --for=condition=ready \ --selector=app.kubernetes.io/name=ngshare \ --namespace jupyterhub \ --timeout=120s echo "✓ ngshare installed" kubectl get pods -n jupyterhub ''; }; ngshare-courses = pkgs.writeShellApplication { name = "ngshare-courses"; runtimeInputs = [ pkgs.kubectl ]; text = '' HUB_POD=$(kubectl get pod -n jupyterhub -l component=hub -o name) kubectl exec -n jupyterhub "$HUB_POD" -- curl -s -X POST \ "http://ngshare.jupyterhub.svc.cluster.local:8080/services/ngshare/course/Programmieren" \ -d "instructors=[\"instructor-Prog\"]" \ -H "Authorization: token setuptoken123456789012345678901234567890123456789012345678901234" kubectl exec -n jupyterhub "$HUB_POD" -- curl -s -X POST \ "http://ngshare.jupyterhub.svc.cluster.local:8080/services/ngshare/course/Signale" \ -d "instructors=[\"instructor-Sig\"]" \ -H "Authorization: token setuptoken123456789012345678901234567890123456789012345678901234" echo "✓ courses created" ''; }; monitoring-install = pkgs.writeShellApplication { name = "monitoring-install"; runtimeInputs = [ pkgs.kubernetes-helm pkgs.kubectl ]; text = '' helm upgrade --install kube-prometheus-stack prometheus/kube-prometheus-stack \ --namespace monitoring \ --create-namespace \ --wait kubectl apply -f ./jupyterhub-monitor.yaml echo "✓ monitoring installed" kubectl get pods -n monitoring ''; }; rebuild-all = pkgs.writeShellApplication { name = "rebuild-all"; runtimeInputs = [ pkgs.kind pkgs.kubectl pkgs.kubernetes-helm pkgs.podman ]; text = '' cluster-stop cluster-start tls-init helm-repos ingress-install hub-build notebook-build db-install ngshare-install jupyterhub-install monitoring-install echo "Waiting for hub to be ready..." kubectl wait pod \ --for=condition=ready \ --selector=component=hub \ --namespace jupyterhub \ --timeout=300s ngshare-courses ''; }; in { devShells.default = pkgs.mkShell { name = "kupyter"; packages = [ get-all cluster-start cluster-stop tls-init helm-repos ingress-install jupyterhub-install notebook-build db-install ngshare-install ngshare-courses hub-build monitoring-install rebuild-all pkgs.openssl pkgs.kubectl pkgs.kubernetes-helm pkgs.podman pkgs.kind ]; shellHook = '' export KUBECONFIG="$(pwd)/.kubeconfig" export KIND_EXPERIMENTAL_PROVIDER=podman echo "" echo " kupyter dev shell" echo " KUBECONFIG → $(pwd)/.kubeconfig (session-local)" echo " runtime → podman (rootless)" echo "" echo " cluster-start # create cluster" echo " cluster-stop # delete cluster + wipe kubeconfig" echo " tls-init # generate self-signed cert" echo " helm-repos # add and update helm repos" echo " ingress-install # install nginx ingress" echo " notebook-build # build and load notebook image" echo " jupyterhub-install # install jupyterhub" echo " get-all # show all pods" echo "" ''; }; } ); }