This commit is contained in:
2026-03-24 10:59:50 +01:00
commit 7c1c161ced
19 changed files with 856 additions and 0 deletions

18
.kubeconfig Normal file
View File

@@ -0,0 +1,18 @@
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJY1R6R0hSU3FrblF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TmpBek1qUXdNREExTXpOYUZ3MHpOakF6TWpFd01ERXdNek5hTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUUN2aVFqN0Z0dVhpZlZRYURtNUNNYmxNYXFaMXJXVGZDMk5SSEJWcVN4M0YxS1IzWlpRZ1J3YjZ5eSsKbU5FLzRZV2ZOK1NJUVEvbG93Y2llMXZxLzl6QTFNaXY4enM0YlRQaU5sY0hRTm9iYkRiUHBUNkNVdXpvdjdqRgpqbXhiQ3BlNlhpSmlTVHQvT3h6Wlg3NzZiUVAvNkxUTEdtdm1xaWxTa0I4Rjl6eVlFRmJrbkVYQkp1UHBXY0pUCkdCUmpyMzJzS05RbE13c2thSFhnNmVsRzhVa1FFMDNQeUpITi8yazlNZWpVWmVwQll2VE1mKzZCMW56ZDdVWWoKKzA2Z3EzWUhlUDE3R0kxVjRzR0UwMDJ3a1RsS213UUNiV1p2NkZMRHl3M01hL0RWdGFjQ0pQMklVeFhHeCs3agowRE0wZXZMN2ZMUnNGbGtSNGl2U09VcmJIamlQQWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJSNjE3TXZ0L01uQXR0aHZXZHZoTWxMcEs3MDZ6QVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQWczVmNNUVFYcQpxSXNhd1RxOXByM05oY282Zk83U3g0MkNncXZXZzFIMXYxR1hiNVMzaDlaaUN1cVF4MkUvT0lNSmdUdytNblY5ClNZMVJKZ1Qvc0RGQk5jQ3ZLM1ZPVmpCdmFmRUh3b3V4dTlGSzdTaityaWJ4STNod3dsNFVrSit6Ly93ZWl0L0IKMXRWSXE5Y1lLblhFck9sQmJ1KzZYR3phTmRzOVBPSGZwU2g3ZWlhTFVZemNDaXN3b2NQN0NVdE53bUViekVZNwpLRFZKclJSWEtTNTdtYnNXSlpnWVFEZGlDVzMvNkI4TUg1YTVoakdjempadjBNc2hsVmtuWWlNL3RrbEExdWxCCi9TM2ZXdnhuallicWlWcXJDbzRMSFhwV0tHbFdyY1ZtSFJVcnZ1ZjlYQ09ncEhyUnRVVHFOOFVUQy95MXN0eDAKZjAzcHd0aGZXSU8rCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
server: https://127.0.0.1:39209
name: kind-kupyter
contexts:
- context:
cluster: kind-kupyter
user: kind-kupyter
name: kind-kupyter
current-context: kind-kupyter
kind: Config
users:
- name: kind-kupyter
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLVENDQWhHZ0F3SUJBZ0lJT0xIdlBuY3E1VWN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TmpBek1qUXdNREExTXpOYUZ3MHlOekF6TWpRd01ERXdNek5hTUR3eApIekFkQmdOVkJBb1RGbXQxWW1WaFpHMDZZMngxYzNSbGNpMWhaRzFwYm5NeEdUQVhCZ05WQkFNVEVHdDFZbVZ5CmJtVjBaWE10WVdSdGFXNHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDdFRVMzgKYXFqTzVlbG5hclhRUWxDcEZiTDNHSnpVY0lhY2ROeHV5NzFZUitEZmc2bEdJK3puQlFVTlpYOXhpak5TbHlZNgpiQ00rQk9IR09vVGxsdUxhL1RXbWNaUnhYYVBCeVpHY3ZkWVJCNFNVT2JlZ1BwT0xjajFBaXdvbU9IQUVOYXNzClZUeFlEcXlOUnd5M1cwNGFVcWNMREMyVUtDU0hEUVk1dlphOWo4MXpkdjl0K0g5L2RZb1diM3RHOTVySlRndE0KUGhhcDZkNlpoVUVXSDl1aE5Ha2YreE01Zi9KaUVRNnovWmc1alBsdHVHcGhaSUR5QmhUcUJaZnNJTjN3UllreQpiRnp6SndMZTZVVmhRQlE2YjVjZjlHYXVndWVocmFLb0wxUThJVFJuR2JvR0ZEb3dUbkQwaGN1V0RqZi9QbnV2CnZIUWk4L0pqK3pKcDBWek5BZ01CQUFHalZqQlVNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUsKQmdnckJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRkhyWHN5KzM4eWNDMjJHOQpaMitFeVV1a3J2VHJNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNXUHhIdDJpM0ZERHkyd3JOeDBJZkFLYUF3CldWMzVCNTcxblVNTWltNVFjalVMUEU1c0praEpra3VGNGRZTlU5amM4K0c1WHF6QnpyQlpBajg5dWI3UmM2MXAKbVpQekEvWHlUbjZBK1BBRFBBRlkxSE9FMmdtSmd4eFZjV08rRmtyRzBZN1pjemRQdzdJRjQySzFDYzVSMDU1TApENjNGMkhaWEQ5d3NYWC8zYS9ReWpuMlFFN0dXOWc4MTUya1lMeVYycGN3cVo5aTFRNlgyUjBzbXRiOEt4UFZDCkdhS2ZwKy9NVXdZOE40WHdOakIraVo5anVvWU1mR095TFBieGIzTThMblR3bkRxNHdRRjV5c24vVFJQWCtFNHAKbnFCblNXbDVSVzdERi9VVi9na0pIbDlxWTJydFlEZkkyWHJ5YzJKdVhUSTh3N1BjRi80QVlFQnQvQkZXCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBclUxTi9HcW96dVhwWjJxMTBFSlFxUld5OXhpYzFIQ0duSFRjYnN1OVdFZmczNE9wClJpUHM1d1VGRFdWL2NZb3pVcGNtT213alBnVGh4anFFNVpiaTJ2MDFwbkdVY1YyandjbVJuTDNXRVFlRWxEbTMKb0Q2VGkzSTlRSXNLSmpod0JEV3JMRlU4V0E2c2pVY010MXRPR2xLbkN3d3RsQ2draHcwR09iMld2WS9OYzNiLwpiZmgvZjNXS0ZtOTdSdmVheVU0TFRENFdxZW5lbVlWQkZoL2JvVFJwSC9zVE9YL3lZaEVPcy8yWU9ZejViYmhxCllXU0E4Z1lVNmdXWDdDRGQ4RVdKTW14Yzh5Y0MzdWxGWVVBVU9tK1hIL1Jtcm9Mbm9hMmlxQzlVUENFMFp4bTYKQmhRNk1FNXc5SVhMbGc0My96NTdyN3gwSXZQeVkvc3lhZEZjelFJREFRQUJBb0lCQUFLSjMxcVROV1hTZUZqTApkMTVWbWxqZnVIOW1IT1gvdi9rS3ZTL2lUQ08rNmN4Y1lWNWxxRks2QUJqeUk2dkdHbnBiUEhRZW9XV0hMTWQ2CmsvZkkvZ20zSzlJRVYraFJOdFRmM3dJc3hiWDZKamNGb1dyM2Y3SExPcHAzYnU2Z1pRT3F4WmNncUlHaHRXVmMKWlJOS2d4cGZtNUxOMnQwUXVYaEErSlpmOEpWV1A3OHFsaUNFQ2ZEd3pCRVpRVHVoYmhwRGhvNjBxL0UzU3RQVQprTGMzVitONnFEK0szeTZpM0hWU3lldkpYWWg0RXJCNlY1RTVweU5wZU90d1BhbThVRG91ZWZpcFZJQkVWVHhvCm00NVNCanZSQnRRYWRxMGN5M0p0L3N3aEtJQUVpT0c2WE1icmc4bzFWSDRNNnJiWmlQdDBiODVOUVJNd0FuR2kKMUsrTU9RRUNnWUVBeWtWMFZlSmdObS8rSVVsblRscGgzOENKd3kydU5QVXBRSHBoQ3pjVUxkQXV0Ri8yNTgvTwpJeVBoMVB5bzNCOXBLVVdmYnRpVjJoZjhXUjV3UjdJakpLWDhzaHRqcEs3TkJvTDhrdnBRUVl0QS9CVS9KR2E0ClRKaWpsbGJNOWtXYzF2dEs5YStQV255U3hCb1psb0hYaE1lRzFMK2JpRE5FcFk4c2hTbzVkTU1DZ1lFQTIxWHIKNnRuelhSRGVtMzdRRmttOXpUL01tSmROQ3MxOVovU2kvNGVRTHpKNkM2RlJUMGNFTHpHVjA3SXdIYjhMZ1JPTwpUY2g3V3RXYngwa2o4L2RVcXNJWXpLYzRhT2hsVVg2aUNpZVZBakdETzg2aFVWT3FkTmVXaFZudDdyZE95cTgxCmtNdkdTTmV6ZlFTMnE0cU1GQVUwcGpVdDQwaiszWFdJdVdvRWp5OENnWUVBbmtzc2QrbnBFYkVqV0RseHQwZlUKUUo4Vk1NR1hDNnF3MWR6d0JTN2RnOXpnTUJqSnlUQS9TaERTc3pQbmtoeWkxOEc4dTZxVDIxSGFFb1JYcWtRbQpiSS9aNmlpMUdqUVNEMzZDMnlNNW01RzNFWkF2RWZXeFZZQSt4WEM0aGlLRVUxbmxsOUFFaC9QbGg4SkZOQnY0CjVkaWdFKzYvY1I5dUlZS2lmTFJHc3JFQ2dZQmZ3cXFtdFpPSURXWnpVekY4bWFOeGFpcGtjS0psVmdRcmorWmUKVkF5Q1hySmtRNEVoY0tzR0E4c2JTdyt3M1FranlLcjNrTkV5ZmxKdDlxUG96eEk3SDFUK2ZQK201ZGZlZGNBLwpXTHE0NDI4ZGZJQjM1bVJrY1ArNXB1SzN0M2FDRFc4QWtjYzNaRjFyOXRQZUh6WTdRMjZTSm1PcmVPSTFSQ3gyCmJ6QWdad0tCZ1FDNUlhVTdzWmlrVVlwbmZJYUZKK1NGTTN4b1lIWVpzNHYvN0t5OEhCM2VqVHlZbXl1QjBZNFYKUDhqZlg4SUxsN0o3a3dKNGpnd2kyWGZxckorOW9SRzZ0N0I5R3EyM3pUR29rSnJXSFRKeXJOcnpUalRRT1A2LwpTNERObWgrM1Mxd1MxTC9IY25VZk1uUmFnMEtraTFIQ0ExdFQzK3Q1a254dWxxYldOUlUyVUE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=

