GitHub - johnhoman/notebook-controller

Working on a remake of Kubeflow notebook controller/api-server. More specifically, I want to improve the experience for both operations teams that manage the cluster, and the users that use it.

Goals

  • Notebooks are created from a list of templates and configurations meant to work with those templates.
  • Single ownership of resources (e.g. a user owns a notebook, not a profile)
  • Dynamic RBAC rules based on notebook ownership (e.g. only the user that created the notebook can patch, update, or delete it)
  • Only modify fields that the controller cares about -- this allows things like mutating webhooks to modify resources maintained by the controller. If a user wants to add a header to a VirtualService by mutating webhook, they should be able to.

API

Templates

A template is the base of a workload, like a notebook. It contains a full Pod spec, similar to a Deployment or StatefulSet, but the template doesn't create anything.

apiVersion: jackhoman.dev/v1beta1
kind: Template
metadata:
  name: jupyter-scipy
  namespace: kubeflow
spec:
  template:
    spec:
      containers:
      - name: main
        image: kubeflownotebookswg/jupyter-scipy:v1.7.0-rc.0
        ports:
        - containerPort: 8888

The template itself does nothing. It's just a Pod spec. It's used by a Notebook to create a workload.

apiVersion: jackhoman.dev/v1beta1
kind: Notebook
metadata:
  name: jupyter-scipy
  namespace: default
spec:
  updatePolicy: Auto  # refresh from template when stopped 
  stopped: false # set this to true to stop the notebook
  templateRef:
    name: jupyter-scipy
    namespace: kubeflow
  resources:
    memory: 16Gi
    cpu: 4

For additional resource that need to be shared across templates, like configuring a database, s3 bucket, package index or other resources, use a PodDefault.

---
apiVersion: jackhoman.dev/v1beta1
kind: PodDefault
metadata:
  name: pypi.private.com
  namespace: kubeflow
spec:
    template:
      spec:
        containers:
        - name: main
          env:
          - name: PIP_INDEX_URL
            value: https://pypi.private.com
          volumeMounts:
          - mountPath: /var/run/secrets/pypi.private.com/ 
            name: pypi
        volumes:
        - name: pypi
          secret:
            secretName: pypi.private.com
---
apiVersion: jackhoman.dev/v1beta1
kind: PodDefault
metadata:
  name: spark-defaults
  namespace: kubeflow
spec:
  template:
    spec:
      containers:
        - name: main
          ports:
          - name: http-spark
            containerPort: 4040
---
apiVersion: jackhoman.dev/v1beta1
kind: Template
metadata:
  name: jupyter-scipy
  namespace: kubeflow
spec:
  template:
    spec:
      containers:
        - name: main
          image: kubeflownotebookswg/jupyter-scipy:v1.7.0-rc.0
          ports:
            - containerPort: 8888
  required:
  - name: pypi.private.com
  dependencies:
  # dependencies will be copied to the target namespace,
  # and will be owned by the revision.
  - apiVersion:  v1
    kind: Secret
    name: pypi.private.com

Rather than the single template model with a limited set of pod options, we can have many templates with different images that are configured exactly for that particular image. There's very little chance of misconfiguration this way.