From 61db5befd17e9ee8ae55256292d5616852781fde Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Sun, 27 Mar 2022 04:39:51 +0300 Subject: [PATCH] feat(ml-workspace): add ml-workspace (#2300) * feat(ml-workspace): add ml-workspace * root * mroe images * ci --- charts/incubator/ml-workspace/Chart.yaml | 29 ++ .../ml-workspace/ci/minimal-values.yaml | 1 + charts/incubator/ml-workspace/questions.yaml | 392 ++++++++++++++++++ .../ml-workspace/templates/common.yaml | 1 + charts/incubator/ml-workspace/values.yaml | 65 +++ docs/_static/img/appicons/ml-workspace.png | Bin 0 -> 30047 bytes docs/manual/default-ports.md | 1 + 7 files changed, 489 insertions(+) create mode 100644 charts/incubator/ml-workspace/Chart.yaml create mode 100644 charts/incubator/ml-workspace/ci/minimal-values.yaml create mode 100644 charts/incubator/ml-workspace/questions.yaml create mode 100644 charts/incubator/ml-workspace/templates/common.yaml create mode 100644 charts/incubator/ml-workspace/values.yaml create mode 100644 docs/_static/img/appicons/ml-workspace.png diff --git a/charts/incubator/ml-workspace/Chart.yaml b/charts/incubator/ml-workspace/Chart.yaml new file mode 100644 index 00000000000..25a5af3bdc6 --- /dev/null +++ b/charts/incubator/ml-workspace/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +appVersion: "10.6.2" +dependencies: +- name: common + repository: https://library-charts.truecharts.org + version: 9.1.15 +description: All-in-one web-based development environment for machine learning +home: https://github.com/truecharts/apps/tree/master/charts/stable/ml-workspace +icon: https://truecharts.org/_static/img/appicons/ml-workspace.png +keywords: +- machine +- learning +- ai +kubeVersion: '>=1.16.0-0' +maintainers: +- email: info@truecharts.org + name: TrueCharts + url: https://truecharts.org +name: ml-workspace +sources: +- https://github.com/ml-tooling/ml-workspace +- https://hub.docker.com/r/mltooling/ml-workspace +- https://hub.docker.com/r/mltooling/ml-workspace-gpu +version: 0.0.1 +annotations: + truecharts.org/catagories: | + - utility + truecharts.org/SCALE-support: "true" + truecharts.org/grade: U diff --git a/charts/incubator/ml-workspace/ci/minimal-values.yaml b/charts/incubator/ml-workspace/ci/minimal-values.yaml new file mode 100644 index 00000000000..91bcbc9405e --- /dev/null +++ b/charts/incubator/ml-workspace/ci/minimal-values.yaml @@ -0,0 +1 @@ +imageSelector: "imageMinimal" diff --git a/charts/incubator/ml-workspace/questions.yaml b/charts/incubator/ml-workspace/questions.yaml new file mode 100644 index 00000000000..af9927d00ab --- /dev/null +++ b/charts/incubator/ml-workspace/questions.yaml @@ -0,0 +1,392 @@ +# Include{groups} +portals: + open: + protocols: + - "$kubernetes-resource_configmap_portal_protocol" + host: + - "$kubernetes-resource_configmap_portal_host" + ports: + - "$kubernetes-resource_configmap_portal_port" +questions: + - variable: portal + group: "Container Image" + label: "Configure Portal Button" + schema: + type: dict + hidden: true + attrs: + - variable: enabled + label: "Enable" + description: "enable the portal button" + schema: + hidden: true + editable: false + type: boolean + default: true +# Include{global} + - variable: imageSelector + group: "Container Image" + label: "Select Image" + schema: + type: string + default: "image" + enum: + - value: "image" + description: "CPU" + - value: "imageGPU" + description: "GPU" + - value: "imageMinimal" + description: "Minimal" + - value: "imageLight" + description: "Light" + - variable: controller + group: "Controller" + label: "" + schema: + additional_attrs: true + type: dict + attrs: + - variable: advanced + label: "Show Advanced Controller Settings" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: type + description: "Please specify type of workload to deploy" + label: "(Advanced) Controller Type" + schema: + type: string + default: "deployment" + required: true + enum: + - value: "deployment" + description: "Deployment" + - value: "statefulset" + description: "Statefulset" + - value: "daemonset" + description: "Daemonset" + - variable: replicas + description: "Number of desired pod replicas" + label: "Desired Replicas" + schema: + type: int + default: 1 + required: true + - variable: strategy + description: "Please specify type of workload to deploy" + label: "(Advanced) Update Strategy" + schema: + type: string + default: "Recreate" + required: true + enum: + - value: "Recreate" + description: "Recreate: Kill existing pods before creating new ones" + - value: "RollingUpdate" + description: "RollingUpdate: Create new pods and then kill old ones" + - value: "OnDelete" + description: "(Legacy) OnDelete: ignore .spec.template changes" +# Include{controllerExpert} + - variable: secret + group: "Container Configuration" + label: "Image Secrets" + schema: + additional_attrs: true + type: dict + attrs: + - variable: WORKSPACE_AUTH_USER + label: "WORKSPACE_AUTH_USER" + description: "Basic auth user name. To enable basic auth, both the user and password need to be set. We recommend to use the AUTHENTICATE_VIA_JUPYTER for securing the workspace" + schema: + type: string + default: "" + - variable: WORKSPACE_AUTH_PASSWORD + label: "WORKSPACE_AUTH_PASSWORD" + description: "Basic auth user password. To enable basic auth, both the user and password need to be set. We recommend to use the AUTHENTICATE_VIA_JUPYTER for securing the workspace." + schema: + type: string + private: true + default: "" + - variable: AUTHENTICATE_VIA_JUPYTER + label: "AUTHENTICATE_VIA_JUPYTER" + description: "If true, all HTTP requests will be authenticated against the Jupyter server, meaning that the authentication method configured with Jupyter will be used for all other tools as well. This can be deactivated with false. Any other value will activate this authentication and are applied as token via NotebookApp.token configuration of Jupyter." + schema: + type: string + private: true + default: "false" + - variable: env + group: "Container Configuration" + label: "Image Environment" + schema: + additional_attrs: true + type: dict + attrs: + - variable: CONFIG_BACKUP_ENABLED + label: "CONFIG_BACKUP_ENABLED" + description: "Automatically backup and restore user configuration to the persisted /workspace folder, such as the .ssh, .jupyter, or .gitconfig from the users home directory." + schema: + type: boolean + default: true + - variable: SHARED_LINKS_ENABLED + label: "SHARED_LINKS_ENABLED" + description: "Enable or disable the capability to share resources via external links. This is used to enable file sharing, access to workspace-internal ports, and easy command-based SSH setup. All shared links are protected via a token. However, there are certain risks since the token cannot be easily invalidated after sharing and does not expire." + schema: + type: boolean + default: false + - variable: INCLUDE_TUTORIALS + label: "INCLUDE_TUTORIALS" + description: "If true, a selection of tutorial and introduction notebooks are added to the /workspace folder at container startup, but only if the folder is empty." + schema: + type: boolean + default: true + - variable: MAX_NUM_THREADS + label: "MAX_NUM_THREADS" + description: "The number of threads used for computations when using various common libraries (MKL, OPENBLAS, OMP, NUMBA, ...). You can also use auto to let the workspace dynamically determine the number of threads based on available CPU resources. This configuration can be overwritten by the user from within the workspace. Generally, it is good to set it at or below the number of CPUs available to the workspace." + schema: + type: string + default: "auto" + - variable: SHUTDOWN_INACTIVE_KERNELS + label: "SHUTDOWN_INACTIVE_KERNELS" + description: "Automatically shutdown inactive kernels after a given timeout (to clean up memory or GPU resources). Value can be either a timeout in seconds or set to true with a default value of 48h." + schema: + type: string + default: "false" + - variable: NOTEBOOK_ARGS + label: "NOTEBOOK_ARGS" + description: "Add and overwrite Jupyter configuration options via command line args." + schema: + type: string + default: "" +# Include{containerConfig} + + - variable: service + group: "Networking and Services" + label: "Configure Service(s)" + schema: + additional_attrs: true + type: dict + attrs: + - variable: main + label: "Main Service" + description: "The Primary service on which the healthcheck runs, often the webUI" + schema: + additional_attrs: true + type: dict + attrs: +# Include{serviceSelector} + - variable: main + label: "Main Service Port Configuration" + schema: + additional_attrs: true + type: dict + attrs: + - variable: port + label: "Port" + description: "This port exposes the container port on the service" + schema: + type: int + default: 10201 + required: true + - variable: advanced + label: "Show Advanced settings" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: protocol + label: "Port Type" + schema: + type: string + default: "HTTP" + enum: + - value: HTTP + description: "HTTP" + - value: "HTTPS" + description: "HTTPS" + - value: TCP + description: "TCP" + - value: "UDP" + description: "UDP" + - variable: nodePort + label: "Node Port (Optional)" + description: "This port gets exposed to the node. Only considered when service type is NodePort, Simple or LoadBalancer" + schema: + type: int + min: 9000 + max: 65535 + - variable: targetPort + label: "Target Port" + description: "The internal(!) port on the container the Application runs on" + schema: + type: int + default: 10201 + + - variable: serviceexpert + group: "Networking and Services" + label: "Show Expert Config" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: hostNetwork + group: "Networking and Services" + label: "Host-Networking (Complicated)" + schema: + type: boolean + default: false + +# Include{serviceExpert} + +# Include{serviceList} + + - variable: persistence + label: "Integrated Persistent Storage" + description: "Integrated Persistent Storage" + group: "Storage and Persistence" + schema: + additional_attrs: true + type: dict + attrs: + - variable: workspace + label: "App Workspace Storage" + description: "Stores the Application Workspace." + schema: + additional_attrs: true + type: dict + attrs: + - variable: type + label: "Type of Storage" + description: "Sets the persistence type, Anything other than PVC could break rollback!" + schema: + type: string + default: "simplePVC" + enum: + - value: "simplePVC" + description: "PVC (simple)" + - value: "simpleHP" + description: "HostPath (simple)" + - value: "emptyDir" + description: "emptyDir" + - value: "pvc" + description: "pvc" + - value: "hostPath" + description: "hostPath" +# Include{persistenceBasic} + - variable: hostPath + label: "hostPath" + description: "Path inside the container the storage is mounted" + schema: + show_if: [["type", "=", "hostPath"]] + type: hostpath + - variable: medium + label: "EmptyDir Medium" + schema: + show_if: [["type", "=", "emptyDir"]] + type: string + default: "" + enum: + - value: "" + description: "Default" + - value: "Memory" + description: "Memory" +# Include{persistenceAdvanced} + +# Include{persistenceList} + + - variable: ingress + label: "" + group: "Ingress" + schema: + additional_attrs: true + type: dict + attrs: + - variable: main + label: "Main Ingress" + schema: + additional_attrs: true + type: dict + attrs: +# Include{ingressDefault} + +# Include{ingressTLS} + +# Include{ingressTraefik} + +# Include{ingressExpert} + +# Include{ingressList} + +# Include{security} + + - variable: advancedSecurity + label: "Show Advanced Security Settings" + group: "Security and Permissions" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: securityContext + label: "Security Context" + schema: + additional_attrs: true + type: dict + attrs: + - variable: privileged + label: "Privileged mode" + schema: + type: boolean + default: false + - variable: readOnlyRootFilesystem + label: "ReadOnly Root Filesystem" + schema: + type: boolean + default: false + - variable: allowPrivilegeEscalation + label: "Allow Privilege Escalation" + schema: + type: boolean + default: false + - variable: runAsNonRoot + label: "runAsNonRoot" + schema: + type: boolean + default: false +# Include{securityContextAdvanced} + + - variable: podSecurityContext + group: "Security and Permissions" + label: "Pod Security Context" + schema: + additional_attrs: true + type: dict + attrs: + - variable: runAsUser + label: "runAsUser" + description: "The UserID of the user running the application" + schema: + type: int + default: 0 + - variable: runAsGroup + label: "runAsGroup" + description: The groupID this App of the user running the application" + schema: + type: int + default: 0 + - variable: fsGroup + label: "fsGroup" + description: "The group that should own ALL storage." + schema: + type: int + default: 568 +# Include{podSecurityContextAdvanced} + +# Include{resources} + +# Include{advanced} + +# Include{addons} diff --git a/charts/incubator/ml-workspace/templates/common.yaml b/charts/incubator/ml-workspace/templates/common.yaml new file mode 100644 index 00000000000..a6613c2ce21 --- /dev/null +++ b/charts/incubator/ml-workspace/templates/common.yaml @@ -0,0 +1 @@ +{{ include "common.all" . }} diff --git a/charts/incubator/ml-workspace/values.yaml b/charts/incubator/ml-workspace/values.yaml new file mode 100644 index 00000000000..011ff1f484a --- /dev/null +++ b/charts/incubator/ml-workspace/values.yaml @@ -0,0 +1,65 @@ +image: + repository: mltooling/ml-workspace + tag: 0.13.2@sha256:5dfc8928059eb9d6d2bc33d7947e99b6bb38c2beaa40029afb73596a9c08c134 + pullPolicy: IfNotPresent + +imageGPU: + repository: mltooling/ml-workspace-gpu + pullPolicy: IfNotPresent + tag: 0.13.2@sha256:ca83f64f4339344c96bb6491234008b972c1e64a1c1ef41522b8da601dfceb1e + +imageMinimal: + repository: mltooling/ml-workspace-minimal + pullPolicy: IfNotPresent + tag: 0.13.2@sha256:94206eadc4bcfd1d4af4c598f767da176ad898592b9dc54bf62ddd2d9f6d1be6 + +imageLight: + repository: mltooling/ml-workspace-light + pullPolicy: IfNotPresent + tag: 0.13.2@sha256:cc0e1441702b49927a14d902c4530fa15ce9ad6796a61e41eaebf2e72cf77bc9 + +imageSelector: "image" + +securityContext: + readOnlyRootFilesystem: false + runAsNonRoot: false + +podSecurityContext: + runAsUser: 0 + runAsGroup: 0 + +secret: + WORKSPACE_AUTH_USER: "admin" + WORKSPACE_AUTH_PASSWORD: "password" + # true, false, or a token + AUTHENTICATE_VIA_JUPYTER: "mytoken" + +env: + WORKSPACE_BASE_URL: "/" + WORKSPACE_SSL_ENABLED: false + WORKSPACE_PORT: "{{ .Values.service.main.ports.main.port }}" + # User Defined + CONFIG_BACKUP_ENABLED: true + SHARED_LINKS_ENABLED: false + INCLUDE_TUTORIALS: true + MAX_NUM_THREADS: "auto" + # Jupyter Config + # true, false or timeout in seconds + SHUTDOWN_INACTIVE_KERNELS: "false" + NOTEBOOK_ARGS: "" + +service: + main: + ports: + main: + port: 10201 + +persistence: + workspace: + enabled: true + mountPath: "/workspace" + shm: + enabled: true + mountPath: "/dev/shm" + type: "emptyDir" + medium: "Memory" diff --git a/docs/_static/img/appicons/ml-workspace.png b/docs/_static/img/appicons/ml-workspace.png new file mode 100644 index 0000000000000000000000000000000000000000..a582f3a3e6b6baeab52507c123f417b8d2f04165 GIT binary patch literal 30047 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 G@c#j=?+up# literal 0 HcmV?d00001 diff --git a/docs/manual/default-ports.md b/docs/manual/default-ports.md index ea081dc4110..a3c81e3325a 100644 --- a/docs/manual/default-ports.md +++ b/docs/manual/default-ports.md @@ -357,6 +357,7 @@ These defaults can of course be changed, but as we guarantee "sane, working defa | kimai | main | main | 10198 | TCP | | | filerun | main | main | 10199 | TCP | | | double-take | main | main | 10200 | TCP | | +| ml-workspace | main | main | 10201 | TCP | | | storj-node | main | main | 14002 | TCP | | | satisfactory | beacon | beacon | 15000 | UDP | | | satisfactory | query | query | 15777 | UDP | |