10
Dockerfile.hub Normal file
View File

@@ -0,0 +1,10 @@
FROM quay.io/jupyterhub/k8s-hub:4.3.2
USER root
RUN apt-get update && apt-get install -y nodejs npm && apt-get clean
USER jovyan
RUN pip install --upgrade pip
RUN pip install git+https://github.com/jupyter/nbgrader.git@main ngshare_exchange
COPY ./kupyter-notebook/nbgrader_config.py /etc/jupyter/nbgrader_config.py

89
config.yaml Normal file
View File

@@ -0,0 +1,89 @@
hub:
image:
name: localhost/kupyter-hub
tag: latest
pullPolicy: Never
services:
ngshare:
url: http://ngshare.jupyterhub.svc.cluster.local:8080
apiToken: 822235aaaf83f0232c799fe948cbb1594b01d7d7b11af051871cc2d3fcb08fe8
ngshare-admin:
apiToken: setuptoken123456789012345678901234567890123456789012345678901234
db:
type: postgres
url: postgresql+psycopg2://jupyterhub:jupyterhub@jupyterhub-db-postgresql.jupyterhub.svc:5432/jupyterhub
config:
JupyterHub:
authenticator_class: nativeauthenticator.NativeAuthenticator
admin_users:
- admin
- instructor-Prog
- instructor-Sig
NativeAuthenticator:
open_signup: false
allowed_users:
- admin
- instructor-Prog
- instructor-Sig
extraVolumes:
- name: hub-logos
configMap:
name: hub-logos
extraVolumeMounts:
- name: hub-logos
mountPath: /usr/local/share/jupyterhub/static/images/jupyterhub-80.png
subPath: jupyterhub-80.png
- name: hub-logos
mountPath: /usr/local/share/jupyterhub/static/images/jupyterhub.svg
subPath: jupyterhub.svg
extraConfig:
ngshare.py: |
c.JupyterHub.services.append({
'name': 'ngshare',
'url': 'http://ngshare.jupyterhub.svc.cluster.local:8080',
'api_token': '822235aaaf83f0232c799fe948cbb1594b01d7d7b11af051871cc2d3fcb08fe8',
'oauth_no_confirm': True})
nbgrader: |
c.JupyterHub.load_groups = {
"formgrader-users": ["admin"]
}
proxy:
secretToken: "8031b6dca309ff7259a10d1d38c70c4852d17d5bab02c31cbe7d76a3fb60cb66"
prePuller:
hook:
enabled: false
continuous:
enabled: false
cull:
enabled: true
timeout: 1800
every: 300
singleuser:
defaultUrl: "/tree"
image:
name: localhost/kupyter-notebook
tag: latest
pullPolicy: Never
memory:
limit: 1G
guarantee: 256M
cpu:
limit: 1
guarantee: 0.1
cloudMetadata:
blockWithIptables: false
networkPolicy:
enabled: false

