├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── README.md ├── assets └── animation.gif └── values.yaml /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at nilslennartbraun@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT LICENCE 2 | 3 | Copyright (c) 2020 Nils Braun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 8 | persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 11 | Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 14 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 16 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zero-to-Codehub 2 | 3 | 4 | 5 | 6 | 7 | This repository contains a guide on how to deploy a multi-user full-blown IDE (Visual Studio Code) installation 8 | on your k8s cluster (e.g. in the public cloud) by glueing together two very nice projects: 9 | 10 | * [Zero to Jupyterhub](https://zero-to-jupyterhub.readthedocs.io/en/latest/index.html): a guide (and helm charts) for deploying jupyterhub to k8s. Jupyterhub is a multi-tenancy installation for managing [jupyter notebooks](https://jupyter.org/). 11 | * [code-server](https://github.com/cdr/code-server), an open-source ready-to-use VS Code installation (and docker image). 12 | 13 | ## Features 14 | 15 | The Codehub brings you multiple nice features: 16 | * Give developers the chance to start working on a project without any overhead or installation: a browser and credentials is all they need 17 | * Scalable, low-maintenance, multi-user installation of an IDE: every logged-in user gets its own running VS Code accessible via the browser. 18 | Optionally, you can add persistent storage, extensions, personalization, different project spaces... 19 | * Use the huge ecosystem around jupyterhub for easily integrating and configuring authentication (LDAP, OAuth, active directory, simple, ...), HTTPS, resource management and storage, user customization and so much more 20 | 21 | ## Get started 22 | 23 | If you have k8s, helm and a persistent storage provider not already set up, follow one of these [guides](https://zero-to-jupyterhub.readthedocs.io/en/latest/kubernetes/index.html) from the Zero to Jupyterhub documentation, to create a k8s cluster on GCP, AWS, Azure or other cloud provider. 24 | Also make sure, to have [helm](https://helm.sh/) installed. 25 | 26 | In principle, we just follow the remaining installation [guide](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/installation.html) to also install jupyterhub on k8s, but we use the supplied custom values file to choose the VS Code image. 27 | 28 | Add the jupyterhub helm chart: 29 | 30 | helm repo add jupyterhub https://jupyterhub.github.io/helm-chart/ 31 | helm repo update 32 | 33 | Now clone or download the [values.yaml](./values.yaml) file and replace the `proxy.secretToken` by the output of `openssl rand -hex 32`. 34 | 35 | After that, install the jupyterhub/codehub helm chart: 36 | 37 | helm upgrade --cleanup-on-fail --install codehub jupyterhub/jupyterhub --values values.yaml 38 | 39 | Wait for all pods to be running 40 | 41 | kubectl get pod 42 | 43 | You can now visit your codehub on the external address of the `proxy-public` service 44 | 45 | kubectl get service 46 | 47 | or by using a port forwarding 48 | 49 | kubectl port-forward svc/proxy-public 8000:80 50 | 51 | and then visiting http://localhost:8000. 52 | 53 | The default authenticator is a dummy authenticator which accepts any username or password combination. 54 | 55 | **Attention**: this repository is for educative purposes only. It was not tested for security thoroughly. Giving users a full IDE with root access can be a severe security problem - even when "only" running in containers. 56 | 57 | ### Stopping your server 58 | 59 | So far, there is no button to stop your server from within VS Code. 60 | However, you can visit `/hub/home` and press "Stop My Server". 61 | 62 | ## Possible customizations 63 | 64 | Behind the scenes, it is still a "normal" jupyterhub installation deployed via the battle-tested jupyterhub helm chart. 65 | Therefore, every customization und extension already implemented in jupyterhub can probably used without any changes. 66 | 67 | Examples are: 68 | * Let users choose between different "profiles" (e.g. resources, predefined images), see [here](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/customizing/user-environment.html#using-multiple-profiles-to-let-users-select-their-environment) 69 | * Customize user [resources](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/customizing/user-resources.html) and [persistent storage](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/customizing/user-storage.html) 70 | * Using a different authenticator, e.g. OAuth2 (e.g. via github), LDAP, Active Directory. See [here](https://zero-to-jupyterhub.readthedocs.io/en/latest/administrator/authentication.html) for more information. 71 | * Use HTTPS for encrypting the communication with the hub. See [here](https://zero-to-jupyterhub.readthedocs.io/en/latest/administrator/security.html#https) for more information. 72 | * Automatically remove idle servers, see [here](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/customizing/user-management.html#culling-user-pods). 73 | 74 | All the mentioned configurations can be controlled via the `values.yaml` file specified on helm chart installation. 75 | When customizing, make sure to not overwrite the already present 76 | settings needed for the VS code image. 77 | 78 | The very good [documentation](https://zero-to-jupyterhub.readthedocs.io/en/latest/index.html) on the jupyterhub k8s installation also contains valuable information on monitoring and operating. 79 | 80 | ## How does it work 81 | 82 | All components are already there - codehub just glues them together with very little glue-settings. 83 | The basis is a normal jupyterhub installation. 84 | Jupyterhub consists roughly of two components: the webfrontend (that your users will interact with) and a (reverse) proxy. 85 | Whenever users log in via the webfrontend, jupyterhub spawns a new pod which normally contains the jupyter notebook server. 86 | This is where codehub steps in: instead, a VS code instance is spawned. 87 | The address of the running VS code instance is registered with the 88 | proxy so that subsequent calls to the hub by this user will be redirected to the running VS Code directly. 89 | That's it! The changes to jupyterhub are really small - because both jupyterhub and VS Code are already very nice projects! 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /assets/animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nils-braun/codehub/baaf77d133d97a9bb34954fdb9619a3f71eeb0af/assets/animation.gif -------------------------------------------------------------------------------- /values.yaml: -------------------------------------------------------------------------------- 1 | # Configuration file for the vscode-jupyterhub helm installation 2 | # See the README.md for information on how to apply it 3 | 4 | singleuser: 5 | # Use the code-server image 6 | image: 7 | name: "codercom/code-server" 8 | tag: "3.6.2" 9 | 10 | # Mount the persistant volume claim 11 | # directly inside the home folder of 12 | # the coder user 13 | storage: 14 | homeMountPath: "/home/coder" 15 | 16 | proxy: 17 | chp: 18 | # Make sure the code server does never get to know about 19 | # the user-specific prefixes and thinks "it runs by itself" 20 | extraCommandLineFlags: 21 | - "--no-include-prefix" 22 | # secret token 23 | secretToken: # TODO: Fill with the result of `openssl rand -hex 32` 24 | 25 | hub: 26 | # The code-server needs different arguments 27 | # than the jupyter notebook image 28 | extraConfig: 29 | code_spawner.py: | 30 | from kubespawner.spawner import KubeSpawner 31 | from jupyterhub.spawner import _quote_safe 32 | 33 | class VSCodeKubeSpawner(KubeSpawner): 34 | def get_args(self): 35 | """Custom args function for the coder""" 36 | 37 | # Turn off authentication (happens via jupyterhub) 38 | args = ["--auth", "none"] 39 | # Turn off telemetry 40 | args += ["--disable-telemetry"] 41 | 42 | # set port and ip if given 43 | ip = "0.0.0.0" 44 | if self.ip: 45 | ip = _quote_safe(self.ip) 46 | 47 | port = 8888 48 | if self.port: 49 | port = self.port 50 | elif self.server and self.server.port: 51 | self.log.warning( 52 | "Setting port from user.server is deprecated as of JupyterHub 0.7." 53 | ) 54 | port = self.server.port 55 | 56 | args += ["--bind-addr", f"{ip}:{port}"] 57 | 58 | # set startup folder 59 | if self.notebook_dir: 60 | notebook_dir = self.format_string(self.notebook_dir) 61 | args += ["--user-data-dir", _quote_safe(notebook_dir)] 62 | 63 | if self.debug: 64 | args += ["-vvv"] 65 | 66 | args.extend(self.args) 67 | return args 68 | 69 | # Use the configured spawner 70 | c.JupyterHub.spawner_class = VSCodeKubeSpawner 71 | 72 | code_settings.py: | 73 | # The working dir is by default set to 74 | # /home/coder in the VSCode image 75 | c.VSCodeKubeSpawner.working_dir = "/home/coder" 76 | 77 | # By default, the cmd includes the call to "jupyterhub-singleserver" 78 | # However, the docker image already comes with the correct 79 | # VSCode command to call, so we just set it to an empty string here 80 | c.VSCodeKubeSpawner.cmd = "" --------------------------------------------------------------------------------