61
flake.lock generated Normal file
View File

@@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1773734432,
"narHash": "sha256-IF5ppUWh6gHGHYDbtVUyhwy/i7D261P7fWD1bPefOsw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "cda48547b432e8d3b18b4180ba07473762ec8558",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

318
flake.nix Normal file
View File

@@ -0,0 +1,318 @@
{
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 ""
'';
};
}
);
}

8
hub-logo-configmap.yaml Normal file
View File

@@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: hub-logos
namespace: jupyterhub
binaryData:
jupyterhub-80.png: ""
jupyterhub.svg: ""

21
jupyterhub-ingress.yaml Normal file
View File

@@ -0,0 +1,21 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jupyterhub
namespace: jupyterhub
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
spec:
ingressClassName: nginx
rules:
- host: jupyterhub.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: proxy-public
port:
number: 80

20
jupyterhub-monitor.yaml Normal file
View File

@@ -0,0 +1,20 @@
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: jupyterhub
namespace: monitoring
labels:
release: kube-prometheus-stack
spec:
namespaceSelector:
matchNames:
- jupyterhub
selector:
matchLabels:
component: hub
app: jupyterhub
release: jupyterhub
endpoints:
- port: hub
path: /hub/metrics
interval: 30s

View File

@@ -0,0 +1,7 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: kupyter
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"]
endpoint = ["http://10.89.2.2:5000"]

16
kind-config.yaml Normal file
View File

@@ -0,0 +1,16 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: kupyter
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:5000"]
endpoint = ["http://REGISTRY_IP:5000"]

View File

@@ -0,0 +1,9 @@
FROM jupyter/datascience-notebook:latest
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY nbgrader_config.py /etc/jupyter/nbgrader_config.py
COPY logo.png /opt/conda/lib/python3.13/site-packages/nbclassic/static/base/images/logo.png
COPY logo.png /opt/conda/lib/python3.13/site-packages/jupyter_server/static/logo/logo.png

BIN
kupyter-notebook/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

198
kupyter-notebook/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -0,0 +1,11 @@
from ngshare_exchange import configureExchange
c = get_config()
configureExchange(
c, "http://ngshare.jupyterhub.svc.cluster.local:8080/services/ngshare"
)
c.CourseDirectory.course_id = "*"
c.FormgradeApp.base_url = "/user/{username}/"

View File

@@ -0,0 +1,7 @@
folium
seaborn
#tensorflow
#torch
nbgrader
ngshare_exchange
rise

9
nbgrader_config.hub.py Normal file
View File

@@ -0,0 +1,9 @@
from ngshare_exchange import configureExchange
c = get_config()
configureExchange(
c, "http://ngshare.jupyterhub.svc.cluster.local:8080/services/ngshare"
)
c.CourseDirectory.course_id = "*"

6
ngshare-values.yaml Normal file
View File

@@ -0,0 +1,6 @@
pvc:
accessModes:
- ReadWriteOnce
ngshare:
debug: true

20
tls.crt Normal file
View File

@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDOzCCAiOgAwIBAgIUdweHytW9S6NYnsg8qQC7qkXrSAkwDQYJKoZIhvcNAQEL
BQAwLTEZMBcGA1UEAwwQanVweXRlcmh1Yi5sb2NhbDEQMA4GA1UECgwHa3VweXRl
cjAeFw0yNjAzMjQwMDExMjJaFw0yNzAzMjQwMDExMjJaMC0xGTAXBgNVBAMMEGp1
cHl0ZXJodWIubG9jYWwxEDAOBgNVBAoMB2t1cHl0ZXIwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCsSo1M0tgSqAwEFQ2XY8qJIdhFvJojTj2mK18gizfS
Egn9whTynbKX6+AxRRlH+TQ8TQ91IYXGpZJaAXnxpwwC1X9qjeqrKFoI9927Bgp2
1CzK8dI2Q7DZPTeSgAAW79dSjApwxqiw+Dy+PP1REe94UvKg/PQezN8Zy3V4+c9F
7noVgUp/xEWPsVwsH84uX2XI7HyHv4t3sMAzqD4d/41GoJX8FZwwK5IKuIyiNVJo
y2UUjcG7qXUUBUXuOcpyW0l9zwRsDtqp6mqXj4+VCdLHKYP/X/mftLK+cwhzNvN5
uWooZf78igN7rFp1n6cvmIUuQEUnnPGkwBfbZSFK0l7NAgMBAAGjUzBRMB0GA1Ud
DgQWBBRA0biw83Xcib+sQcIypsreXfv9oDAfBgNVHSMEGDAWgBRA0biw83Xcib+s
QcIypsreXfv9oDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB5
ufcXwO0iKoXkPkAoVXEz4xs0uGQ6Q4nq23VYoNGqKtqlRm7p9FnWv/OFC6p4QXT8
J1Ju2oa5iQ8iUVvznPEUz78995xMtrnpQbJCHOBvCMpYojNiOmq1d+rxZvzJrVmS
PxMtljbS1Xk60WTmGoWIFjEl8j0TARVzW3tnafEv83Ss/E4oZjo7RVVsyyAa+VQ/
6kB3HsJRdie+9FpOFU0YzyFuQb+e8mVVUSMwI42WAflDK+PD8ZjyRWVrj+WNWM0b
1Ic1Fe8BzGuDigPc6Md8i09WePyLWw+Q11x2ZCMJzKk4Nh0EPmgemusRUPXBsk0Z
ozVE/zLvqtJg+94F8q9l
-----END CERTIFICATE-----

28
tls.key Normal file
View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsSo1M0tgSqAwE
FQ2XY8qJIdhFvJojTj2mK18gizfSEgn9whTynbKX6+AxRRlH+TQ8TQ91IYXGpZJa
AXnxpwwC1X9qjeqrKFoI9927Bgp21CzK8dI2Q7DZPTeSgAAW79dSjApwxqiw+Dy+
PP1REe94UvKg/PQezN8Zy3V4+c9F7noVgUp/xEWPsVwsH84uX2XI7HyHv4t3sMAz
qD4d/41GoJX8FZwwK5IKuIyiNVJoy2UUjcG7qXUUBUXuOcpyW0l9zwRsDtqp6mqX
j4+VCdLHKYP/X/mftLK+cwhzNvN5uWooZf78igN7rFp1n6cvmIUuQEUnnPGkwBfb
ZSFK0l7NAgMBAAECggEAAKUpL6g7X4nIvQHm/iwWoHoyGonWwtTPrDJN1deW45qJ
PAq1Dl+0WF0zQNqGEXv5F4K26D1sZVFxIYlsg8sYTBnfvvPmdNUqcMfiSRUjHhNu
gMfdIIPkd1JUxZ+2cdPoLo2KgzHe4cA4lI34LzsfXx9K8HrvGXNV8f1fjUjrR+pX
n2aCTCr+yqvF57ja9JugwOVdpWxfdJK7Km19cEDh78BTwJhmw0dUujh8eFcecxN0
m9s+HKuOs+TDhl5G2FgfmGxJgz/g5qUDPy+MulPISpQnkFNQ8lYV1FYpCxqsbm+D
L4uGNqvaUbgsl/TDuujcSnFzPNih01D6ZiHESwE/pwKBgQDSGp6RqfA7e9HTIRmW
HORupf1eE/qdIwVWVhBcmHOB6teAY5gtltEnFojOi6+nwm3yuU72pD59S+Ev08g+
fxdDAdaGR16+9Ih6KvPQNiI+2w9p0huoXIz+kZPGOYrL2d5hsKQrOnNHUEVwHQ4J
BhMrr5Sf4Xjxpv8ATgKyb39CowKBgQDR7WCAFUwvyisVrz1GDAkGzmimbLtWUsSg
dzOX0e54zDf8sC4QJdgowSIsFbfQqfkQQkUJrVA3Lk92XNfuyBo4RS9rnNv0F4eC
4CMFcBsjQ5gIgu5OHbXf1RFoc4fwabetIbb7z3xbmixQfJxgbyzySO8GZ7RwtLN+
/pVvthtfzwKBgQDHkCM3hmu5hFV7rb/o1o6fDqkHOADeSopiRCMMYH2uVArXV0IP
Y2ZMM1pEnWd99+6JEzyOhtkYF//PduCHhB3rNo62Qooa5JfROoUVKqYCf/427Cv7
EdWWY14ydSuBjvJsZeS5bq5aeUNLRz2ykoOZBhAsgHRpS86AUpi7Na5x8wKBgGi8
Dq44cfdR3ScHdAGTlZlQt8N4cgrCZplMf3Aaa+jWsoQefgzOZMcIfH0UJM41Ty6+
cWU/k8rEDx8VeSIHsZUrZ1pAOzjP2GsCWlanNNLmMV7lu/E7P3c5/WJoaYUXqWz2
ai29ueSVydAqK3atYPZMTvyaFts4PGl6qKHAcG3fAoGBALYJ7OhtEddzo3PKPZOh
uhH2vyRsLuTZCZYDGPIdxHSS0Kk307oghIZhYwKf+fx5H1Y6xtmZ59QUAg4V2Ol2
p8uoJW50skVHx/OwZkm+wQkBF+INj4akG/MaFpJ8XcwWtn8FiEMN+ljBJx7nu6dW
GxA2b5RVTQ8SBnF2TEFwjw5o
-----END PRIVATE KEY-----