From 14a1a876848bc8fbd4118e687fed318861bd0268 Mon Sep 17 00:00:00 2001 From: eskild <42120229+iameskild@users.noreply.github.com> Date: Fri, 15 Apr 2022 08:26:19 -0700 Subject: [PATCH] Add auth to argo (#1249) * Mdformat tables (#1186) * Add mdformat-tables * Run mdformat on all files * mdformat only docs folder (restore .github md files) * Fix some vale, restore README/RELEASE * [ImgBot] Optimize images (#1187) /docs/source/images/dev_postman_for_keycloak.png -- 298.79kb -> 270.60kb (9.44%) Signed-off-by: ImgBotApp Co-authored-by: ImgBotApp * Bump conda-store version to 0.3.14 (#1192) * Allow terraform init to upgrade providers within version specification (#1194) * Allow terraform init to upgrade providers within version specification Closes #1193 * Black formatting * Adding missing __init__ files (#1196) * Adding missing __init__ files Closes #1195 * Explicitely using qhub for package * Give hint on what to include * Release 0.3.15 for Conda-Store (#1205) * Profilegroups (#1203) * Fix in case groups is None * access all/keycloak/yaml * jupyterlabproflies mapper * Keycloak profiles working * ignore changes to keycloak group attributes * qhub upgrade for jupyterlab profiles * docs for jupyterlabprofiles * Renamed to jupyterlab_profiles * Render `.gitignore`, black py files (#1206) * Render .gitignore * Render clean .gitignore * Add unit test * Upgrade black * Upgrade black * black format * exclude qhub/_version.py from black * Black what needs blackening * Fix * Fix * Update qhub-dask version (#1224) * Fix env doc links and add corresponding tests (#1216) * Fix env doc links and add corresponding tests * fix broken image link * fix black formatting * map(any) -> any (#1213) * Update release notes - justification for changes in `v0.4.0` (#1178) * Update release notes * Remove ref to cookiecutter * Update link-checker version * Fix * Use lycee link-checker instead * Remove lycee, update md config.json * Revert version * Release notes cleanup * Rewording * Add to vocab * Fix table * Add explicit warning about release * Update README.md Fixed some syntax/grammar issues. * Minor updates Co-authored-by: Christopher Ostrouchov Co-authored-by: Shannon * Merge spawner and profile env vars * Support for pinning the IP address of the load balancer via terraform overrides (#1235) * Suport adding load balancer annotations and ip via terraform overrides * add documentation for terraform overrides * make terraform overrides being able to override any variable * Bump moment from 2.29.1 to 2.29.2 in /tests_e2e (#1241) Bumps [moment](https://github.com/moment/moment) from 2.29.1 to 2.29.2. - [Release notes](https://github.com/moment/moment/releases) - [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md) - [Commits](https://github.com/moment/moment/compare/2.29.1...2.29.2) --- updated-dependencies: - dependency-name: moment dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update cdsdashboards to 0.6.1, Voila to 0.3.5 (#1240) * Update cdsdashboards to 0.6.1 * voila v0.3.5 * Bump minimist from 1.2.5 to 1.2.6 in /tests_e2e (#1208) Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6. - [Release notes](https://github.com/substack/minimist/releases) - [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6) --- updated-dependencies: - dependency-name: minimist dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * output check fix (#1244) Co-authored-by: Adam-D-Lewis <> * Add auth to argo * add argo_workflows value to qhub init command * update black version * update black in setup.cfg Co-authored-by: Dan Lester Co-authored-by: imgbot[bot] <31301654+imgbot[bot]@users.noreply.github.com> Co-authored-by: ImgBotApp Co-authored-by: Christopher Ostrouchov Co-authored-by: Amit Kumar Co-authored-by: Shannon Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Adam Lewis <23342526+Adam-D-Lewis@users.noreply.github.com> Co-authored-by: Adam-D-Lewis <> --- .github/workflows/markdown.links.config.json | 7 +- .github/workflows/test.yaml | 4 +- .gitignore | 2 +- .pre-commit-config.yaml | 3 + CONTRIBUTING.md | 108 ++-- README.md | 84 +-- RELEASE.md | 496 ++++++++++-------- docs/ext/substitute.py | 8 +- docs/index.md | 4 +- docs/source/admin_guide/awss3curl.md | 13 +- docs/source/admin_guide/backup.md | 38 +- docs/source/admin_guide/breaking-upgrade.md | 37 +- docs/source/admin_guide/clearml.md | 3 +- docs/source/admin_guide/cost.md | 63 ++- docs/source/admin_guide/custom-helm-charts.md | 3 +- docs/source/admin_guide/faq.md | 18 +- docs/source/admin_guide/gpu.md | 61 +-- docs/source/admin_guide/jupyterhub.md | 12 +- docs/source/admin_guide/keycloak.md | 9 +- docs/source/admin_guide/monitoring.md | 6 +- .../admin_guide/preemptible-spot-instances.md | 4 +- docs/source/admin_guide/prefect.md | 32 +- docs/source/admin_guide/system_maintenance.md | 58 +- docs/source/admin_guide/traefik.md | 20 +- docs/source/admin_guide/troubleshooting.md | 40 +- docs/source/admin_guide/upgrade.md | 23 +- docs/source/dev_guide/architecture.md | 97 ++-- docs/source/dev_guide/changelog.md | 2 +- docs/source/dev_guide/contribution.md | 13 +- docs/source/dev_guide/keycloak.md | 30 +- docs/source/dev_guide/logo.md | 14 +- docs/source/dev_guide/minikube.md | 97 ++-- docs/source/dev_guide/release.md | 63 ++- docs/source/dev_guide/testing.md | 67 ++- .../images/dev_postman_for_keycloak.png | Bin 305966 -> 277092 bytes docs/source/installation/configuration.md | 443 ++++++++-------- docs/source/installation/existing.md | 135 +++-- docs/source/installation/index.md | 1 - docs/source/installation/installation.md | 11 +- docs/source/installation/management.md | 20 +- docs/source/installation/setup.md | 176 ++++--- docs/source/installation/usage.md | 115 ++-- docs/source/introduction/index.md | 67 +-- docs/source/introduction/qhub-101.md | 44 +- docs/source/user_guide/code_server.md | 13 +- docs/source/user_guide/dashboard.md | 47 +- docs/source/user_guide/dask_gateway.md | 38 +- docs/source/user_guide/environments.md | 36 +- docs/source/user_guide/experimental.md | 2 - docs/source/user_guide/faq.md | 54 +- docs/source/user_guide/getting_started.md | 62 +-- docs/source/user_guide/idle_culler.md | 26 +- docs/source/user_guide/ssh.md | 35 +- docs/source/user_guide/training.md | 4 +- docs/source/user_guide/troubleshooting.md | 26 +- environment-dev.yaml | 2 +- qhub/initialize.py | 12 +- qhub/provider/cicd/__init__.py | 0 qhub/provider/terraform.py | 7 +- qhub/render.py | 23 + qhub/schema.py | 26 +- qhub/stages/__init__.py | 0 qhub/stages/input_vars.py | 1 + qhub/template/image/README.md | 5 +- .../image/jupyterhub/environment.yaml | 2 +- .../image/jupyterlab/environment.yaml | 2 +- .../stages/04-kubernetes-ingress/main.tf | 10 +- .../modules/kubernetes/ingress/main.tf | 5 +- .../modules/kubernetes/ingress/variables.tf | 15 + .../stages/04-kubernetes-ingress/variables.tf | 17 + .../main.tf | 6 + .../07-kubernetes-services/argo-workflows.tf | 2 +- .../07-kubernetes-services/conda-store.tf | 2 +- .../services/argo-workflows/main.tf | 54 +- .../services/argo-workflows/variables.tf | 5 + .../services/clearml/chart/README.md | 135 ++--- .../conda-store/config/conda_store_config.py | 4 +- .../files/examples/dashboard_plotly.py | 35 +- .../files/examples/dashboard_streamlit.py | 9 +- .../jupyterhub/files/jupyterhub/02-spawner.py | 2 +- .../files/jupyterhub/03-profiles.py | 53 +- .../kubernetes/services/jupyterhub/main.tf | 1 + .../services/jupyterhub/variables.tf | 2 +- .../services/keycloak-client/main.tf | 16 + .../services/keycloak-client/variables.tf | 6 + qhub/upgrade.py | 26 + qhub/utils.py | 11 +- setup.cfg | 6 +- tests/scripts/minikube-loadbalancer-ip.py | 6 +- tests/test_links.py | 21 + tests/test_render.py | 32 +- tests/test_upgrade.py | 2 +- tests/vale/styles/vocab.txt | 28 +- tests_deployment/test_jupyterhub_ssh.py | 1 - tests_e2e/package-lock.json | 24 +- 95 files changed, 1971 insertions(+), 1539 deletions(-) create mode 100644 qhub/provider/cicd/__init__.py create mode 100644 qhub/stages/__init__.py create mode 100644 tests/test_links.py diff --git a/.github/workflows/markdown.links.config.json b/.github/workflows/markdown.links.config.json index 96da28778..fd37a7985 100644 --- a/.github/workflows/markdown.links.config.json +++ b/.github/workflows/markdown.links.config.json @@ -21,5 +21,10 @@ { "pattern": "https://cloud.google.com" } - ] + ], + "timeout": "20s", + "retryOn429": true, + "retryCount": 5, + "fallbackRetryDelay": "30s", + "aliveStatusCodes": [200, 206] } diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index acc0d369f..d4b6109cf 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -46,8 +46,8 @@ jobs: - name: Black Formatting run: | black --version - black qhub --diff - black --check qhub + black qhub --diff --exclude "qhub/_version.py" + black --check qhub --exclude "qhub/_version.py" - name: Flake8 Formatting run: | flake8 --version diff --git a/.gitignore b/.gitignore index 9afe1b610..777817b9b 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,4 @@ qhub-config.yaml .vscode/ # Ignore Vale -vale +./vale diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a71a63197..800cc196a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,6 +34,7 @@ repos: rev: 0.7.13 hooks: - id: mdformat + files: ^docs/ name: mdformat description: "CommonMark compliant Markdown formatter" entry: mdformat @@ -44,3 +45,5 @@ repos: language_version: python3 types: [markdown] minimum_pre_commit_version: '1.0.0' + additional_dependencies: + - mdformat-tables diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bcf29c2b3..df715de1e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,9 @@ # Contributing to QHub -:sparkles: :raised_hands: Welcome to the QHub repository! :sparkles: :raised_hands: +:sparkles: :raised_hands: Welcome to the QHub repository! :sparkles: :raised_hands: -Everyone is welcome to contribute, and we value everybody's contribution. Code is not the only way to help the community. -Your choices aren't limited to programming; as you can see below, there are many areas where we need **your** help. -Answering questions, helping others, reaching out and improving the documentation is immensely valuable to the community. +Everyone is welcome to contribute, and we value everybody's contribution. Code is not the only way to help the community. Your choices aren't limited to programming; as you can see +below, there are many areas where we need **your** help. Answering questions, helping others, reaching out and improving the documentation is immensely valuable to the community. Whichever way you choose to contribute, please be mindful of respecting our code of conduct. @@ -27,46 +26,44 @@ This document will help you through your journey of open source. Here, you'll ge ## 🏷 Where to start: issues -Before you open a new issue, please check the [open issues][QHub-issues]. See if the issue has already been reported or if your idea has already been discussed. -If so, it's often better to leave a comment on a current issue rather than opening a new one. Old issues also often include helpful tips and solutions to common problems. +Before you open a new issue, please check the [open issues][qhub-issues]. See if the issue has already been reported or if your idea has already been discussed. If so, it's often +better to leave a comment on a current issue rather than opening a new one. Old issues also often include helpful tips and solutions to common problems. -If you are looking for specific help with QHub or its configuration, check our [Github discussions][QHub-qa]. +If you are looking for specific help with QHub or its configuration, check our [Github discussions][qhub-qa]. ### Submitting issues -When opening an issue, give it a **descriptive title** and provide as much information as possible. -Our [issue templates][QHub-templates] help you remember the most important details to include. +When opening an issue, give it a **descriptive title** and provide as much information as possible. Our [issue templates][qhub-templates] help you remember the most important +details to include. There are three issues templates to choose from: 1. **Bug Report**: With this template, create an issue report that can help others fix something currently broken. 2. **Documentation**: Use this template to provide feedback on our documentation or suggest additions and improvements. -3. **Feature request**: Is there anything to make the community work better? Have you spotted something missing in QHub? - Use this template to share your feature ideas with the QHub team. +3. **Feature request**: Is there anything to make the community work better? Have you spotted something missing in QHub? Use this template to share your feature ideas with the QHub + team. A few more tips: -- **Describing your issue**: Try to provide as many details as possible. What exactly goes wrong? How is it failing? Is there an error? - "XY doesn't work" usually isn't that helpful for tracking down problems. Always remember to include the code you ran, and if possible, - extract only the relevant parts, and don't dump your entire script. - This will make it easier for us to reproduce the error. Screenshots are also great ways to demonstrate errors or unexpected behaviours. +- **Describing your issue**: Try to provide as many details as possible. What exactly goes wrong? How is it failing? Is there an error? "XY doesn't work" usually isn't that helpful + for tracking down problems. Always remember to include the code you ran, and if possible, extract only the relevant parts, and don't dump your entire script. This will make it + easier for us to reproduce the error. Screenshots are also great ways to demonstrate errors or unexpected behaviours. -- **Sharing long blocks of code or logs**: If you need to include extended code, logs or tracebacks, you can wrap them in `
and
`. - This collapses the content, so it only becomes visible on click, making it easier to read and follow. +- **Sharing long blocks of code or logs**: If you need to include extended code, logs or tracebacks, you can wrap them in `
and
`. This collapses the content, so + it only becomes visible on click, making it easier to read and follow. - **Suggesting a new feature:** When suggesting a new feature, please also add details on how this new feature might impact the users' and developers' workflow. ### Issue labels -Check our [labels page][QHub-labels] for an overview of the system we use to tag our issues and pull requests. +Check our [labels page][qhub-labels] for an overview of the system we use to tag our issues and pull requests. ## :computer: Contributing to the codebase -You don't have to be a Python or Kubernetes pro to contribute, and we're happy to help you get started. -If you're new to QHub, an excellent place to start are the issues marked with the [type: good first issue](https://github.com/Quansight/QHub/labels/type%3A%20good%20first%20issue) label, -which we use to tag bugs and feature requests that require low-effort (i.e. low entry-barrier or little in-depth knowledge needed) and self-contained. -If you've decided to take on one of these problems and you're making good progress, don't forget to add a quick comment to the issue to assign this to yourself. -You can also use the issue to ask questions or share your work in progress. +You don't have to be a Python or Kubernetes pro to contribute, and we're happy to help you get started. If you're new to QHub, an excellent place to start are the issues marked +with the [type: good first issue](https://github.com/Quansight/QHub/labels/type%3A%20good%20first%20issue) label, which we use to tag bugs and feature requests that require +low-effort (i.e. low entry-barrier or little in-depth knowledge needed) and self-contained. If you've decided to take on one of these problems and you're making good progress, +don't forget to add a quick comment to the issue to assign this to yourself. You can also use the issue to ask questions or share your work in progress. ### Development process - short summary @@ -74,7 +71,8 @@ Never made an open-source contribution before? Wondering how contributions work #### If you are a first-time contributor -1. Go to the [QHub repository][QHub-repo] and click the `fork` button on the top-right corner to create your own copy of the project. +1. Go to the [QHub repository][qhub-repo] and click the `fork` button on the top-right corner to create your own copy of the project. + 2. Clone the project to your local computer: ```bash @@ -101,6 +99,7 @@ Now using the command `git remote -v` will show two remote repositories: #### Develop your contribution 1. Find an issue you are interested in addressing or a feature you would like to address. + 2. Pull the latest changes from upstream ```bash @@ -116,58 +115,59 @@ Now using the command `git remote -v` will show two remote repositories: # this is an alternative to the git checkout -b feature/ command ``` -4. Commit locally as you progress (`git add` and `git commit`). Use an adequately formatted commit message, - write tests that fail before your change and pass afterwards, run all the tests locally. Be sure to document any changed behaviour in docstrings. +4. Commit locally as you progress (`git add` and `git commit`). Use an adequately formatted commit message, write tests that fail before your change and pass afterwards, run all + the tests locally. Be sure to document any changed behaviour in docstrings. #### Submitting your contribution 1. Push your changes back to your fork on GitHub: - ```bash - git push origin feature/ - ``` + ```bash + git push origin feature/ + ``` 2. Enter your GitHub username and password (repeat contributors or advanced users can remove this step by connecting to GitHub with SSH). -3. Go to GitHub. The new branch will show a green **Pull Request** button. Make sure the title and message are clear, concise, and self-explanatory. - Then click the button to submit it. -:warning: - If your commit introduces a new feature or changes functionality, please -ensure you first create an open Pull Request on our repo with `WIP` (work in progress) in the title and marked as draft, explaining what you want to do. -That way we can discuss it -to be sure it makes sense for QHub. Or start by creating an issue and indicate that you would be interested in solving the problem yourself. -This is generally not necessary for bug fixes, documentation updates, etc. However, if you do not get any reaction, do feel free to ask for a review. +3. Go to GitHub. The new branch will show a green **Pull Request** button. Make sure the title and message are clear, concise, and self-explanatory. Then click the button to submit + it. + +:warning: - If your commit introduces a new feature or changes functionality, please ensure you first create an open Pull Request on our repo with `WIP` (work in progress) in the +title and marked as draft, explaining what you want to do. That way we can discuss it to be sure it makes sense for QHub. Or start by creating an issue and indicate that you would +be interested in solving the problem yourself. This is generally not necessary for bug fixes, documentation updates, etc. However, if you do not get any reaction, do feel free to +ask for a review. #### Review process -Reviewers (the other developers and interested community members) will write inline and/or general comments on your Pull Request (PR) to help you improve its implementation, documentation and style. -Every developer working on the project has their code reviewed, and we've come to see it as a friendly conversation from which we all learn and the overall code quality benefits. -Therefore, please don't let the review discourage you from contributing: its only aim is to improve the quality of the project, not to criticize -(we are, after all, very grateful for the time you're donating!). +Reviewers (the other developers and interested community members) will write inline and/or general comments on your Pull Request (PR) to help you improve its implementation, +documentation and style. Every developer working on the project has their code reviewed, and we've come to see it as a friendly conversation from which we all learn and the overall +code quality benefits. Therefore, please don't let the review discourage you from contributing: its only aim is to improve the quality of the project, not to criticize (we are, +after all, very grateful for the time you're donating!). -To update your PR, make your changes on your local repository, commit, run tests, and only if they succeed, push to your fork. -The PR will update automatically as soon as those changes are pushed up (to the same branch as before). -If you have no idea how to fix the test failures, you may push your changes anyway and ask for help in a PR comment. +To update your PR, make your changes on your local repository, commit, run tests, and only if they succeed, push to your fork. The PR will update automatically as soon as those +changes are pushed up (to the same branch as before). If you have no idea how to fix the test failures, you may push your changes anyway and ask for help in a PR comment. -Various continuous integration (CI) pipelines are triggered after each PR update to build artefacts, run unit tests, and check the coding style of your branch. -The CI tests must pass before your PR can be merged. If CI fails, you can find why by clicking on the "failed" icon (red cross) and inspecting the build and test log. -To avoid overuse and waste of this resource, test your work locally before committing. +Various continuous integration (CI) pipelines are triggered after each PR update to build artefacts, run unit tests, and check the coding style of your branch. The CI tests must +pass before your PR can be merged. If CI fails, you can find why by clicking on the "failed" icon (red cross) and inspecting the build and test log. To avoid overuse and waste of +this resource, test your work locally before committing. Before merging, a PR must be approved by at least one core team member. Approval means the core team member has carefully reviewed the changes, and the PR is ready for merging. #### Document changes -Beyond changes to a functions docstring and possible description in the general documentation, if your change introduces any user-facing modifications, they may need to be mentioned in the release notes. +Beyond changes to a functions docstring and possible description in the general documentation, if your change introduces any user-facing modifications, they may need to be +mentioned in the release notes. #### Cross referencing issues -If the PR relates to any issues, you can add the text `xref gh-xxxx` where `xxxx` is the issue number to GitHub comments. Likewise, if the PR solves an issue, replace the `xref` with `closes`, `fixes` or any other flavours [github accepts](https://help.github.com/en/articles/closing-issues-using-keywords). +If the PR relates to any issues, you can add the text `xref gh-xxxx` where `xxxx` is the issue number to GitHub comments. Likewise, if the PR solves an issue, replace the `xref` +with `closes`, `fixes` or any other flavours [github accepts](https://help.github.com/en/articles/closing-issues-using-keywords). In the source code, be sure to preface any issue or PR reference with gh-xxxx. -[QHub-repo]: https://github.com/Quansight/QHub/ -[QHub-issues]: https://github.com/Quansight/QHub/issues -[QHub-labels]: https://github.com/Quansight/QHub/labels -[QHub-templates]: https://github.com/Quansight/QHub/issues/new/choose -[QHub-qa]: https://github.com/Quansight/QHub/discussions/categories/q-a -[issue-template]: https://github.com/Quansight/QHub/blob/main/ISSUE_TEMPLATE.md + +[qhub-issues]: https://github.com/Quansight/QHub/issues +[qhub-labels]: https://github.com/Quansight/QHub/labels +[qhub-qa]: https://github.com/Quansight/QHub/discussions/categories/q-a +[qhub-repo]: https://github.com/Quansight/QHub/ +[qhub-templates]: https://github.com/Quansight/QHub/issues/new/choose diff --git a/README.md b/README.md index e2dcf8e73..07178a558 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,15 @@
-Information | Links | -------------|------------| -Project | [![License](https://img.shields.io/badge/License-BSD%203--Clause-gray.svg?colorA=2D2A56&colorB=5936D9&style=flat.svg)](https://opensource.org/licenses/BSD-3-Clause) [![QHUb documentation](https://img.shields.io/badge/📖%20Read-the%20docs-gray.svg?colorA=2D2A56&colorB=5936D9&style=flat.svg)](https://docs.qhub.dev/en/stable/) [![PyPI version](https://badge.fury.io/py/qhub.svg)](https://badge.fury.io/py/qhub) | -Community | [![GH discussions](https://img.shields.io/badge/💬%20-Participate%20in%20discussions-gray.svg?colorA=2D2A56&colorB=5936D9&style=flat.svg)](https://github.com/Quansight/qhub/discussions) [![Open an issue](https://img.shields.io/badge/📝%20Open-an%20issue-gray.svg?colorA=2D2A56&colorB=5936D9&style=flat.svg)](https://github.com/Quansight/qhub/issues/new/choose) | -CI | [![Build Docker Images](https://github.com/Quansight/qhub/actions/workflows/image.yaml/badge.svg)](https://github.com/Quansight/qhub/actions/workflows/image.yaml) [![Kubernetes Tests](https://github.com/Quansight/qhub/actions/workflows/kubernetes_test.yaml/badge.svg)](https://github.com/Quansight/qhub/actions/workflows/kubernetes_test.yaml) [![Tests](https://github.com/Quansight/qhub/actions/workflows/test.yaml/badge.svg)](https://github.com/Quansight/qhub/actions/workflows/test.yaml) [![Documentation linter](https://github.com/Quansight/qhub/actions/workflows/docs.yml/badge.svg)](https://github.com/Quansight/qhub/actions/workflows/docs.yml) | +| Information | Links | +| :---------- | :-----| +| Project | [![License](https://img.shields.io/badge/License-BSD%203--Clause-gray.svg?colorA=2D2A56&colorB=5936D9&style=flat.svg)](https://opensource.org/licenses/BSD-3-Clause) [![QHUb documentation](https://img.shields.io/badge/%F0%9F%93%96%20Read-the%20docs-gray.svg?colorA=2D2A56&colorB=5936D9&style=flat.svg)](https://docs.qhub.dev/en/stable/) [![PyPI version](https://badge.fury.io/py/qhub.svg)](https://badge.fury.io/py/qhub) | +| Community | [![GH discussions](https://img.shields.io/badge/%F0%9F%92%AC%20-Participate%20in%20discussions-gray.svg?colorA=2D2A56&colorB=5936D9&style=flat.svg)](https://github.com/Quansight/qhub/discussions) [![Open an issue](https://img.shields.io/badge/%F0%9F%93%9D%20Open-an%20issue-gray.svg?colorA=2D2A56&colorB=5936D9&style=flat.svg)](https://github.com/Quansight/qhub/issues/new/choose) | +| CI | [![Build Docker Images](https://github.com/Quansight/qhub/actions/workflows/image.yaml/badge.svg)](https://github.com/Quansight/qhub/actions/workflows/image.yaml) [![Kubernetes Tests](https://github.com/Quansight/qhub/actions/workflows/kubernetes_test.yaml/badge.svg)](https://github.com/Quansight/qhub/actions/workflows/kubernetes_test.yaml) [![Tests](https://github.com/Quansight/qhub/actions/workflows/test.yaml/badge.svg)](https://github.com/Quansight/qhub/actions/workflows/test.yaml) [![Documentation linter](https://github.com/Quansight/qhub/actions/workflows/docs.yml/badge.svg)](https://github.com/Quansight/qhub/actions/workflows/docs.yml) | ## Table of contents +- [Table of contents](#table-of-contents) - [QHub HPC](#qhub-hpc) - [QHub](#qhub) - [:cloud: Cloud Providers](#cloud-cloud-providers) @@ -22,14 +23,14 @@ CI | [![Build Docker Images](https://github.com/Quansight/qhub/actions/workflows - [:book: Code of Conduct](#book-code-of-conduct) - [:gear: Installing the Development version of QHub](#gear-installing-the-development-version-of-qhub) - [:raised_hands: Contributions](#raised_hands-contributions) +- [Ongoing Support](#ongoing-support) - [License](#license) -Automated data science platform. From [JupyterHub](https://jupyter.org/hub "Multi-user version of the Notebook") to -Cloud environments with [Dask Gateway](https://docs.dask.org/ "Parallel computing in Python"). +Automated data science platform. From [JupyterHub](https://jupyter.org/hub "Multi-user version of the Notebook") to Cloud environments with +[Dask Gateway](https://docs.dask.org/ "Parallel computing in Python"). -QHub is an open source tool that enables users to build and maintain -cost-effective and scalable compute/data science platforms on [HPC](#qhub-hpc) or on [Kubernetes](#qhub) with minimal DevOps -experience. +QHub is an open source tool that enables users to build and maintain cost-effective and scalable compute/data science platforms on [HPC](#qhub-hpc) or on [Kubernetes](#qhub) with +minimal DevOps experience. **This repository details the [QHub](https://qhub.dev/ "Official QHub docs") (Kubernetes) version.** @@ -44,21 +45,19 @@ Version of QHub based on OpenHPC. ## QHub The Kubernetes version of QHub is built using [Terraform](https://www.terraform.io/), [Helm](https://helm.sh/), and -[GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions). -Terraform handles the build, change, and versioning of the infrastructure. Helm helps to define, install, and manage -[Kubernetes](https://kubernetes.io/ "Automated container deployment, scaling, and management"). GitHub -Actions is used to automatically create commits when the configuration file (`qhub-config.yaml`) is rendered, as well as -to kick off the deployment action. +[GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions). Terraform handles the build, change, and versioning of the infrastructure. Helm helps to define, install, +and manage [Kubernetes](https://kubernetes.io/ "Automated container deployment, scaling, and management"). GitHub Actions is used to automatically create commits when the +configuration file (`qhub-config.yaml`) is rendered, as well as to kick off the deployment action. -QHub aims to abstract all these complexities for its users. Hence, it is not necessary to know any of the above mentioned -technologies to have your project successfully deployed. +QHub aims to abstract all these complexities for its users. Hence, it is not necessary to know any of the above mentioned technologies to have your project successfully deployed. -> TLDR: -> If you know GitHub and feel comfortable generating and using API keys, you should have all it takes to deploy -> and maintain your system without the need for a dedicated DevOps team. No need to learn Kubernetes, Terraform, or Helm. +> TLDR: If you know GitHub and feel comfortable generating and using API keys, you should have all it takes to deploy and maintain your system without the need for a dedicated +> DevOps team. No need to learn Kubernetes, Terraform, or Helm. ### :cloud: Cloud Providers -QHub offers out-of-the-box support for [Digital Ocean](https://www.digitalocean.com/), Amazon [AWS](https://aws.amazon.com/), [GCP](https://cloud.google.com/ "Google Cloud Provider"), and Microsoft [Azure](https://azure.microsoft.com/en-us/). + +QHub offers out-of-the-box support for [Digital Ocean](https://www.digitalocean.com/), Amazon [AWS](https://aws.amazon.com/), +[GCP](https://cloud.google.com/ "Google Cloud Provider"), and Microsoft [Azure](https://azure.microsoft.com/en-us/). ![High-level illustration of QHub architecture](docs/source/images/qhub-cloud_architecture.png) @@ -68,28 +67,28 @@ For more details, check out the release [blog post](https://www.quansight.com/po ### Pre-requisites -* QHub is supported by macOS and Linux operating systems (Windows is **NOT** currently supported). -* Compatible with Python 3.7+. New to Python? We recommend using [Anaconda](https://www.anaconda.com/products/individual). -* Adoption of virtual environments ([`conda`](https://docs.conda.io/en/latest/), [`pipenv`](https://github.com/pypa/pipenv) or [`venv`](https://docs.python.org/3/library/venv.html)) is also encouraged. +- QHub is supported by macOS and Linux operating systems (Windows is **NOT** currently supported). +- Compatible with Python 3.7+. New to Python? We recommend using [Anaconda](https://www.anaconda.com/products/individual). +- Adoption of virtual environments ([`conda`](https://docs.conda.io/en/latest/), [`pipenv`](https://github.com/pypa/pipenv) or + [`venv`](https://docs.python.org/3/library/venv.html)) is also encouraged. ### Install QHub To install QHub type the following commands in your command line: -* Install using `conda`: +- Install using `conda`: ```bash conda install -c conda-forge qhub ``` -* Install using `pip`: +- Install using `pip`: - ```bash - pip install qhub - ``` + ```bash + pip install qhub + ``` -Once finished, you can check QHub's version (and additional CLI -args) by typing: +Once finished, you can check QHub's version (and additional CLI args) by typing: ```bash qhub --help @@ -113,11 +112,11 @@ optional arguments: ## :label: Usage -QHub requires the setting of environment variables to automate the deployments fully. For details on how to obtain those -variables, check the [installation guide](docs/source/installation/installation.md) in the docs. +QHub requires the setting of environment variables to automate the deployments fully. For details on how to obtain those variables, check the +[installation guide](docs/source/installation/installation.md) in the docs. -Once all the necessary credentials are gathered and set as [UNIX environment variables](https://linuxize.com/post/how-to-set-and-list-environment-variables-in-linux/), -QHub can be deployed in under 20 minutes using: +Once all the necessary credentials are gathered and set as [UNIX environment variables](https://linuxize.com/post/how-to-set-and-list-environment-variables-in-linux/), QHub can be +deployed in under 20 minutes using: ```bash qhub init ... # generates initial config file and optionally automates deployment steps @@ -130,17 +129,15 @@ Have a look at our [FAQ](docs/source/user_guide/faq.md) to see if your query has We separate the queries for QHub into: -* [GitHub Discussions](https://github.com/Quansight/qhub/discussions) used to raise discussions about a subject, such as: -"What is the recommended way to do X with QHub?" +- [GitHub Discussions](https://github.com/Quansight/qhub/discussions) used to raise discussions about a subject, such as: "What is the recommended way to do X with QHub?" -* [Issues](https://github.com/Quansight/qhub/issues/new/choose) for queries, bug reporting, feature requests,documentation, etc. +- [Issues](https://github.com/Quansight/qhub/issues/new/choose) for queries, bug reporting, feature requests,documentation, etc. > We work around the clock to make QHub better, but sometimes your query might take a while to get a reply. We apologise in advance and ask you to please, be patient :pray:. ## :book: Code of Conduct -To guarantee a welcoming and friendly community, we require contributors to follow our -[Code of Conduct](https://github.com/Quansight/.github/blob/master/CODE_OF_CONDUCT.md). +To guarantee a welcoming and friendly community, we require contributors to follow our [Code of Conduct](https://github.com/Quansight/.github/blob/master/CODE_OF_CONDUCT.md). ## :gear: Installing the Development version of QHub @@ -154,6 +151,13 @@ pip install git+https://github.com/Quansight/qhub.git@dev Thinking about contributing? Check out our [Contribution Guidelines](https://github.com/Quansight/qhub/blob/main/CONTRIBUTING.md). +## Ongoing Support + +The `v0.4.0` release introduced many changes that will irrevocably break your deployment if you attempt an inplace upgrade; for details see our +[RELEASE](RELEASE.md#release-v040---march-17-2022) notes. In order to focus on the future direction of the project, we have decided as a team that we will provide **limited** support for older versions. Any new user is encouraged to use `v0.4.0` or greater. + +If you're using an older version of QHub and would like professional support, please reach out to Quansight. + ## License [QHub is BSD3 licensed](LICENSE). diff --git a/RELEASE.md b/RELEASE.md index 19d16b818..700accc57 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,14 +1,8 @@ # Changelog > Contains description of QHub releases. ---- -## To create a new release: -1. Increment the version number in `qhub/VERSION` -2. Ensure that the version number in `qhub/VERSION` is used in pinning QHub in the github actions -`qhub/template/{{ cookiecutter.repo_directory }}/.github/workflows/qhub-ops.yaml` - ---- +______________________________________________________________________ ## Upcoming Release @@ -16,12 +10,43 @@ ### Bug fixes -## Release v0.4.0 - 03/17/2022 +## Release v0.4.0 - March 17, 2022 + +**WARNING** +> If you're looking for a stable version of QHub, please consider `v0.3.14`. The `v0.4.0` has many breaking changes and has rough edges that will be resolved in upcoming point releases. + +We are happy to annouce the release of `v0.4.0`! This release lays the groundwork for many exciting new features and improvements in the future, stay tuned. + +Version `v0.4.0` introduced many design changes along with a handful of user-facing changes that require some justification. Unfortunately as a result of these changes, QHub +instances that are upgraded from previous version to `v0.4.0` will irrevocably break. + +Until we have a fully functioning backup mechanism, anyone looking to upgrade is highly encouraged to backup their data, see the +[upgrade docs](https://docs.qhub.dev/en/latest/source/admin_guide/breaking-upgrade.html) and more specifically, the +[backup docs](https://docs.qhub.dev/en/latest/source/admin_guide/backup.html). + +These design changes were considered important enough that the development team felt they were warranted. Below we try to highlight a few of the largest changes +and provide justification for them. + +- Replace Terraforms resource targeting with staged Terraform deployments. + - *Justification*: using Terraform resource targeting was never an ideal way of handing off outputs from stage to the next and Terraform explicitly warns its users that it's only + intended to be used "for exceptional situations such as recovering from errors or mistakes". +- Fully remove `cookiecutter` as a templating mechanism. + - *Justification*: Although `cookiecutter` has its benefits, we were becoming overly reliant on it as a means of rendering various scripts needed for the deployment. Reading through + Terraform scripts with scattered `cookiecutter` statements was increasing troublesome and a bit intimidating. Our IDEs are also much happier about this change. +- Removing users and groups from the `qhub-config.yaml` and replacing user management with Keycloak. + - *Justification*: Up until now, any change to QHub deployment needed to be made in the `qhub-config.yaml` which had the benefit of centralizing any configuration. However it + also potentially limited the kinds of user management tasks while also causing the `qhub-config.yaml` to balloon in size. Another benefit of removing users and groups from the + `qhub-config.yaml` that deserves highlighting is that user management no longer requires a full redeployment. + +Although breaking changes are never fun, we hope the reasons outlined above are encouraging signs that we are working on building a better, more stable, more flexible product. If you +experience any issues or have any questions about these changes, feel free to open an [issue on our Github repo](https://github.com/Quansight/qhub/issues). ## Breaking changes +Explicit user facing changes: + - Upgrading to `v0.4.0` will require a filesystem backup given the scope and size of the current change set. - - Running `qhub upgrade` will produce an updated `qhub-config.yaml` and a json file of users that can then be imported into Keycloak. + - Running `qhub upgrade` will produce an updated `qhub-config.yaml` and a JSON file of users that can then be imported into Keycloak. - With the addition of Keycloak, QHub will no longer support `security.authentication.type = custom`. - No more users and groups in the `qhub-config.yaml`. @@ -35,136 +60,140 @@ ## What's Changed -* Enabling Vale CI with GitHub Actions by @HarshCasper in https://github.com/Quansight/qhub/pull/871 -* Qhub upgrade by @danlester in https://github.com/Quansight/qhub/pull/870 -* Documentation cleanup by @HarshCasper in https://github.com/Quansight/qhub/pull/873 -* [Docs] Add Traefik wildcard docs by @viniciusdc in https://github.com/Quansight/qhub/pull/876 -* replace deprecated "minikube cache add" with "minikube image load" by @Adam-D-Lewis in https://github.com/Quansight/qhub/pull/880 -* Azure Python needs different env var names to Terraform by @danlester in https://github.com/Quansight/qhub/pull/882 -* Add notes about broken upgrades by @tylerpotts in https://github.com/Quansight/qhub/pull/877 -* Keycloak integration first pass by @danlester in https://github.com/Quansight/qhub/pull/848 -* K8s tests - keycloak adduser by @danlester in https://github.com/Quansight/qhub/pull/890 -* Documentation cleanup by @HarshCasper in https://github.com/Quansight/qhub/pull/889 -* Improvements to templates and readme by @trallard in https://github.com/Quansight/qhub/pull/893 -* Keycloak docs by @danlester in https://github.com/Quansight/qhub/pull/901 -* DOCS: Add a PR Template by @HarshCasper in https://github.com/Quansight/qhub/pull/900 -* Delete existing `.gitlab-ci.yml` when rendering by @iameskild in https://github.com/Quansight/qhub/pull/887 -* Qhub Extension (Ready for Review) by @Adam-D-Lewis in https://github.com/Quansight/qhub/pull/886 -* Updates to Readme by @trallard in https://github.com/Quansight/qhub/pull/897 -* Mirror docker images to ghcr and quay container registry by @aktech in https://github.com/Quansight/qhub/pull/912 -* Fix CI: skip failure on cleanup by @aktech in https://github.com/Quansight/qhub/pull/910 -* Create and solve envs using mamba by @iameskild in https://github.com/Quansight/qhub/pull/915 -* Pin terraform providers by @Adam-D-Lewis in https://github.com/Quansight/qhub/pull/914 -* qhub-config.yaml as a secret by @danlester in https://github.com/Quansight/qhub/pull/905 -* Setup/Add integration/deployment tests via pytest by @aktech in https://github.com/Quansight/qhub/pull/922 -* Disabl/Remove the stale bot by @viniciusdc in https://github.com/Quansight/qhub/pull/923 -* Integrates Hadolint for Dockerfile linting by @HarshCasper in https://github.com/Quansight/qhub/pull/917 -* Reduce minimum nodes in user and dask node pools to 0 for Azure / GCP by @tarundmsharma in https://github.com/Quansight/qhub/pull/723 -* Allow jupyterhub.overrides in qhub-config.yaml by @danlester in https://github.com/Quansight/qhub/pull/930 -* qhub destroy using targets by @danlester in https://github.com/Quansight/qhub/pull/948 -* Take AWS region from AWS_DEFAULT_REGION into qhub-config.yaml on init… by @danlester in https://github.com/Quansight/qhub/pull/950 -* cookicutter template out of raw by @danlester in https://github.com/Quansight/qhub/pull/951 -* kubernetes-initialization depends_on kubernetes by @danlester in https://github.com/Quansight/qhub/pull/952 -* Add timeout to terraform import command by @tylerpotts in https://github.com/Quansight/qhub/pull/949 -* Timeout in process (for import) by @danlester in https://github.com/Quansight/qhub/pull/955 -* Remove user/groups from YAML by @danlester in https://github.com/Quansight/qhub/pull/956 -* qhub upgrade custom auth plus tests by @danlester in https://github.com/Quansight/qhub/pull/946 -* Add minimal support `centos` images by @iameskild in https://github.com/Quansight/qhub/pull/943 -* Keycloak Export by @danlester in https://github.com/Quansight/qhub/pull/947 -* qhub cli tool to save kubernetes logs - `qhub support` by @tarundmsharma in https://github.com/Quansight/qhub/pull/818 -* Add docs for deploying QHub to existing EKS cluster by @iameskild in https://github.com/Quansight/qhub/pull/944 -* Add jupyterhub-idle-culler to jupyterhub image by @danlester in https://github.com/Quansight/qhub/pull/959 -* Robust external container registry by @danlester in https://github.com/Quansight/qhub/pull/945 -* use qhub-jupyterhub-theme 0.3.3 to simplify JupyterHub config by @danlester in https://github.com/Quansight/qhub/pull/966 -* Get kubernetes version for all cloud providers + pytest refactor by @iameskild in https://github.com/Quansight/qhub/pull/927 -* Merge hub.extraEnv env vars by @danlester in https://github.com/Quansight/qhub/pull/968 -* DOCS: Removing errors from documentation by @HarshCasper in https://github.com/Quansight/qhub/pull/941 -* keycloak.realm_display_name by @danlester in https://github.com/Quansight/qhub/pull/973 -* minor updates to keycloak docs by @tylerpotts in https://github.com/Quansight/qhub/pull/977 -* CI changes for QHub by @HarshCasper in https://github.com/Quansight/qhub/pull/989 -* Update `upgrade` docs and general doc improvements by @iameskild in https://github.com/Quansight/qhub/pull/990 -* Remove `scope`, `oauth_callback_url` during upgrade step by @iameskild in https://github.com/Quansight/qhub/pull/997 -* Adding Conda-Store to QHub by @costrouc in https://github.com/Quansight/qhub/pull/967 -* Fix Jupyterlab docker build by @viniciusdc in https://github.com/Quansight/qhub/pull/1001 -* DOCS: Fix broken link in setup doc by @HarshCasper in https://github.com/Quansight/qhub/pull/1006 -* Fix Kubernetes local test deployment by @viniciusdc in https://github.com/Quansight/qhub/pull/1002 -* Initial commit for auth and stages workflow by @costrouc in https://github.com/Quansight/qhub/pull/1003 -* Fix formatting issues with black #1003 by @viniciusdc in https://github.com/Quansight/qhub/pull/1020 -* use pyproject.toml and setup.cfg for packaging by @tonyfast in https://github.com/Quansight/qhub/pull/986 -* Increase timeout/attempts for keycloak check by @viniciusdc in https://github.com/Quansight/qhub/pull/1023 -* Fix issue with traefik issueing certificates with letsencrypt acme by @costrouc in https://github.com/Quansight/qhub/pull/1017 -* Fixing cdsdashboard conda environments being shown by @costrouc in https://github.com/Quansight/qhub/pull/1025 -* Fix input variable support for multiple types by @viniciusdc in https://github.com/Quansight/qhub/pull/1029 -* Fix Black/Flake8 problems by @danlester in https://github.com/Quansight/qhub/pull/1039 -* Add remote state condition for 01-terraform-state provisioning by @viniciusdc in https://github.com/Quansight/qhub/pull/1042 -* Round versions for upgrade and schema by @danlester in https://github.com/Quansight/qhub/pull/1038 -* Code Server is now installed via conda, and the Jupyterlab Extension is https://github.com/betatim/vscode-binder/ by @costrouc in https://github.com/Quansight/qhub/pull/1044 -* Removing cookiecutter from setup.cfg requirements by @costrouc in https://github.com/Quansight/qhub/pull/1026 -* Destroy terraform-state stage when condition match by @viniciusdc in https://github.com/Quansight/qhub/pull/1051 -* Fixup adding support for security.keycloak.realm_display_name key by @costrouc in https://github.com/Quansight/qhub/pull/1054 -* Move external_container_reg to earlier stage by @danlester in https://github.com/Quansight/qhub/pull/1053 -* Adding ability to specify overrides back into keycloak configuration by @costrouc in https://github.com/Quansight/qhub/pull/1055 -* Depricating terraform_modules option since no longer used by @costrouc in https://github.com/Quansight/qhub/pull/1057 -* Adding security.shared_users_group option for default users group by @costrouc in https://github.com/Quansight/qhub/pull/1056 -* Fixup adding back jupyterhub overrides option by @costrouc in https://github.com/Quansight/qhub/pull/1058 -* prevent_deploy flag for safeguarding upgrades by @danlester in https://github.com/Quansight/qhub/pull/1047 -* CI: Add layer caching for Docker images by @HarshCasper in https://github.com/Quansight/qhub/pull/1061 -* Additions to TCP/DNS stage check, fix 1027 by @iameskild in https://github.com/Quansight/qhub/pull/1063 -* FIX: Remove concurrency groups by @HarshCasper in https://github.com/Quansight/qhub/pull/1064 -* Stage 08 extensions and realms/logout by @danlester in https://github.com/Quansight/qhub/pull/1069 -* Auto create/destroy azure resource group by @viniciusdc in https://github.com/Quansight/qhub/pull/1071 -* Add CICD schema and render workflows by @iameskild in https://github.com/Quansight/qhub/pull/1068 -* Ensure that the shared folder symlink only exists if user has shared folders by @costrouc in https://github.com/Quansight/qhub/pull/1074 -* Adds the ability on render to deleted targeted files or directories by @costrouc in https://github.com/Quansight/qhub/pull/1073 -* DOCS: QHub 101 by @HarshCasper in https://github.com/Quansight/qhub/pull/1011 -* remove jovyan user by @tylerpotts in https://github.com/Quansight/qhub/pull/1089 -* More finely scoped github actions and kubernetes_test build docker images by @costrouc in https://github.com/Quansight/qhub/pull/1088 -* Adding clearml overrides by @costrouc in https://github.com/Quansight/qhub/pull/1059 -* Reorganizing render, deploy, destroy to unify stages input_vars, tf_objects, checks, and state_imports by @costrouc in https://github.com/Quansight/qhub/pull/1091 -* Updates/fixes for rendering CICD workflows by @iameskild in https://github.com/Quansight/qhub/pull/1086 -* fix bug in state_01_terraform_state function call by @tylerpotts in https://github.com/Quansight/qhub/pull/1094 -* Use paths instead of paths-ignore so that test only run on changes to given paths by @costrouc in https://github.com/Quansight/qhub/pull/1097 -* [ENH] - Update issue templates by @trallard in https://github.com/Quansight/qhub/pull/1083 -* Generate independet objects for terraform-state resources by @viniciusdc in https://github.com/Quansight/qhub/pull/1102 -* Complete implementation of destroy which goes through each stage by @costrouc in https://github.com/Quansight/qhub/pull/1103 -* Change AWS Kubenetes provider authentication to use data.eks_cluster instead of exec by @costrouc in https://github.com/Quansight/qhub/pull/1107 -* Relax qhub destroy to attempt to continue destroying resources by @costrouc in https://github.com/Quansight/qhub/pull/1109 -* Breaking upgrade docs (0.4) by @danlester in https://github.com/Quansight/qhub/pull/1087 -* Simplify default images by @tylerpotts in https://github.com/Quansight/qhub/pull/1114 -* Change group structure by @danlester in https://github.com/Quansight/qhub/pull/1112 -* Adding status field to each destroy stage to print status by @costrouc in https://github.com/Quansight/qhub/pull/1116 -* Incorrect mapping of values to gcp node group instance types by @costrouc in https://github.com/Quansight/qhub/pull/1117 -* FIX: Remove Conda Store from default images by @HarshCasper in https://github.com/Quansight/qhub/pull/1119 -* Minor fix to `setup.cfg` by @iameskild in https://github.com/Quansight/qhub/pull/1122 -* [DOC]- Update contribution guidelines by @trallard in https://github.com/Quansight/qhub/pull/1080 -* Adding tests to visit additional endpoints by @costrouc in https://github.com/Quansight/qhub/pull/1118 -* Adding tests for juypterhub-ssh, jhub-client, and vs code by @costrouc in https://github.com/Quansight/qhub/pull/1123 -* Update Keycloak docs by @iameskild in https://github.com/Quansight/qhub/pull/1093 -* Upgrade conda-store v0.3.10 and simplify specification of image by @HarshCasper in https://github.com/Quansight/qhub/pull/1130 -* [ImgBot] Optimize images by @imgbot in https://github.com/Quansight/qhub/pull/1140 -* Adjust Idle culler settings and add internal culling by @viniciusdc in https://github.com/Quansight/qhub/pull/1133 -* [BUG] Removing jovyan home directory and issue with nss confiuration by @costrouc in https://github.com/Quansight/qhub/pull/1142 -* [DOC] Add `troubleshooting` docs by @iameskild in https://github.com/Quansight/qhub/pull/1139 -* Update user login guides by @viniciusdc in https://github.com/Quansight/qhub/pull/1144 -* [ImgBot] Optimize images by @imgbot in https://github.com/Quansight/qhub/pull/1146 -* Workaround for kubernetes-client version issue by @iameskild in https://github.com/Quansight/qhub/pull/1148 -* Make the commit of the terraform rendering optional (replaces PR 995) by @iameskild in https://github.com/Quansight/qhub/pull/1149 -* Fix typos in user guide docs by @ericdatakelly in https://github.com/Quansight/qhub/pull/1154 -* Minor docs clean up for v0.4.0 release by @iameskild in https://github.com/Quansight/qhub/pull/1155 -* Readthedocs and documentation updates by @tonyfast in https://github.com/Quansight/qhub/pull/1153 -* Add markdown formatter for doc wrapping by @viniciusdc in https://github.com/Quansight/qhub/pull/1152 -* remove deprecated param `count` from `.cirun.yml` by @aktech in https://github.com/Quansight/qhub/pull/1164 -* Use qhub-bot for keycloak deployment/check by @iameskild in https://github.com/Quansight/qhub/pull/1167 -* Only list active conda-envs for dask-gateway by @iameskild in https://github.com/Quansight/qhub/pull/1162 +
+ +- Enabling Vale CI with GitHub Actions by @HarshCasper in https://github.com/Quansight/qhub/pull/871 +- Qhub upgrade by @danlester in https://github.com/Quansight/qhub/pull/870 +- Documentation cleanup by @HarshCasper in https://github.com/Quansight/qhub/pull/873 +- \[Docs\] Add Traefik wildcard docs by @viniciusdc in https://github.com/Quansight/qhub/pull/876 +- replace deprecated "minikube cache add" with "minikube image load" by @Adam-D-Lewis in https://github.com/Quansight/qhub/pull/880 +- Azure Python needs different env var names to Terraform by @danlester in https://github.com/Quansight/qhub/pull/882 +- Add notes about broken upgrades by @tylerpotts in https://github.com/Quansight/qhub/pull/877 +- Keycloak integration first pass by @danlester in https://github.com/Quansight/qhub/pull/848 +- K8s tests - keycloak adduser by @danlester in https://github.com/Quansight/qhub/pull/890 +- Documentation cleanup by @HarshCasper in https://github.com/Quansight/qhub/pull/889 +- Improvements to templates and readme by @trallard in https://github.com/Quansight/qhub/pull/893 +- Keycloak docs by @danlester in https://github.com/Quansight/qhub/pull/901 +- DOCS: Add a PR Template by @HarshCasper in https://github.com/Quansight/qhub/pull/900 +- Delete existing `.gitlab-ci.yml` when rendering by @iameskild in https://github.com/Quansight/qhub/pull/887 +- Qhub Extension (Ready for Review) by @Adam-D-Lewis in https://github.com/Quansight/qhub/pull/886 +- Updates to Readme by @trallard in https://github.com/Quansight/qhub/pull/897 +- Mirror docker images to ghcr and quay container registry by @aktech in https://github.com/Quansight/qhub/pull/912 +- Fix CI: skip failure on cleanup by @aktech in https://github.com/Quansight/qhub/pull/910 +- Create and solve envs using mamba by @iameskild in https://github.com/Quansight/qhub/pull/915 +- Pin terraform providers by @Adam-D-Lewis in https://github.com/Quansight/qhub/pull/914 +- qhub-config.yaml as a secret by @danlester in https://github.com/Quansight/qhub/pull/905 +- Setup/Add integration/deployment tests via pytest by @aktech in https://github.com/Quansight/qhub/pull/922 +- Disabl/Remove the stale bot by @viniciusdc in https://github.com/Quansight/qhub/pull/923 +- Integrates Hadolint for Dockerfile linting by @HarshCasper in https://github.com/Quansight/qhub/pull/917 +- Reduce minimum nodes in user and dask node pools to 0 for Azure / GCP by @tarundmsharma in https://github.com/Quansight/qhub/pull/723 +- Allow jupyterhub.overrides in qhub-config.yaml by @danlester in https://github.com/Quansight/qhub/pull/930 +- qhub destroy using targets by @danlester in https://github.com/Quansight/qhub/pull/948 +- Take AWS region from AWS_DEFAULT_REGION into qhub-config.yaml on init… by @danlester in https://github.com/Quansight/qhub/pull/950 +- cookicutter template out of raw by @danlester in https://github.com/Quansight/qhub/pull/951 +- kubernetes-initialization depends_on kubernetes by @danlester in https://github.com/Quansight/qhub/pull/952 +- Add timeout to terraform import command by @tylerpotts in https://github.com/Quansight/qhub/pull/949 +- Timeout in process (for import) by @danlester in https://github.com/Quansight/qhub/pull/955 +- Remove user/groups from YAML by @danlester in https://github.com/Quansight/qhub/pull/956 +- qhub upgrade custom auth plus tests by @danlester in https://github.com/Quansight/qhub/pull/946 +- Add minimal support `centos` images by @iameskild in https://github.com/Quansight/qhub/pull/943 +- Keycloak Export by @danlester in https://github.com/Quansight/qhub/pull/947 +- qhub cli tool to save kubernetes logs - `qhub support` by @tarundmsharma in https://github.com/Quansight/qhub/pull/818 +- Add docs for deploying QHub to existing EKS cluster by @iameskild in https://github.com/Quansight/qhub/pull/944 +- Add jupyterhub-idle-culler to jupyterhub image by @danlester in https://github.com/Quansight/qhub/pull/959 +- Robust external container registry by @danlester in https://github.com/Quansight/qhub/pull/945 +- use qhub-jupyterhub-theme 0.3.3 to simplify JupyterHub config by @danlester in https://github.com/Quansight/qhub/pull/966 +- Get kubernetes version for all cloud providers + pytest refactor by @iameskild in https://github.com/Quansight/qhub/pull/927 +- Merge hub.extraEnv env vars by @danlester in https://github.com/Quansight/qhub/pull/968 +- DOCS: Removing errors from documentation by @HarshCasper in https://github.com/Quansight/qhub/pull/941 +- keycloak.realm_display_name by @danlester in https://github.com/Quansight/qhub/pull/973 +- minor updates to keycloak docs by @tylerpotts in https://github.com/Quansight/qhub/pull/977 +- CI changes for QHub by @HarshCasper in https://github.com/Quansight/qhub/pull/989 +- Update `upgrade` docs and general doc improvements by @iameskild in https://github.com/Quansight/qhub/pull/990 +- Remove `scope`, `oauth_callback_url` during upgrade step by @iameskild in https://github.com/Quansight/qhub/pull/997 +- Adding Conda-Store to QHub by @costrouc in https://github.com/Quansight/qhub/pull/967 +- Fix Jupyterlab docker build by @viniciusdc in https://github.com/Quansight/qhub/pull/1001 +- DOCS: Fix broken link in setup doc by @HarshCasper in https://github.com/Quansight/qhub/pull/1006 +- Fix Kubernetes local test deployment by @viniciusdc in https://github.com/Quansight/qhub/pull/1002 +- Initial commit for auth and stages workflow by @costrouc in https://github.com/Quansight/qhub/pull/1003 +- Fix formatting issues with black #1003 by @viniciusdc in https://github.com/Quansight/qhub/pull/1020 +- use pyproject.toml and setup.cfg for packaging by @tonyfast in https://github.com/Quansight/qhub/pull/986 +- Increase timeout/attempts for keycloak check by @viniciusdc in https://github.com/Quansight/qhub/pull/1023 +- Fix issue with traefik issuing certificates with let's encrypt acme by @costrouc in https://github.com/Quansight/qhub/pull/1017 +- Fixing cds dashboard conda environments being shown by @costrouc in https://github.com/Quansight/qhub/pull/1025 +- Fix input variable support for multiple types by @viniciusdc in https://github.com/Quansight/qhub/pull/1029 +- Fix Black/Flake8 problems by @danlester in https://github.com/Quansight/qhub/pull/1039 +- Add remote state condition for 01-terraform-state provisioning by @viniciusdc in https://github.com/Quansight/qhub/pull/1042 +- Round versions for upgrade and schema by @danlester in https://github.com/Quansight/qhub/pull/1038 +- Code Server is now installed via conda, and the Jupyterlab Extension is https://github.com/betatim/vscode-binder/ by @costrouc in https://github.com/Quansight/qhub/pull/1044 +- Removing cookiecutter from setup.cfg requirements by @costrouc in https://github.com/Quansight/qhub/pull/1026 +- Destroy terraform-state stage when condition match by @viniciusdc in https://github.com/Quansight/qhub/pull/1051 +- Fix up adding support for security.keycloak.realm_display_name key by @costrouc in https://github.com/Quansight/qhub/pull/1054 +- Move external_container_reg to earlier stage by @danlester in https://github.com/Quansight/qhub/pull/1053 +- Adding ability to specify overrides back into keycloak configuration by @costrouc in https://github.com/Quansight/qhub/pull/1055 +- Deprecating terraform_modules option since no longer used by @costrouc in https://github.com/Quansight/qhub/pull/1057 +- Adding security.shared_users_group option for default users group by @costrouc in https://github.com/Quansight/qhub/pull/1056 +- Fix up adding back jupyterhub overrides option by @costrouc in https://github.com/Quansight/qhub/pull/1058 +- prevent_deploy flag for safeguarding upgrades by @danlester in https://github.com/Quansight/qhub/pull/1047 +- CI: Add layer caching for Docker images by @HarshCasper in https://github.com/Quansight/qhub/pull/1061 +- Additions to TCP/DNS stage check, fix 1027 by @iameskild in https://github.com/Quansight/qhub/pull/1063 +- FIX: Remove concurrency groups by @HarshCasper in https://github.com/Quansight/qhub/pull/1064 +- Stage 08 extensions and realms/logout by @danlester in https://github.com/Quansight/qhub/pull/1069 +- Auto create/destroy azure resource group by @viniciusdc in https://github.com/Quansight/qhub/pull/1071 +- Add CICD schema and render workflows by @iameskild in https://github.com/Quansight/qhub/pull/1068 +- Ensure that the shared folder symlink only exists if user has shared folders by @costrouc in https://github.com/Quansight/qhub/pull/1074 +- Adds the ability on render to deleted targeted files or directories by @costrouc in https://github.com/Quansight/qhub/pull/1073 +- DOCS: QHub 101 by @HarshCasper in https://github.com/Quansight/qhub/pull/1011 +- remove jovyan user by @tylerpotts in https://github.com/Quansight/qhub/pull/1089 +- More finely scoped github actions and kubernetes_test build docker images by @costrouc in https://github.com/Quansight/qhub/pull/1088 +- Adding clearml overrides by @costrouc in https://github.com/Quansight/qhub/pull/1059 +- Reorganizing render, deploy, destroy to unify stages input_vars, tf_objects, checks, and state_imports by @costrouc in https://github.com/Quansight/qhub/pull/1091 +- Updates/fixes for rendering CICD workflows by @iameskild in https://github.com/Quansight/qhub/pull/1086 +- fix bug in state_01_terraform_state function call by @tylerpotts in https://github.com/Quansight/qhub/pull/1094 +- Use paths instead of paths-ignore so that test only run on changes to given paths by @costrouc in https://github.com/Quansight/qhub/pull/1097 +- \[ENH\] - Update issue templates by @trallard in https://github.com/Quansight/qhub/pull/1083 +- Generate independent objects for terraform-state resources by @viniciusdc in https://github.com/Quansight/qhub/pull/1102 +- Complete implementation of destroy which goes through each stage by @costrouc in https://github.com/Quansight/qhub/pull/1103 +- Change AWS Kubernetes provider authentication to use data.eks_cluster instead of exec by @costrouc in https://github.com/Quansight/qhub/pull/1107 +- Relax qhub destroy to attempt to continue destroying resources by @costrouc in https://github.com/Quansight/qhub/pull/1109 +- Breaking upgrade docs (0.4) by @danlester in https://github.com/Quansight/qhub/pull/1087 +- Simplify default images by @tylerpotts in https://github.com/Quansight/qhub/pull/1114 +- Change group structure by @danlester in https://github.com/Quansight/qhub/pull/1112 +- Adding status field to each destroy stage to print status by @costrouc in https://github.com/Quansight/qhub/pull/1116 +- Incorrect mapping of values to gcp node group instance types by @costrouc in https://github.com/Quansight/qhub/pull/1117 +- FIX: Remove Conda Store from default images by @HarshCasper in https://github.com/Quansight/qhub/pull/1119 +- Minor fix to `setup.cfg` by @iameskild in https://github.com/Quansight/qhub/pull/1122 +- \[DOC\]- Update contribution guidelines by @trallard in https://github.com/Quansight/qhub/pull/1080 +- Adding tests to visit additional endpoints by @costrouc in https://github.com/Quansight/qhub/pull/1118 +- Adding tests for juypterhub-ssh, jhub-client, and vs code by @costrouc in https://github.com/Quansight/qhub/pull/1123 +- Update Keycloak docs by @iameskild in https://github.com/Quansight/qhub/pull/1093 +- Upgrade conda-store v0.3.10 and simplify specification of image by @HarshCasper in https://github.com/Quansight/qhub/pull/1130 +- \[ImgBot\] Optimize images by @imgbot in https://github.com/Quansight/qhub/pull/1140 +- Adjust Idle culler settings and add internal culling by @viniciusdc in https://github.com/Quansight/qhub/pull/1133 +- \[BUG\] Removing jovyan home directory and issue with nss configuration by @costrouc in https://github.com/Quansight/qhub/pull/1142 +- \[DOC\] Add `troubleshooting` docs by @iameskild in https://github.com/Quansight/qhub/pull/1139 +- Update user login guides by @viniciusdc in https://github.com/Quansight/qhub/pull/1144 +- \[ImgBot\] Optimize images by @imgbot in https://github.com/Quansight/qhub/pull/1146 +- Workaround for kubernetes-client version issue by @iameskild in https://github.com/Quansight/qhub/pull/1148 +- Make the commit of the terraform rendering optional (replaces PR 995) by @iameskild in https://github.com/Quansight/qhub/pull/1149 +- Fix typos in user guide docs by @ericdatakelly in https://github.com/Quansight/qhub/pull/1154 +- Minor docs clean up for v0.4.0 release by @iameskild in https://github.com/Quansight/qhub/pull/1155 +- Read-the-docs and documentation updates by @tonyfast in https://github.com/Quansight/qhub/pull/1153 +- Add markdown formatter for doc wrapping by @viniciusdc in https://github.com/Quansight/qhub/pull/1152 +- remove deprecated param `count` from `.cirun.yml` by @aktech in https://github.com/Quansight/qhub/pull/1164 +- Use qhub-bot for keycloak deployment/check by @iameskild in https://github.com/Quansight/qhub/pull/1167 +- Only list active conda-envs for dask-gateway by @iameskild in https://github.com/Quansight/qhub/pull/1162 + +
## New Contributors -* @imgbot made their first contribution in https://github.com/Quansight/qhub/pull/1140 -* @ericdatakelly made their first contribution in https://github.com/Quansight/qhub/pull/1154 +- @imgbot made their first contribution in https://github.com/Quansight/qhub/pull/1140 +- @ericdatakelly made their first contribution in https://github.com/Quansight/qhub/pull/1154 **Full Changelog**: https://github.com/Quansight/qhub/compare/v0.3.13...v0.4.0 -## Release 0.3.13 - 10/13/2021 +## Release 0.3.13 - October 13, 2021 ### Breaking changes @@ -190,30 +219,30 @@ - Update `remove_existing_renders` to only delete QHub related files/directories ([#800](https://github.com/Quansight/qhub/pull/800)) - Reduce number of AWS subnets down to 4 to increase the number of available nodes by a factor of 4 ([#839](https://github.com/Quansight/qhub/pull/839)) -## Release 0.3.11 - 05/07/2021 +## Release 0.3.11 - May 7, 2021 ### Breaking changes ### Feature changes and enhancements - - better validation messages on github auto provisioning +- better validation messages on github auto provisioning ### Bug fixes - - removing default values from pydantic schema which caused invalid yaml files to unexpectedly pass validation - - make kubespawner_override.environment overridable (prior changes were overwritten) +- removing default values from pydantic schema which caused invalid yaml files to unexpectedly pass validation +- make kubespawner_override.environment overridable (prior changes were overwritten) -## Release 0.3.10 - 05/06/2021 +## Release 0.3.10 - May 6, 2021 ### Breaking changes - - reverting `qhub_user` default name to `jovyan` +- reverting `qhub_user` default name to `jovyan` ### Feature changes and enhancements ### Bug fixes -## Release 0.3.9 - 05/05/2021 +## Release 0.3.9 - May 5, 2021 ### Breaking changes @@ -221,70 +250,70 @@ ### Bug fixes - - terraform formatting in cookiecutter for enabling GPUs on GCP +- terraform formatting in cookiecutter for enabling GPUs on GCP -## Release 0.3.8 - 05/05/2021 +## Release 0.3.8 - May 5, 2021 ### Breaking changes ### Feature changes and enhancements - - creating releases for QHub simplified - - added an image for overriding the dask-gateway being used +- creating releases for QHub simplified +- added an image for overriding the dask-gateway being used ### Bug fixes - - dask-gateway exposed by default now properly - - typo in cookiecutter for enabling GPUs on GCP +- dask-gateway exposed by default now properly +- typo in cookiecutter for enabling GPUs on GCP -## Release 0.3.7 - 04/30/2021 +## Release 0.3.7 - April 30, 2021 ### Breaking changes ### Feature changes and enhancements - - setting `/bin/bash` as the default terminal +- setting `/bin/bash` as the default terminal ### Bug fixes - - `jhsingle-native-proxy` added to the base jupyterlab image +- `jhsingle-native-proxy` added to the base jupyterlab image -## Release 0.3.6 - 04/29/2021 +## Release 0.3.6 - April 29, 2021 ### Breaking changes - - simplified bash jupyterlab image to no longer have dashboard packages panel, etc. +- simplified bash jupyterlab image to no longer have dashboard packages panel, etc. ### Feature changes and enhancements - - added emacs and vim as default editors in image - - added jupyterlab-git and jupyterlab-sidecar since they now support 3.0 - - improvements with `qhub destroy` cleanly deleting resources - - allow user to select conda environments for dashboards - - added command line argument `--skip-terraform-state-provision` to allow for skipping terraform state provisioning in `qhub deploy` step - - no longer render `qhub init` `qhub-config.yaml` file in alphabetical order - - allow user to select instance sizes for dashboards +- added emacs and vim as default editors in image +- added jupyterlab-git and jupyterlab-sidecar since they now support 3.0 +- improvements with `qhub destroy` cleanly deleting resources +- allow user to select conda environments for dashboards +- added command line argument `--skip-terraform-state-provision` to allow for skipping terraform state provisioning in `qhub deploy` step +- no longer render `qhub init` `qhub-config.yaml` file in alphabetical order +- allow user to select instance sizes for dashboards ### Bug fixes - - fixed gitlab-ci before_script and after_script - - fixed jovyan -> qhub_user home directory path issue with dashboards +- fixed gitlab-ci before_script and after_script +- fixed jovyan -> qhub_user home directory path issue with dashboards -## Release 0.3.5 - 04/28/2021 +## Release 0.3.5 - April 28, 2021 ### Breaking changes ### Feature changes and enhancements - - added a `--skip-remote-state-provision` flag to allow `qhub deploy` within CI to skip the remote state creation - - added saner defaults for instance sizes and jupyterlab/dask profiles - - `qhub init` no longer renders `qhub-config.yaml` in alphabetical order - - `spawn_default_options` to False to force dashboard owner to pick profile - - adding `before_script` and `after_script` key to `ci_cd` to allow customization of CI process +- added a `--skip-remote-state-provision` flag to allow `qhub deploy` within CI to skip the remote state creation +- added saner defaults for instance sizes and jupyterlab/dask profiles +- `qhub init` no longer renders `qhub-config.yaml` in alphabetical order +- `spawn_default_options` to False to force dashboard owner to pick profile +- adding `before_script` and `after_script` key to `ci_cd` to allow customization of CI process ### Bug fixes -## Release 0.3.4 - 04/27/2021 +## Release 0.3.4 - April 27, 2021 ### Breaking changes @@ -292,9 +321,9 @@ ### Bug fixes - - remaining issues with ci_cd branch not being fully changed +- remaining issues with ci_cd branch not being fully changed -## Release 0.3.3 - 04/27/2021 +## Release 0.3.3 - April 27, 2021 ### Breaking changes @@ -302,106 +331,107 @@ ### Bug fixes - - Moved to ruamel as yaml parser to throw errors on duplicate keys - - fixed a url link error in cds dashboards - - Azure fixes to enable multiple deployments under one account - - Terraform formatting issue in acme_server deployment - - Terraform errors are caught by qhub and return error code +- Moved to ruamel as yaml parser to throw errors on duplicate keys +- fixed a url link error in cds dashboards +- Azure fixes to enable multiple deployments under one account +- Terraform formatting issue in acme_server deployment +- Terraform errors are caught by qhub and return error code ### Breaking changes -## Release 0.3.2 - 04/20/2021 +## Release 0.3.2 - April 20, 2021 ### Bug fixes - - prevent gitlab-ci from freezing on gitlab deployment - - not all branches were configured via the `branch` option in `ci_cd` +- prevent gitlab-ci from freezing on gitlab deployment +- not all branches were configured via the `branch` option in `ci_cd` -## Release 0.3.1 - 04/20/2021 +## Release 0.3.1 - April 20, 2021 ### Feature changes an enhancements - - added gitlab support for CI - - `ci_cd` field is now optional - - AWS provider now respects the region set - - More robust errors messages in cli around project name and namespace - - `git init` default branch is now `main` - - branch for CI/CD is now configurable + +- added gitlab support for CI +- `ci_cd` field is now optional +- AWS provider now respects the region set +- More robust errors messages in cli around project name and namespace +- `git init` default branch is now `main` +- branch for CI/CD is now configurable ### Bug fixes - - typo in `authenticator_class` for custom authentication -## Release 0.3.0 - 04/14/2021 +- typo in `authenticator_class` for custom authentication + +## Release 0.3.0 - April 14, 2021 ### Feature changes and enhancements -* Support for self-signed certificate/secret keys via kubernetes secrets -* [jupyterhub-ssh](https://github.com/yuvipanda/jupyterhub-ssh) (`ssh` and `sftp` integration) accessible on port `8022` and `8023` respectively -* VSCode([code-server](https://github.com/cdr/code-server)) now provided in default image and integrated with jupyterlab -* [Dask Gateway](https://gateway.dask.org/) now accessible outside of cluster -* Moving fully towards traefik as a load balancer with tight integration with dask-gateway -* Adding ability to specify node selector label for general, user, and worker -* Ability to specify `kube_context` for local deployments otherwise will use default -* Strict schema validation for `qhub-config.yaml` -* Terraform binary is auto-installed and version managed by qhub -* Deploy stage will auto render by default removing the need for render command for end users -* Support for namespaces with qhub deployments on kubernetes clusters -* Full JupyterHub theming including colors now. -* JupyterHub docker image now independent from zero-to-jupyterhub. -* JupyterLab 3 now default user Docker image. -* Implemented the option to locally deploy QHub allowing for local testing. -* Removed the requirement for DNS, authorization is now password-based (no more OAuth requirements). -* Added option for password-based authentication -* CI now tests local deployment on each commit/PR. -* QHub Terraform modules are now pinned to specific git branch via - `terraform_modules.repository` and `terraform_modules.ref`. -* Adds support for Azure cloud provider. +- Support for self-signed certificate/secret keys via kubernetes secrets +- [jupyterhub-ssh](https://github.com/yuvipanda/jupyterhub-ssh) (`ssh` and `sftp` integration) accessible on port `8022` and `8023` respectively +- VSCode([code-server](https://github.com/cdr/code-server)) now provided in default image and integrated with jupyterlab +- [Dask Gateway](https://gateway.dask.org/) now accessible outside of cluster +- Moving fully towards traefik as a load balancer with tight integration with dask-gateway +- Adding ability to specify node selector label for general, user, and worker +- Ability to specify `kube_context` for local deployments otherwise will use default +- Strict schema validation for `qhub-config.yaml` +- Terraform binary is auto-installed and version managed by qhub +- Deploy stage will auto render by default removing the need for render command for end users +- Support for namespaces with qhub deployments on kubernetes clusters +- Full JupyterHub theming including colors now. +- JupyterHub docker image now independent from zero-to-jupyterhub. +- JupyterLab 3 now default user Docker image. +- Implemented the option to locally deploy QHub allowing for local testing. +- Removed the requirement for DNS, authorization is now password-based (no more OAuth requirements). +- Added option for password-based authentication +- CI now tests local deployment on each commit/PR. +- QHub Terraform modules are now pinned to specific git branch via `terraform_modules.repository` and `terraform_modules.ref`. +- Adds support for Azure cloud provider. ### Bug fixes ### Breaking changes -* Terraform version is now pinned to specific version -* `domain` attributed in `qhub-config.yaml` is now the url for the cluster +- Terraform version is now pinned to specific version +- `domain` attributed in `qhub-config.yaml` is now the url for the cluster ### Migration guide 0. Version `` is in format `X.Y.Z` 1. Create release branch `release-` based off `main` -2. Ensure full functionality of QHub this involves at a minimum - ensuring - - [ ] GCP, AWS, DO, and local deployment - - [ ] "Let's Encrypt" successfully provisioned - - [ ] Dask Gateway functions properly on each - - [ ] JupyterLab functions properly on each +2. Ensure full functionality of QHub this involves at a minimum ensuring + +- \[ \] GCP, AWS, DO, and local deployment +- \[ \] "Let's Encrypt" successfully provisioned +- \[ \] Dask Gateway functions properly on each +- \[ \] JupyterLab functions properly on each + 3. Increment the version number in `qhub/VERSION` in format `X.Y.Z` -4. Ensure that the version number in `qhub/VERSION` is used in pinning - QHub in the github actions `qhub/template/{{ - cookiecutter.repo_directory }}/.github/workflows/qhub-ops.yaml` in - format `X.Y.Z` -5. Create a git tag pointing to the release branch once fully tested - and version numbers are incremented `v` +4. Ensure that the version number in `qhub/VERSION` is used in pinning QHub in the github actions `qhub/template/{{ cookiecutter.repo_directory }}/.github/workflows/qhub-ops.yaml` + in format `X.Y.Z` +5. Create a git tag pointing to the release branch once fully tested and version numbers are incremented `v` ---- +______________________________________________________________________ -## Release 0.2.3 - 02/05/2021 +## Release 0.2.3 - February 5, 2021 ### Feature changes, and enhancements -* Added conda prerequisites for GUI packages. -* Added `qhub destroy` functionality that tears down the QHub deployment. -* Changed the default repository branch from `master` to `main`. -* Added error message when Terraform parsing fails. -* Added templates for GitHub issues. +- Added conda prerequisites for GUI packages. +- Added `qhub destroy` functionality that tears down the QHub deployment. +- Changed the default repository branch from `master` to `main`. +- Added error message when Terraform parsing fails. +- Added templates for GitHub issues. ### Bug fixes -* `qhub deploy -c qhub-config.yaml` no longer prompts unsupported argument for `load_config_file`. -* Minor changes on the Step-by-Step walkthrough on the docs. -* Revamp of README.md to make it concise and highlight QHub HPC. +- `qhub deploy -c qhub-config.yaml` no longer prompts unsupported argument for `load_config_file`. +- Minor changes on the Step-by-Step walkthrough on the docs. +- Revamp of README.md to make it concise and highlight QHub HPC. ### Breaking changes -* Removed the registry for DigitalOcean. +- Removed the registry for DigitalOcean. ## Thank you for your contributions! -> [Brian Larsen](https://github.com/brl0), [Rajat Goyal](https://github.com/RajatGoyal), [Prasun Anand](https://github.com/prasunanand), and [Rich Signell](https://github.com/rsignell-usgs) and [Josef Kellndorfer](https://github.com/jkellndorfer) for the insightful discussions. + +> [Brian Larsen](https://github.com/brl0), [Rajat Goyal](https://github.com/RajatGoyal), [Prasun Anand](https://github.com/prasunanand), and +> [Rich Signell](https://github.com/rsignell-usgs) and [Josef Kellndorfer](https://github.com/jkellndorfer) for the insightful discussions. diff --git a/docs/ext/substitute.py b/docs/ext/substitute.py index e0c22ff07..3a63bb023 100644 --- a/docs/ext/substitute.py +++ b/docs/ext/substitute.py @@ -3,14 +3,16 @@ Simply forces replace of ||QHUB_VERSION|| with the qhub_version_string in conf.py """ + def dosubs(app, docname, source): """ Replace QHUB_VERSION with the qhub version """ - if app.config.qhub_version_string != '': + if app.config.qhub_version_string != "": src = source[0] - source[0] = src.replace('||QHUB_VERSION||', app.config.qhub_version_string) + source[0] = src.replace("||QHUB_VERSION||", app.config.qhub_version_string) + def setup(app): app.connect("source-read", dosubs) - app.add_config_value('qhub_version_string', '', 'env') + app.add_config_value("qhub_version_string", "", "env") diff --git a/docs/index.md b/docs/index.md index b2494d20a..2dedd6399 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,7 +9,9 @@ Open source tooling for data science research, development, and deployment. # What is QHub? -QHUb is an integrated data science environment designed and developed by scientists at [**Quansight**](https://www.quansight.com/). It enables teams to build and maintain a cost effective and scalable compute/data science platform in the Cloud, providing an [**Infrastructure as Code**](https://en.wikipedia.org/wiki/Infrastructure_as_code) platform that streamlines the deployment of data science infrastructure. +QHUb is an integrated data science environment designed and developed by scientists at [**Quansight**](https://www.quansight.com/). It enables teams to build and maintain a cost +effective and scalable compute/data science platform in the Cloud, providing an [**Infrastructure as Code**](https://en.wikipedia.org/wiki/Infrastructure_as_code) platform that +streamlines the deployment of data science infrastructure. ```{toctree} :maxdepth: 1 diff --git a/docs/source/admin_guide/awss3curl.md b/docs/source/admin_guide/awss3curl.md index 129f3f5f5..02feee2b8 100644 --- a/docs/source/admin_guide/awss3curl.md +++ b/docs/source/admin_guide/awss3curl.md @@ -2,10 +2,12 @@ In some situations, users may wish to upload content to S3 or download content from an S3 bucket. For example, when attempting [manual backups of QHub's data](./backup.md). -In many cases, the most straightforward way to access AWS S3 buckets is by installing and using AWS's command-line tool. But in some situations - for example, to back up the JupyterHub SQLite database - it may be difficult to install AWS' CLI tools due to being in a restricted container environment. In that situation, it is possible to fall back on AWS' basic REST API and use HTTPS requests directly instead. (Ultimately, the AWS CLI is simply a wrapper around those REST APIs.) +In many cases, the most straightforward way to access AWS S3 buckets is by installing and using AWS's command-line tool. But in some situations - for example, to back up the +JupyterHub SQLite database - it may be difficult to install AWS' CLI tools due to being in a restricted container environment. In that situation, it is possible to fall back on +AWS' basic REST API and use HTTPS requests directly instead. (Ultimately, the AWS CLI is simply a wrapper around those REST APIs.) -This document describes how to use `curl` commands to interface with S3 directly, specifically in the case of [uploading a backup of JupyterHub's SQLite database](./backup.md) from a restricted pod to S3 -(or restoring it from a backup from S3). +This document describes how to use `curl` commands to interface with S3 directly, specifically in the case of [uploading a backup of JupyterHub's SQLite database](./backup.md) from +a restricted pod to S3 (or restoring it from a backup from S3). ## Common settings @@ -67,6 +69,7 @@ curl -H "Host: s3-${region}.amazonaws.com" \ https://s3-${region}.amazonaws.com/${bucket}/${s3_file} -o $output_file ``` +______________________________________________________________________ ---- -Inspired by [this article on how to use curl to upload files to was s3](https://www.gyanblog.com/aws/how-upload-aws-s3-curl/) and [this StackOverflow answer on how to access was s3 buckets](https://stackoverflow.com/a/57516606/2792760). +Inspired by [this article on how to use curl to upload files to was s3](https://www.gyanblog.com/aws/how-upload-aws-s3-curl/) and +[this StackOverflow answer on how to access was s3 buckets](https://stackoverflow.com/a/57516606/2792760). diff --git a/docs/source/admin_guide/backup.md b/docs/source/admin_guide/backup.md index d6cef87ba..c60a2f8fd 100644 --- a/docs/source/admin_guide/backup.md +++ b/docs/source/admin_guide/backup.md @@ -2,7 +2,8 @@ Your cloud provider may have native ways to backup your Kubernetes cluster and volumes. -This guide describes how you would manually obtain the data you need to repopulate your QHub if your cluster is lost and you wish to start it up again from the `qhub-config.yaml` file. +This guide describes how you would manually obtain the data you need to repopulate your QHub if your cluster is lost and you wish to start it up again from the `qhub-config.yaml` +file. There are three main locations that you need to backup: @@ -15,15 +16,15 @@ There are three main locations that you need to backup: This amounts to: - Tarballing the /home directory -- Saving to block storage [s3, google cloud storage, etc] +- Saving to block storage \[s3, google cloud storage, etc\] - Downloading and untaring to new cluster This specific guide shows how to do this on an AWS cluster and upload to AWS S3. ### Pre-requisites -- [Install kubectl]() -- [Install AWS command-line tool]() +- [Install kubectl](https://kubernetes.io/docs/tasks/tools/) +- [Install AWS command-line tool](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) ### Kubectl configuration @@ -41,7 +42,8 @@ aws eks update-kubeconfig --region us-west-2 --name ### Pod deployment -With `kubectl` configured, the next step will be to deploy the pod that allows you to access the cluster files. First, save the following pod specification to a file named `pod.yaml`: +With `kubectl` configured, the next step will be to deploy the pod that allows you to access the cluster files. First, save the following pod specification to a file named +`pod.yaml`: ```yaml kind: Pod @@ -109,7 +111,8 @@ cd /data tar -cvf .tar . ``` -The preferred naming scheme includes a year-month-day, example `2021-04-23_home_backup.tar`. You can utilize multi-backups through this step. This step takes several minutes depending on the size of the home directories. +The preferred naming scheme includes a year-month-day, example `2021-04-23_home_backup.tar`. You can utilize multi-backups through this step. This step takes several minutes +depending on the size of the home directories. ### Upload to block storage @@ -152,22 +155,26 @@ The file permissions for the default tar is same as the original files. > QHub v0.4: If restoring your NFS as part of the upgrade you must also run some extra commands, immediately after extracting from the tar file. > > Previous versions contained the `shared` folder within `home`. From `0.4.0` both `shared` and `home` directories are at the same level with respect to the QHub filesystem: +> > ```shell > cd /data > cp -r home/shared/* shared/ > rm -rf home/shared/ > ``` +> > And then: +> > ```shell > chown -R 1000:100 /data/home/* > chown -R 1000:100 /data/shared/* > ``` -> From QHUb v0.4. all users will have the same `uid`. > +> From QHUb v0.4. all users will have the same `uid`. ### Google cloud provider -To use the Google Cloud provider, install the [gsutil](https://cloud.google.com/storage/docs/gsutil_install) CLI instead of the AWS CLI. Otherwise, the instructions are the same as for AWS above, other than when working with S3. Here are the commands to access Google Spaces instead of S3 for copy/download of the backup: +To use the Google Cloud provider, install the [gsutil](https://cloud.google.com/storage/docs/gsutil_install) CLI instead of the AWS CLI. Otherwise, the instructions are the same as +for AWS above, other than when working with S3. Here are the commands to access Google Spaces instead of S3 for copy/download of the backup: ```shell cd /data @@ -182,18 +189,20 @@ gsutil cp gs:///backups/2021-04-23.tar . Instructions will be similar to those for AWS above, but use Digital Ocean spaces instead of S3. This guide explains installation of the command-line tool: - ## JupyterHub Database The JupyterHub database will mostly be recreated whenever you start a new cluster, but should be backed up to save Dashboard configurations. -You want to do something very similar to the NFS backup, above - this time you need to back up just one file located in the PersistentVolume `hub-db-dir`. +You want to do something very similar to the NFS backup, above - this time you need to back up just one file located in the PersistentVolume `hub-db-dir`. -First, you might think you can just make a new `pod.yaml` file, this time specifying `claimName: "hub-db-dir"` instead of `claimName: "jupyterhub-dev-share"`. However, `hub-db-dir` is 'Read Write Once' - the 'Once' meaning it can only be mounted to one pod at a time, but the JupyterHub pod will already have this mounted! So the same approach will not work here. +First, you might think you can just make a new `pod.yaml` file, this time specifying `claimName: "hub-db-dir"` instead of `claimName: "jupyterhub-dev-share"`. However, `hub-db-dir` +is 'Read Write Once' - the 'Once' meaning it can only be mounted to one pod at a time, but the JupyterHub pod will already have this mounted! So the same approach will not work +here. Instead of mounting to a new 'debugger pod' you have to access the JupyterHub pod directly using the `kubectl` CLI. Look up the JupyterHub pod: + ```bash kubectl get pods -n dev ``` @@ -210,7 +219,8 @@ There is no need to TAR anything up since the only file required to be backed up ### Backing up JupyterHub DB -Now we just need to upload the file to S3. You might want to [install the AWS CLI tool](#installations) as we did before, however, as the Hub container is a rather restricted environment the recommended approach is to upload files to AWS S3 buckets using curl. +Now we just need to upload the file to S3. You might want to [install the AWS CLI tool](#installations) as we did before, however, as the Hub container is a rather restricted +environment the recommended approach is to upload files to AWS S3 buckets using curl. For more details please refer to the [using curl to access AWS S3 buckets](./awss3curl.md) documentation. @@ -219,6 +229,7 @@ For more details please refer to the [using curl to access AWS S3 buckets](./aws You will need to overwrite the file `/srv/jupyterhub/jupyterhub.sqlite` based on the version backed up to S3. You should restart the pod: + ```bash kubectl delete -n dev pod hub-765c9488d6-8z4nj ``` @@ -227,7 +238,8 @@ As for uploads, [you may need to use curl to download items from an AWS S3 bucke ## Keycloak user/group database -QHub provides a simple script to export the important user/group database. Your new QHub cluster will recreate a lot of Keycloak config (including new Keycloak clients which will have new secrets), so only the high-level Group and User info is exported. +QHub provides a simple script to export the important user/group database. Your new QHub cluster will recreate a lot of Keycloak config (including new Keycloak clients which will +have new secrets), so only the high-level Group and User info is exported. If you have a heavily customized Keycloak configuration, some details may be omitted in this export. diff --git a/docs/source/admin_guide/breaking-upgrade.md b/docs/source/admin_guide/breaking-upgrade.md index 43c9dc6b8..59676ed01 100644 --- a/docs/source/admin_guide/breaking-upgrade.md +++ b/docs/source/admin_guide/breaking-upgrade.md @@ -15,7 +15,8 @@ Please always check the [release notes](../dev_guide/changelog.md) for more deta > The rest of this guide assumes you are upgrading from version v0.3.14 (or earlier) to v0.4. -You may be deploying QHub based on a local configuration file, or you may be using CI/CD workflows in GitHub or GitLab. Either way, you will need to locate a copy of your `qhub-config.yaml` configuration file to upgrade it (and commit back to your git repo in the CI/CD case). +You may be deploying QHub based on a local configuration file, or you may be using CI/CD workflows in GitHub or GitLab. Either way, you will need to locate a copy of your +`qhub-config.yaml` configuration file to upgrade it (and commit back to your git repo in the CI/CD case). For CI/CD deployments, you will need to `git clone ` into a folder on your local machine if you haven't done so already. @@ -65,11 +66,13 @@ qhub upgrade -c qhub-config.yaml This will output a newer version of `qhub-config.yaml` that's compatible with the new version of `qhub`. The process outputs a list of changes it has made. -The `upgrade` command creates a copy of the original unmodified config file (`qhub-config.yaml.old.backup`) as well as a JSON file (`qhub-users-import.json`) used to import existing users into Keycloak. +The `upgrade` command creates a copy of the original unmodified config file (`qhub-config.yaml.old.backup`) as well as a JSON file (`qhub-users-import.json`) used to import +existing users into Keycloak. ## 5. Rename the Project and Increase Kubernetes version -You need to rename the project to avoid clashes with the existing (old) cluster which would otherwise already own resources based on the names that the new cluster will attempt to use. +You need to rename the project to avoid clashes with the existing (old) cluster which would otherwise already own resources based on the names that the new cluster will attempt to +use. The domain should remain as the preferred main one that was always in use previously. @@ -87,7 +90,8 @@ project_name: myqhubnew domain: qhub.myproj.com ``` -> It is also a good time to upgrade your version of Kubernetes. Look for the `kubernetes_version` field within the cloud provider section of the `qhub-config.yaml` file and increase it to the latest. +> It is also a good time to upgrade your version of Kubernetes. Look for the `kubernetes_version` field within the cloud provider section of the `qhub-config.yaml` file and +> increase it to the latest. ## 6. Redeploy QHub @@ -97,17 +101,21 @@ You will now have a `qhub-config.yaml` file that you can deploy. qhub deploy -c qhub-config.yaml ``` -At this point you will see an error message saying that deployment is prevented due to the `prevent_deploy` setting in your YAML file. This is a safeguard to ensure that you only proceed if you are aware of possible breaking changes in the current upgrade. +At this point you will see an error message saying that deployment is prevented due to the `prevent_deploy` setting in your YAML file. This is a safeguard to ensure that you only +proceed if you are aware of possible breaking changes in the current upgrade. Make sure to **backup your data** as described in the [backup section of the documentation](./backup.md). -Only after backing up your data proceed to remove the `prevent_deploy: true` line in the `qhub-config.yaml` file. This `prevent_deploy` functionality is there as a safeguard. Please only remove it if you understand why it was there in the first place - as a way to stop users blindly upgrading without realising they absolutely needed to backup their data first so that it can be restored into a completely new cluster. +Only after backing up your data proceed to remove the `prevent_deploy: true` line in the `qhub-config.yaml` file. This `prevent_deploy` functionality is there as a safeguard. +Please only remove it if you understand why it was there in the first place - as a way to stop users blindly upgrading without realising they absolutely needed to backup their data +first so that it can be restored into a completely new cluster. Run the `qhub deploy -c qhub-config.yaml` command again and it should get further this time. ## 7. CI/CD: render and commit to git -For CI/CD (GitHub/GitLab) workflows, as well as generating the updated `qhub-config.yaml` files as above, you will also need to regenerate the workflow files based on the latest `qhub` version's templates. +For CI/CD (GitHub/GitLab) workflows, as well as generating the updated `qhub-config.yaml` files as above, you will also need to regenerate the workflow files based on the latest +`qhub` version's templates. With the newly upgraded `qhub-config.yaml` file, run: @@ -115,7 +123,8 @@ With the newly upgraded `qhub-config.yaml` file, run: qhub render -c qhub-config.yaml ``` -(Note that `qhub deploy` would have performed this render step too, but will also immediately redeploy your QHub instance. Run the render command alone if you are now working separately in your repo and don't want to redeploy.) +(Note that `qhub deploy` would have performed this render step too, but will also immediately redeploy your QHub instance. Run the render command alone if you are now working +separately in your repo and don't want to redeploy.) Commit all the files (`qhub-config.yaml` and GitHub/GitLab workflow files) back to the remote repo. All files need to be committed together in the same commit. For example: @@ -133,8 +142,8 @@ If your QHub deployment relies on Auth0 or GitHub for authentication, please upd 2. Select the "Regular Web Application" with the name of your deployment. -3. Under the "Application URIs" section, paste the new OAuth callback URL in the "Allowed Callback URLs" text block. - The URL should be `https://{your-qhub-domain}/auth/realms/qhub/broker/auth0/endpoint`, replacing `{your-qhub-domain}` with your literal domain of course. +3. Under the "Application URIs" section, paste the new OAuth callback URL in the "Allowed Callback URLs" text block. The URL should be + `https://{your-qhub-domain}/auth/realms/qhub/broker/auth0/endpoint`, replacing `{your-qhub-domain}` with your literal domain of course. @@ -144,8 +153,8 @@ If your QHub deployment relies on Auth0 or GitHub for authentication, please upd 2. Click "OAuth Apps" and then click the app representing your QHub instance. -3. Under "Authorization callback URL", paste the new GitHub callback URL. - The URL should be `https://{your-qhub-domain}/auth/realms/qhub/broker/github/endpoint`, replacing `{your-qhub-domain}` with your literal domain of course. +3. Under "Authorization callback URL", paste the new GitHub callback URL. The URL should be `https://{your-qhub-domain}/auth/realms/qhub/broker/github/endpoint`, replacing + `{your-qhub-domain}` with your literal domain of course. @@ -166,9 +175,9 @@ The last two steps are to: For more details on this process, visit the [Keycloak docs section](../installation/login.md). - ## Known versions that require re-deployment -Version `v0.3.11` on AWS has an error with the Kubernetes config map. See [this GitHub discussion related to AWS K8s config maps](https://github.com/Quansight/qhub/discussions/841) for more details. +Version `v0.3.11` on AWS has an error with the Kubernetes config map. See [this GitHub discussion related to AWS K8s config maps](https://github.com/Quansight/qhub/discussions/841) +for more details. Version `v0.4`. diff --git a/docs/source/admin_guide/clearml.md b/docs/source/admin_guide/clearml.md index 2704f4c84..e6218fddf 100644 --- a/docs/source/admin_guide/clearml.md +++ b/docs/source/admin_guide/clearml.md @@ -54,8 +54,7 @@ This is especially useful for accessing ClearML programmatically. ## Overrides -Addition helm chart variables may want to be overridden. For this an -override hook is provided where you can specify anything with the +Addition helm chart variables may want to be overridden. For this an override hook is provided where you can specify anything with the [values.yaml](https://github.com/allegroai/clearml-helm-charts/tree/main/charts/clearml). ```yaml diff --git a/docs/source/admin_guide/cost.md b/docs/source/admin_guide/cost.md index d84ace70c..75539a349 100644 --- a/docs/source/admin_guide/cost.md +++ b/docs/source/admin_guide/cost.md @@ -1,24 +1,27 @@ # Cloud cost and capabilities -Qhub doesn't charge a fee for infrastructure but cloud providers themselves have pricing for all their services. A digital ocean cluster's minimum fixed cost is around \$60/month. While other cloud providers fixed cost is around \$200/month. Each cloud vendor has different pricing and capabilities of their kubernetes offerings which can significantly affect the pricing of QHub. Cost alone doesn't determine which cloud is best for your use case. Often times you can't choose the cloud that QHub runs on. In this case this document can help determine a reasonable cost for running QHub. Keep in mind these numbers are a simplified view of pricing and won't reflect your actual bill. +Qhub doesn't charge a fee for infrastructure but cloud providers themselves have pricing for all their services. A digital ocean cluster's minimum fixed cost is around $60/month. +While other cloud providers fixed cost is around $200/month. Each cloud vendor has different pricing and capabilities of their kubernetes offerings which can significantly affect +the pricing of QHub. Cost alone doesn't determine which cloud is best for your use case. Often times you can't choose the cloud that QHub runs on. In this case this document can +help determine a reasonable cost for running QHub. Keep in mind these numbers are a simplified view of pricing and won't reflect your actual bill. ## Kubernetes Often cloud providers have a fixed cost for using kubernetes. Here is a table of capabilities of each cloud kubernetes offering along with costs: | Cloud | Pricing | Scale to 0? | Spot/Preemptible? | GPUs | -|:------------------------------------------------------------------------------|:----------|:------------|------------------|:-----| -| [Digital Ocean Kubernetes](https://www.digitalocean.com/products/kubernetes/) | 0 | No | No | No | -| [Google Compute Platform GKE](https://cloud.google.com/kubernetes-engine/) | $75/month | Yes | Yes | Yes | -| [Amazon Web Services](https://aws.amazon.com/eks/) | $75/month | No | Yes | Yes | -| [Azure AKS](https://azure.microsoft.com/en-us/services/kubernetes-service/) | $75/month | Yes | Yes | Yes | +| :---------------------------------------------------------------------------- | :-------- | :---------- | ----------------- | :--- | +| [Digital Ocean Kubernetes](https://www.digitalocean.com/products/kubernetes/) | 0 | No | No | No | +| [Google Compute Platform GKE](https://cloud.google.com/kubernetes-engine/) | $75/month | Yes | Yes | Yes | +| [Amazon Web Services](https://aws.amazon.com/eks/) | $75/month | No | Yes | Yes | +| [Azure AKS](https://azure.microsoft.com/en-us/services/kubernetes-service/) | $75/month | Yes | Yes | Yes | ## Network costs All cloud providers charge for egress. Egress is the traffic leaving their cloud service. Additionally QHub sets up a single load balancer that all traffic goes through. | Cloud | Egress | Load Balancer | -|:----------------------|:--------------|:--------------| +| :-------------------- | :------------ | :------------ | | Digital Ocean | $0.01/GB | $10/month | | Google Cloud Platform | $0.12-0.08/GB | $200/month | | Amazon Web Services | $0.09-0.05/GB | $20/month | @@ -26,30 +29,38 @@ All cloud providers charge for egress. Egress is the traffic leaving their cloud ## Storage costs -Cloud providers provide many different types of storage. The include S3 like [object storage](https://en.wikipedia.org/wiki/Object_storage), [block storage](https://en.wikipedia.org/wiki/Block_(data_storage)), and traditional [filesystem storage](https://en.wikipedia.org/wiki/File_system). Note that each type of storage has well known advantages and limitations. - -- Object storage is optimized for cost, bandwidth, and the cost of latency for file access. It directly affects the number of IOPs S3 is capable of. Object storage always provides the highest bandwidth. It does provide parallel partial access to files. -- Block storage is equivalent to a physical disk attached to your machine. Block storage offers high [IOPs](https://en.wikipedia.org/wiki/IOPS) for latency sensitive filesystem operations. They offer high bandwidth similar to object storage but at around 2-4 times the cost. -- Filesystem storage enables shared filesystems between multiple compute notes but at significant cost. NFS filesystem have significantly lower IOPS than block storage and significantly lower bandwidth than object storage. Usually the users choose this option due to needing to share files between multiple machines. This offering should be a last choice due to costing around $0.20/GB. - -| Cloud | Object | Block | Filesystem | -|:----------------------|:---------|:--------------|----------------------------------| -| Digital Ocean | $0.02/GB | $0.10/GB | N/A | -| Google Cloud Platform | $0.02/GB | $0.4-0.12/GB | \$0.20-0.30/GB | -| Amazon Web Services | $0.02/GB | $0.05-0.12/GB | $0.30/GB | -| Azure | $0.02/GB | $0.6-0.12/GB | $0.16/GB | +Cloud providers provide many different types of storage. The include S3 like [object storage](https://en.wikipedia.org/wiki/Object_storage), +[block storage](), and traditional [filesystem storage](https://en.wikipedia.org/wiki/File_system). Note that each type of +storage has well known advantages and limitations. + +- Object storage is optimized for cost, bandwidth, and the cost of latency for file access. It directly affects the number of IOPs S3 is capable of. Object storage always provides + the highest bandwidth. It does provide parallel partial access to files. +- Block storage is equivalent to a physical disk attached to your machine. Block storage offers high [IOPs](https://en.wikipedia.org/wiki/IOPS) for latency sensitive filesystem + operations. They offer high bandwidth similar to object storage but at around 2-4 times the cost. +- Filesystem storage enables shared filesystems between multiple compute notes but at significant cost. NFS filesystem have significantly lower IOPS than block storage and + significantly lower bandwidth than object storage. Usually the users choose this option due to needing to share files between multiple machines. This offering should be a last + choice due to costing around $0.20/GB. + +| Cloud | Object | Block | Filesystem | +| :-------------------- | :------- | :------------ | ------------- | +| Digital Ocean | $0.02/GB | $0.10/GB | N/A | +| Google Cloud Platform | $0.02/GB | $0.4-0.12/GB | $0.20-0.30/GB | +| Amazon Web Services | $0.02/GB | $0.05-0.12/GB | $0.30/GB | +| Azure | $0.02/GB | $0.6-0.12/GB | $0.16/GB | Note that these prices can be deceptive to compare. Each cloud providers offering have wildly different guaranteed IOPs, burst IOPS, guaranteed bandwidth, and burst bandwidth. ## Compute costs -Cloud providers have huge offerings of compute instances. And this guide couldn't do it all justice. A standard 4 CPU/16 GB RAM is used to compare the cloud offerings. This should give a ballpark of the cost of running a compute instance. Note that all compute instances need an attached block storage usually at lest 10 GB. Comparing CPUs isn't a fair comparison due to computer architecture and clock rate. +Cloud providers have huge offerings of compute instances. And this guide couldn't do it all justice. A standard 4 CPU/16 GB RAM is used to compare the cloud offerings. This should +give a ballpark of the cost of running a compute instance. Note that all compute instances need an attached block storage usually at lest 10 GB. Comparing CPUs isn't a fair +comparison due to computer architecture and clock rate. -| Cloud | 4 GB/16 RAM | GPUs? | ARM? | Max CPUs | Max RAM | -|:----------------------|:-----------|:------|------|-----------------|---------| -| Digital Ocean | $120/month | No | No | 40 | 256 | -| Google Cloud Platform | $100/month | Yes | No | 416 | 11776 | -| Amazon Web Services | $100/month | Yes | Yes | 448 | 6144 | -| Azure | $120/month | Yes | No | 120 | 2400 | +| Cloud | 4 GB/16 RAM | GPUs? | ARM? | Max CPUs | Max RAM | +| :-------------------- | :---------- | :---- | ---- | -------- | ------- | +| Digital Ocean | $120/month | No | No | 40 | 256 | +| Google Cloud Platform | $100/month | Yes | No | 416 | 11776 | +| Amazon Web Services | $100/month | Yes | Yes | 448 | 6144 | +| Azure | $120/month | Yes | No | 120 | 2400 | The cloud prices are pretty much the same between cloud providers. For smaller instances, that aren't shown in the table, Digital Ocean can save some money. diff --git a/docs/source/admin_guide/custom-helm-charts.md b/docs/source/admin_guide/custom-helm-charts.md index 37c32f795..d3586b2d3 100644 --- a/docs/source/admin_guide/custom-helm-charts.md +++ b/docs/source/admin_guide/custom-helm-charts.md @@ -15,4 +15,5 @@ helm_extensions: enabled: true ``` -The `overrides` section is optional, but corresponds to the helm chart's [values.yaml](https://helm.sh/docs/chart_template_guide/values_files/) file, and allows you to override the default helm chart settings. +The `overrides` section is optional, but corresponds to the helm chart's [values.yaml](https://helm.sh/docs/chart_template_guide/values_files/) file, and allows you to override the +default helm chart settings. diff --git a/docs/source/admin_guide/faq.md b/docs/source/admin_guide/faq.md index 6f25d5484..26716b644 100644 --- a/docs/source/admin_guide/faq.md +++ b/docs/source/admin_guide/faq.md @@ -2,13 +2,20 @@ ## On AWS, why do user instances occasionally die ~30 minutes after spinning up a large dask cluster? -AWS uses Amazon's Elastic Kubernetes Service for hosting the Kubernetes cluster. [Elastic Kubernetes Service requires the use of at least two availability zones](https://docs.aws.amazon.com/eks/latest/userguide/infrastructure-security.html). The QHub cluster has an [autoscaler](https://docs.aws.amazon.com/eks/latest/userguide/cluster-autoscaler.html) that has a default service that automatically balances the number of EC2 instances between the two availability zones. When large Dask clusters get initialized and destroyed, the autoscaler attempts to reschedule a user pod. This reschedule operation occurs in the other availability zone. When this happens, Kubernetes doesn't successfully transfer the active pod to the other zone and the pod dies. +AWS uses Amazon's Elastic Kubernetes Service for hosting the Kubernetes cluster. +[Elastic Kubernetes Service requires the use of at least two availability zones](https://docs.aws.amazon.com/eks/latest/userguide/infrastructure-security.html). The QHub cluster +has an [autoscaler](https://docs.aws.amazon.com/eks/latest/userguide/cluster-autoscaler.html) that has a default service that automatically balances the number of EC2 instances +between the two availability zones. When large Dask clusters get initialized and destroyed, the autoscaler attempts to reschedule a user pod. This reschedule operation occurs in +the other availability zone. When this happens, Kubernetes doesn't successfully transfer the active pod to the other zone and the pod dies. -To stop this occuring, the autoscaler service "AZRebalance" needs to be manually suspended. Currently this autoscaler service isn't managed by terraform. Disabling it via the console is permanent for the life of the cluster. [There is an open issue to permanently fix this via Terraform](https://github.com/Quansight/qhub/issues/786) +To stop this occuring, the autoscaler service "AZRebalance" needs to be manually suspended. Currently this autoscaler service isn't managed by terraform. Disabling it via the +console is permanent for the life of the cluster. [There is an open issue to permanently fix this via Terraform](https://github.com/Quansight/qhub/issues/786) -To turn off the AZRebalance service, follow the steps in this [AWS documentation](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-suspend-resume-processes.html) to suspend the AZRebalance service. +To turn off the AZRebalance service, follow the steps in this [AWS documentation](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-suspend-resume-processes.html) to suspend +the AZRebalance service. -To turn off the AZRebalance service, follow the steps in this [AWS documentation](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-suspend-resume-processes.html) to suspend the AZRebalance service. +To turn off the AZRebalance service, follow the steps in this [AWS documentation](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-suspend-resume-processes.html) to suspend +the AZRebalance service. ## Can a user deploy an arbitrary pod? @@ -22,4 +29,5 @@ extensions: private: true ``` -This deploys a simple service based on the image provided. name must be a simple terraform-friendly string. It's available on your QHub site at the `/echo` URL, or whatever URL slug you provide. Users need log-in credentials in if the private is true. +This deploys a simple service based on the image provided. name must be a simple terraform-friendly string. It's available on your QHub site at the `/echo` URL, or whatever URL +slug you provide. Users need log-in credentials in if the private is true. diff --git a/docs/source/admin_guide/gpu.md b/docs/source/admin_guide/gpu.md index 111c1801a..c8ed81b16 100644 --- a/docs/source/admin_guide/gpu.md +++ b/docs/source/admin_guide/gpu.md @@ -1,17 +1,14 @@ # GPUs on QHub -Having access to GPUs is of prime importance for speeding up many -computations by several orders of magnitude. QHub provides a way to -achieve that, we will go through achieving that for each Cloud -provider. +Having access to GPUs is of prime importance for speeding up many computations by several orders of magnitude. QHub provides a way to achieve that, we will go through achieving +that for each Cloud provider. ## Clouds ### Google Cloud Platform -By default the quota to spin up GPUs on GCP is 0. Make sure you have -requested GCP Support to increase quota of allowed GPUs for your -billing account to be the number of GPUs you need access to. +By default the quota to spin up GPUs on GCP is 0. Make sure you have requested GCP Support to increase quota of allowed GPUs for your billing account to be the number of GPUs you +need access to. See [GCP Pre-requisites here](https://cloud.google.com/kubernetes-engine/docs/how-to/gpus#requirements) @@ -19,11 +16,8 @@ Here are the changes needed in your `qhub-config.yml` file to get GPUs working w #### 1. Add GPU node group -Add a node group for GPU instance in the `node_groups` section of -`google_cloud_platform` section, and under the `guest_accelerators` -section add the name of the GPU. A comprehensive list of GPU types can -be found in at the Official GCP docs here: -https://cloud.google.com/compute/docs/gpus +Add a node group for GPU instance in the `node_groups` section of `google_cloud_platform` section, and under the `guest_accelerators` section add the name of the GPU. A +comprehensive list of GPU types can be found in at the Official GCP docs here: https://cloud.google.com/compute/docs/gpus An example of getting GPUs on GCP: @@ -49,17 +43,15 @@ google_cloud_platform: Notes: -- One of the restrictions regarding GPUs on GCP is they can only be used -with general-purpose *[N1 machine types](https://cloud.google.com/compute/docs/machine-types#n1_machine_types)*, -except A100 GPUs, which are only supported on *[a2 machine types](https://cloud.google.com/blog/products/compute/announcing-google-cloud-a2-vm-family-based-on-nvidia-a100-gpu)* +- One of the restrictions regarding GPUs on GCP is they can only be used with general-purpose + *[N1 machine types](https://cloud.google.com/compute/docs/machine-types#n1_machine_types)*, except A100 GPUs, which are only supported on + *[a2 machine types](https://cloud.google.com/blog/products/compute/announcing-google-cloud-a2-vm-family-based-on-nvidia-a100-gpu)* -- If you are not using the gcp provider in QHub but are using gcp (let's say deploying - on an existing gcp cluster). You will need to manually install NVIDIA drivers to the - cluster - see [documentation here](https://cloud.google.com/kubernetes-engine/docs/how-to/gpus#installing_drivers). +- If you are not using the gcp provider in QHub but are using gcp (let's say deploying on an existing gcp cluster). You will need to manually install NVIDIA drivers to the cluster + \- see [documentation here](https://cloud.google.com/kubernetes-engine/docs/how-to/gpus#installing_drivers). - See [general limitations of GPUs on Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/docs/how-to/gpus#limitations). - #### 2. Add GPU instance in the JupyterLab profiles ```yaml @@ -82,9 +74,8 @@ profiles: ### Amazon Web Services -Here are the changes needed in your `qhub-config.yml` file to get GPUs -working with AWS. Unlike GCP gpus are specified in the instance type -this is due to how AWS exposes gpus to the user. +Here are the changes needed in your `qhub-config.yml` file to get GPUs working with AWS. Unlike GCP gpus are specified in the instance type this is due to how AWS exposes gpus to +the user. #### 1. Add GPU node group @@ -121,9 +112,8 @@ profiles: Notes: -- If you are not using the AWS provider in QHub but are using the AWS cloud (let's say deploying - on an existing AWS cluster), you will need to manually install NVIDIA drivers to the - cluster. See [documentation here](https://github.com/NVIDIA/k8s-device-plugin). +- If you are not using the AWS provider in QHub but are using the AWS cloud (let's say deploying on an existing AWS cluster), you will need to manually install NVIDIA drivers to + the cluster. See [documentation here](https://github.com/NVIDIA/k8s-device-plugin). ### DigitalOcean @@ -131,13 +121,11 @@ DigitalOcean does not support GPUs at the time of writing this. ### Azure -Azure does support GPUs in Kubernetes, but QHub doesn't currently have -official support for this. +Azure does support GPUs in Kubernetes, but QHub doesn't currently have official support for this. ## Create conda environment to take advantage of GPUs -First you need to consult the driver version of nvidia being -used. This can easily be checked via the command `nvidia-smi`. +First you need to consult the driver version of nvidia being used. This can easily be checked via the command `nvidia-smi`. ```shell $ nvidia-smi @@ -161,13 +149,9 @@ Thu May 20 18:05:14 2021 +-----------------------------------------------------------------------------+ ``` -The important section is `CUDA Version`. In general you should install -a version of cudatoolkit that's less than or equal to the cuda -version (but not too old). If you install `cudatoolkit-dev` and -`cudatoolkit` make sure that they are the same version exactly -including minor version. Also in the near future cuda should have -better [ABI -compatibility](https://docs.nvidia.com/deploy/cuda-compatibility/index.html). +The important section is `CUDA Version`. In general you should install a version of cudatoolkit that's less than or equal to the cuda version (but not too old). If you install +`cudatoolkit-dev` and `cudatoolkit` make sure that they are the same version exactly including minor version. Also in the near future cuda should have better +[ABI compatibility](https://docs.nvidia.com/deploy/cuda-compatibility/index.html). Bellow is an example gpu environment: @@ -183,6 +167,5 @@ dependencies: - numba ``` -We are working hard to make the GPU experience on Qhub as streamlined -as possible. There are many small gotchas when working with GPUs and -getting all the drivers installed properly. +We are working hard to make the GPU experience on Qhub as streamlined as possible. There are many small gotchas when working with GPUs and getting all the drivers installed +properly. diff --git a/docs/source/admin_guide/jupyterhub.md b/docs/source/admin_guide/jupyterhub.md index 023808f8c..df5c8e0f0 100644 --- a/docs/source/admin_guide/jupyterhub.md +++ b/docs/source/admin_guide/jupyterhub.md @@ -4,7 +4,8 @@ QHub has the JupyterHub project at its core. Within the `qhub deploy` step, JupyterHub is installed using the [Zero2JupyterHub Helm package](https://zero-to-jupyterhub.readthedocs.io/). -It's possible to specify Helm overrides (i.e. your own values for selected fields in the JupyterHub deployment's `values.yaml` file) from the `qhub-config.yaml` file. However, be aware that this may conflict with values that are needed to be set in a certain way in order for QHub to operate correctly. +It's possible to specify Helm overrides (i.e. your own values for selected fields in the JupyterHub deployment's `values.yaml` file) from the `qhub-config.yaml` file. However, be +aware that this may conflict with values that are needed to be set in a certain way in order for QHub to operate correctly. To set a Helm override, for example enabling auth state: @@ -17,8 +18,11 @@ jupyterhub: enable_auth_state: true ``` -Where it's possible to influence a value using 'native' QHub configuration, you should use that as a preference. For example, you would not set `jupyterhub.overrides.hub.image.name` to use a custom JupyterHub Docker image. Instead you would set `default_images.jupyterhub`. +Where it's possible to influence a value using 'native' QHub configuration, you should use that as a preference. For example, you would not set +`jupyterhub.overrides.hub.image.name` to use a custom JupyterHub Docker image. Instead you would set `default_images.jupyterhub`. -There is special behavior for the values `jupyterhub.overrides.hub.extraEnv` and `jupyterhub.overrides.hub.extraConfig`. Setting these would have naturally seen them be overridden in their entirety by QHub's own values, but there is special treatment whereby QHub's values are merged into the list of any values that you might have set as overrides. +There is special behavior for the values `jupyterhub.overrides.hub.extraEnv` and `jupyterhub.overrides.hub.extraConfig`. Setting these would have naturally seen them be overridden +in their entirety by QHub's own values, but there is special treatment whereby QHub's values are merged into the list of any values that you might have set as overrides. -In general, it is possible that other overrides will always be lost where QHub sets its own values, so caution must be taken, and in debugging ensure that you are prepared for unexpected results when using overrides. +In general, it is possible that other overrides will always be lost where QHub sets its own values, so caution must be taken, and in debugging ensure that you are prepared for +unexpected results when using overrides. diff --git a/docs/source/admin_guide/keycloak.md b/docs/source/admin_guide/keycloak.md index f8867442b..31e260af1 100644 --- a/docs/source/admin_guide/keycloak.md +++ b/docs/source/admin_guide/keycloak.md @@ -4,7 +4,8 @@ QHub includes a deployment of [Keycloak](https://www.keycloak.org/documentation. Within the `qhub deploy` step, Keycloak is installed using the [Helm chart](https://github.com/codecentric/helm-charts/tree/master/charts/keycloak). -It's possible to specify Helm overrides (i.e. your own values for selected fields in the Keycloak deployment's `values.yaml` file) from the `qhub-config.yaml` file. However, be aware that this may conflict with values that are needed to be set in a certain way in order for QHub to operate correctly. +It's possible to specify Helm overrides (i.e. your own values for selected fields in the Keycloak deployment's `values.yaml` file) from the `qhub-config.yaml` file. However, be +aware that this may conflict with values that are needed to be set in a certain way in order for QHub to operate correctly. To set a Helm override, for example: @@ -25,8 +26,10 @@ security: repository: dockerusername/my-qhub-keycloak ``` -If you do set `overrides.extraEnv` as above, you must remember to include `PROXY_ADDRESS_FORWARDING=true`. Otherwise, the Keycloak deployment will not work as you will have overridden an important default Helm value that's required by QHub. +If you do set `overrides.extraEnv` as above, you must remember to include `PROXY_ADDRESS_FORWARDING=true`. Otherwise, the Keycloak deployment will not work as you will have +overridden an important default Helm value that's required by QHub. To find out more about using Keycloak in QHub, see [Installation - Login](../installation/login.md) -The `security.keycloak.realm_display_name` setting is the text to display on the Keycloak login page for your QHub (and in some other locations). This is optional, and if omitted will default to "QHub " where `project_name` is a field in the `qhub-config.yaml` file. +The `security.keycloak.realm_display_name` setting is the text to display on the Keycloak login page for your QHub (and in some other locations). This is optional, and if omitted +will default to "QHub \" where `project_name` is a field in the `qhub-config.yaml` file. diff --git a/docs/source/admin_guide/monitoring.md b/docs/source/admin_guide/monitoring.md index 12f132d9d..ab31f195f 100644 --- a/docs/source/admin_guide/monitoring.md +++ b/docs/source/admin_guide/monitoring.md @@ -4,13 +4,15 @@ Cluster monitoring via Grafana/Prometheus comes built in with QHub. It's enabled ## Accessing the Grafana dashboards -Users can access the monitoring dashboards via Grafana at: `your-qhub-domain.com/monitoring`. The initial login credentials are username: `admin` and password: `prom-operator`, but users should change the administrator password immediately after the first log in. +Users can access the monitoring dashboards via Grafana at: `your-qhub-domain.com/monitoring`. The initial login credentials are username: `admin` and password: `prom-operator`, but +users should change the administrator password immediately after the first log in. More than 25 prebuilt dashboards come with Qhub. To access them, hover over the dashboards icon, then click "Manage" as indicated in the image below. ![See Existing Dashboards](../images/grafana_manage_dashboards.png) -For example, the General/Kubernetes/Compute Resources/Node/Pods dashboard allows you to easily see which pods are using the most compute and memory on a particular node of your kubernetes cluster. +For example, the General/Kubernetes/Compute Resources/Node/Pods dashboard allows you to easily see which pods are using the most compute and memory on a particular node of your +kubernetes cluster. ![Grafana Node Cpu Usage Dashboard](../images/grafana_node_cpu_usage.png) diff --git a/docs/source/admin_guide/preemptible-spot-instances.md b/docs/source/admin_guide/preemptible-spot-instances.md index 5fdb3c85f..0462edaad 100644 --- a/docs/source/admin_guide/preemptible-spot-instances.md +++ b/docs/source/admin_guide/preemptible-spot-instances.md @@ -1,6 +1,8 @@ # Preemptible and Spot instances on QHub -A preemptible or spot VM is an instance that you can create and run at a much lower price than normal instances. Azure and Google Cloud platform use the term preemptible, while AWS uses the term spot, and Digital Ocean doesn't support these types of instances. However, the cloud provider might stop these instances if it requires access to those resources for other tasks. Preemptible instances are excess Cloud Provider's capacity, so their availability varies with usage. +A preemptible or spot VM is an instance that you can create and run at a much lower price than normal instances. Azure and Google Cloud platform use the term preemptible, while AWS +uses the term spot, and Digital Ocean doesn't support these types of instances. However, the cloud provider might stop these instances if it requires access to those resources for +other tasks. Preemptible instances are excess Cloud Provider's capacity, so their availability varies with usage. ## Usage diff --git a/docs/source/admin_guide/prefect.md b/docs/source/admin_guide/prefect.md index 6d558e4fc..b5c963c8a 100644 --- a/docs/source/admin_guide/prefect.md +++ b/docs/source/admin_guide/prefect.md @@ -27,7 +27,8 @@ There are a bunch of components in getting Prefect working for you, here is a br prefect create project 'your-prefect-project-name' ``` -The `TF_VAR_prefect_token` API key is set as `PREFECT__CLOUD__AGENT__AUTH_TOKEN` environment variable in the agent. It's used while deploying Prefect Agent so that it can connect to Prefect Cloud and query flows. +The `TF_VAR_prefect_token` API key is set as `PREFECT__CLOUD__AGENT__AUTH_TOKEN` environment variable in the agent. It's used while deploying Prefect Agent so that it can connect +to Prefect Cloud and query flows. ## Prefect Cloud @@ -35,15 +36,18 @@ Prefect Cloud is a fully hosted, production-ready backend for Prefect Core. Chec ## Prefect Agent -Prefect Agents is a lightweight processes for orchestrating flow runs. Agents run inside a user's architecture, and are responsible for starting and monitoring flow runs. During operation the agent process queries the Prefect API for any scheduled flow runs, and allocates resources for them on their respective deployment platforms. +Prefect Agents is a lightweight processes for orchestrating flow runs. Agents run inside a user's architecture, and are responsible for starting and monitoring flow runs. During +operation the agent process queries the Prefect API for any scheduled flow runs, and allocates resources for them on their respective deployment platforms. When you enable prefect via `qhub-config.yml` prefect agent is deployed on the QHub's kubernetes cluster, which queries the Prefect Cloud for flow runs. ## Agent configuration overrides -You can override your agent configuration without having to modify the helm files directly. The extra variable `overrides` makes this possible by changing the default values for the Agent chart according to the settings presented on your qhub-config.yaml file. +You can override your agent configuration without having to modify the helm files directly. The extra variable `overrides` makes this possible by changing the default values for +the Agent chart according to the settings presented on your qhub-config.yaml file. -The current variables, originally available in the [Agent helm chart](https://github.com/PrefectHQ/server/blob/master/helm/prefect-server/templates/agent/deployment.yaml) that can be overridden include: +The current variables, originally available in the [Agent helm chart](https://github.com/PrefectHQ/server/blob/master/helm/prefect-server/templates/agent/deployment.yaml) that can +be overridden include: ``` - IMAGE_PULL_SECRETS @@ -67,8 +71,10 @@ prefect: limit: cpu: 4 ``` -Also, if you would like to include an extra variable to the agent environment configuration, that was not previously in the helm chart, you can do it by including it under -the `envVars` field in the overrides block. For example, if you would like to add `MY_VAR: ""` to you agent environment, you can do so by adding the following to your qhub-config + +Also, if you would like to include an extra variable to the agent environment configuration, that was not previously in the helm chart, you can do it by including it under the +`envVars` field in the overrides block. For example, if you would like to add `MY_VAR: ""` to you agent environment, you can do so by adding the following to your +qhub-config ```yaml prefect: @@ -80,7 +86,9 @@ prefect: ### Adding secrets to your Agent configuration -Overrides also allow you to define extra secrets to pass through your agent configuration, for example, when using [default secrets](https://docs.prefect.io/core/concepts/secrets.html#default-secrets) to automatically authenticate your flow with the listed service. In the Google cloud case, for `GCP_CREDENTIALS` context secret, you can do it by adding that specific key value pair into your configuration: +Overrides also allow you to define extra secrets to pass through your agent configuration, for example, when using +[default secrets](https://docs.prefect.io/core/concepts/secrets.html#default-secrets) to automatically authenticate your flow with the listed service. In the Google cloud case, for +`GCP_CREDENTIALS` context secret, you can do it by adding that specific key value pair into your configuration: ```yaml prefect: @@ -89,11 +97,13 @@ prefect: secretEnvVars: PREFECT__CONTEXT__SECRETS__GCP_CREDENTIALS: '' ``` + This secret will then be stored as a [kubernetes secret](https://kubernetes.io/docs/concepts/configuration/secret/) variable into you QHub secrets volume. ## Flows -Prefect agent can only orchestrate your flows, you need an actual flow to run via prefect agent. The API for the same can be found in the [prefect documentation](https://docs.prefect.io/core/concepts/flows.html) Here is a simple example from their official doc: +Prefect agent can only orchestrate your flows, you need an actual flow to run via prefect agent. The API for the same can be found in the +[prefect documentation](https://docs.prefect.io/core/concepts/flows.html) Here is a simple example from their official doc: ```python from prefect import task, Task, Flow @@ -114,7 +124,8 @@ with Flow('My Functional Flow') as flow: ## Storage -The Prefect Storage interface encapsulates logic for storing flows. Each storage unIt's able to store multiple flows (with the constraint of name uniqueness within a given unit). The API documentation for the same can be found in the [prefect documentation](https://docs.prefect.io/api/latest/storage.html#docker) +The Prefect Storage interface encapsulates logic for storing flows. Each storage unIt's able to store multiple flows (with the constraint of name uniqueness within a given unit). +The API documentation for the same can be found in the [prefect documentation](https://docs.prefect.io/api/latest/storage.html#docker) ## Example: Creating, Building and Register Flow @@ -213,4 +224,5 @@ if __name__ == "__main__": Now that you have Prefect Agent running in QHub Kubernetes cluster, you can now run your flows from either of the two ways: - Triggering manually from the Prefect Cloud dashboard. -- Running them on a schedule by adding a parameter to you flow. You can read more about it in the [prefect docs.](https://docs.prefect.io/core/tutorial/05-running-on-a-schedule.html#running-on-schedule) +- Running them on a schedule by adding a parameter to you flow. You can read more about it in the + [prefect docs.](https://docs.prefect.io/core/tutorial/05-running-on-a-schedule.html#running-on-schedule) diff --git a/docs/source/admin_guide/system_maintenance.md b/docs/source/admin_guide/system_maintenance.md index 23b20fd42..63e66afec 100644 --- a/docs/source/admin_guide/system_maintenance.md +++ b/docs/source/admin_guide/system_maintenance.md @@ -1,40 +1,29 @@ # Day-to-day Maintenance -All modifications to the infrastructure should be done with GitHub -Pull-Requests. +All modifications to the infrastructure should be done with GitHub Pull-Requests. ## Common Modifications ### Modifying docker images: jupyterlab, jupyterhub, dask-workers -The docker images used for dask-worker and jupyterlab user -environments are pulled from a docker container registry. The images -are built based on the images specified in the `image` folder. There -are three images that are currently built +The docker images used for dask-worker and jupyterlab user environments are pulled from a docker container registry. The images are built based on the images specified in the +`image` folder. There are three images that are currently built - jupyterlab :: modification of jupyterlab instances for each user - dask-worker :: modification of dask workers and dask scheduler - jupyterhub :: the jupyterhub server (allows for customization of hub UI) - conda-store :: Environment management tool for QHub -Each docker image is customized with its respective directory -(for example `image/Dockerfile.jupyterlab` -> `image/jupyterlab/*`. For -jupyterlab the environment is located at -`image/jupyterlab/environment.yaml`. Thus to add a package to the -environment simply submit a pull request with the new package. +Each docker image is customized with its respective directory (for example `image/Dockerfile.jupyterlab` -> `image/jupyterlab/*`. For jupyterlab the environment is located at +`image/jupyterlab/environment.yaml`. Thus to add a package to the environment simply submit a pull request with the new package. -At this current point in time once a user submits a pull request to -create the given docker image and the PR is accepted with images -built, a PR must follow that adds the image to the qhub -deployment. This can be done by modifying -`infrastructure/variables.tf` and the configuration file. +At this current point in time once a user submits a pull request to create the given docker image and the PR is accepted with images built, a PR must follow that adds the image to +the qhub deployment. This can be done by modifying `infrastructure/variables.tf` and the configuration file. ### Adding additional worker nodegroups -Adding additional nodegroups can be done by editing the configuration -file. While a `general`, `user`, and `worker` nodegroup are required -you may create any additional node group. Take for example the Digital -Ocean configuration. +Adding additional nodegroups can be done by editing the configuration file. While a `general`, `user`, and `worker` nodegroup are required you may create any additional node group. +Take for example the Digital Ocean configuration. ```yaml digital_ocean: @@ -55,8 +44,7 @@ digital_ocean: max_nodes: 5 ``` -To add a node group for a node group called `worker-high-mem` simply -add to the configuration. The same applies for AWS, GCP, and DO. +To add a node group for a node group called `worker-high-mem` simply add to the configuration. The same applies for AWS, GCP, and DO. ```yaml digital_ocean: @@ -83,16 +71,15 @@ digital_ocean: ### Setting specific JupyterLab profile to run on a nodegroup -Sometimes we would like a profile to execute on nodes that are not in -the normal nodegroup. In the example above we created a high memory -node group. To make the jupyterlab profile `small worker` use the high -memory nodegroup do the following. +Sometimes we would like a profile to execute on nodes that are not in the normal nodegroup. In the example above we created a high memory node group. To make the jupyterlab profile +`small worker` use the high memory nodegroup do the following. ```yaml profiles: jupyterlab: - display_name: Small Instance description: Stable environment with 1 cpu / 1 GB ram + access: yaml groups: - admin kubespawner_override: @@ -116,6 +103,7 @@ profiles: jupyterlab: - display_name: Small Instance description: Stable environment with 1 cpu / 1 GB ram + access: yaml groups: - admin kubespawner_override: @@ -130,8 +118,7 @@ profiles: ### Setting specific dask workers to run on a nodegroup -Suppose we want a specific dask worker profile to run on a specific -node group. Here we demonstrate annotating the DO example configuration. +Suppose we want a specific dask worker profile to run on a specific node group. Here we demonstrate annotating the DO example configuration. ```yaml profiles: @@ -144,14 +131,12 @@ profiles: image: "quansight/qhub-dask-worker:v||QHUB_VERSION||" ``` -[Dask-gateway](https://gateway.dask.org/api-server.html#kube-cluster-config) -takes additional configuration for the scheduler pods and -workers. Remember similar to assigning node groups to specific -jupyterlab instances we must get the key for the node pool. +[Dask-gateway](https://gateway.dask.org/api-server.html#kube-cluster-config) takes additional configuration for the scheduler pods and workers. Remember similar to assigning node +groups to specific jupyterlab instances we must get the key for the node pool. - - AWS :: `eks.amazonaws.com/nodegroup` - - GCP :: `cloud.google.com/gke-nodepool` - - DO :: `doks.digitalocean.com/node-pool` +- AWS :: `eks.amazonaws.com/nodegroup` +- GCP :: `cloud.google.com/gke-nodepool` +- DO :: `doks.digitalocean.com/node-pool` Since we are using digital ocean in this example we then need to set the following. @@ -174,5 +159,4 @@ profiles: ## General Modifications -The infrastructure was designed with the goal in mind that each -`module` is orthogonal. +The infrastructure was designed with the goal in mind that each `module` is orthogonal. diff --git a/docs/source/admin_guide/traefik.md b/docs/source/admin_guide/traefik.md index 38f71a7b8..54dcd5922 100644 --- a/docs/source/admin_guide/traefik.md +++ b/docs/source/admin_guide/traefik.md @@ -4,22 +4,16 @@ ### Creating the certificate -[Lego](https://go-acme.github.io/lego/installation/) is a command line -tool for provisioning certificates for a domain. If you are trying to -install QHub within an enterprise you may need to contact someone in -IT to create the certificate and key-pair for you. Ensure that this -certificate has all of the domains that QHub is running on. Lego -supports [multiple DNS -providers](https://go-acme.github.io/lego/dns/). For this example we -will assume Cloudflare as your DNS provider. +[Lego](https://go-acme.github.io/lego/installation/) is a command line tool for provisioning certificates for a domain. If you are trying to install QHub within an enterprise you +may need to contact someone in IT to create the certificate and key-pair for you. Ensure that this certificate has all of the domains that QHub is running on. Lego supports +[multiple DNS providers](https://go-acme.github.io/lego/dns/). For this example we will assume Cloudflare as your DNS provider. ```shell export CLOUDFLARE_DNS_API_TOKEN=1234567890abcdefghijklmnopqrstuvwxyz lego --email myemail@example.com --dns cloudflare --domains my.example.org run ``` -Or alternatively for testing you can create a self-signed -certificate. This should only be used for testing. +Or alternatively for testing you can create a self-signed certificate. This should only be used for testing. ```shell export QHUB_DOMAIN=github-actions.qhub.dev @@ -30,8 +24,7 @@ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3 ### Adding certificate to kubernetes cluster as a secret -You can name the certificate anything you would like -`qhub-domain-certificate` is only an example. +You can name the certificate anything you would like `qhub-domain-certificate` is only an example. ``` kubectl create secret tls qhub-domain-certificate -n dev \ @@ -41,8 +34,7 @@ kubectl create secret tls qhub-domain-certificate -n dev \ ### Using custom certificate in qhub-config.yaml -Once you have followed these steps make sure to modify the -configuration to use the new certificate. +Once you have followed these steps make sure to modify the configuration to use the new certificate. ``` certificate: diff --git a/docs/source/admin_guide/troubleshooting.md b/docs/source/admin_guide/troubleshooting.md index ba4c7e3af..f9f29346b 100644 --- a/docs/source/admin_guide/troubleshooting.md +++ b/docs/source/admin_guide/troubleshooting.md @@ -4,7 +4,8 @@ This guide aims to provide useful information to developers in the detection and ## General Troubleshooting -To minimize the occurrence of errors on your QHub application, please follow the best practices described on the [Installation](../installation/installation.md), [Setup](../installation/setup.md) and [Usage](../installation/usage.md) sections. +To minimize the occurrence of errors on your QHub application, please follow the best practices described on the [Installation](../installation/installation.md), +[Setup](../installation/setup.md) and [Usage](../installation/usage.md) sections. ### Solutions for common problems @@ -37,26 +38,30 @@ To get the kubernetes context to interact with a AWS use the [following instruct 1. Download the [aws command line](https://aws.amazon.com/cli/) 2. [Create AWS Access Key and Secret Key](https://aws.amazon.com/premiumsupport/knowledge-center/create-access-key/) likely already done -2. `aws eks --region update-kubeconfig --name -` +3. `aws eks --region update-kubeconfig --name -` After completing these steps. `kubectl` should be able to access the cluster. #### Debug your Kubernetes cluster -[`k9s`](https://k9scli.io/) is a terminal-based UI to manage Kubernetes clusters that aims to simplify navigating, observing, and managing your applications in `k8s`. `k9s` continuously monitors Kubernetes clusters for changes and provides shortcut commands to interact with the observed resources becoming a fast way to review and resolve day-to-day issues in Kubernetes. It's definitely a huge improvement to the general workflow, and a best-to-have tool for debugging your Kubernetes cluster sessions. +[`k9s`](https://k9scli.io/) is a terminal-based UI to manage Kubernetes clusters that aims to simplify navigating, observing, and managing your applications in `k8s`. `k9s` +continuously monitors Kubernetes clusters for changes and provides shortcut commands to interact with the observed resources becoming a fast way to review and resolve day-to-day +issues in Kubernetes. It's definitely a huge improvement to the general workflow, and a best-to-have tool for debugging your Kubernetes cluster sessions. -Installation can be done on macOS, Windows, and Linux. Instructions for each operating system can be found [here](https://github.com/derailed/k9s). Complete the installation to follow along. +Installation can be done on macOS, Windows, and Linux. Instructions for each operating system can be found [here](https://github.com/derailed/k9s). Complete the installation to +follow along. By default, `k9s` starts with the standard directory that's set as the context (in this case Minikube). To view all the current process press `0`: -![Image of the `k9s` terminal UI](../images/k9s_UI.png) +![Image of the terminal UI](../images/k9s_UI.png) -> **NOTE**: In some circumstances you will be confronted with the need to inspect any services launched by your cluster at your ‘localhost’. For instance, if your cluster has problem -with the network traffic tunnel configuration, it may limit or block the user's access to destination resources over the connection. +> **NOTE**: In some circumstances you will be confronted with the need to inspect any services launched by your cluster at your ‘localhost’. For instance, if your cluster has +> problem with the network traffic tunnel configuration, it may limit or block the user's access to destination resources over the connection. -`k9s` port-forward option shift + f allows you to access and interact with internal Kubernetes cluster processes from your localhost you can then use this method to investigate issues and adjust your services locally without the need to expose them beforehand. +`k9s` port-forward option shift + f allows you to access and interact with internal Kubernetes cluster processes from your localhost you can then use this +method to investigate issues and adjust your services locally without the need to expose them beforehand. ---- +______________________________________________________________________ ## Further Setup @@ -64,7 +69,9 @@ with the network traffic tunnel configuration, it may limit or block the user's #### JupyterHub Theme -The QHub theme was originally based off the [work of the pangeo team](https://github.com/pangeo-data/pangeo-custom-jupyterhub-templates) and is now located in [github.com/Quansight/qhub-jupyterhub-theme](https://github.com/Quansight/qhub-jupyterhub-theme/). For simple modifications to the jupyterhub theme we suggest only editing `infrastructure/jupyterhub.yaml` and the value `c.JupyterHub.template_vars`. For most use cases this should provide enough flexibility. +The QHub theme was originally based off the [work of the pangeo team](https://github.com/pangeo-data/pangeo-custom-jupyterhub-templates) and is now located in +[github.com/Quansight/qhub-jupyterhub-theme](https://github.com/Quansight/qhub-jupyterhub-theme/). For simple modifications to the jupyterhub theme we suggest only editing +`infrastructure/jupyterhub.yaml` and the value `c.JupyterHub.template_vars`. For most use cases this should provide enough flexibility. ```yaml hub: @@ -78,11 +85,14 @@ hub: } ``` -For more serious modifications to the jupyterhub theme you will need to fork [Quansight/qhub-jupyterhub-theme](https://github.com/Quansight/qhub-jupyterhub-theme) and edit the jupyterhub Dockerfile located at `image/Dockerfile.jupyterhub`. Modify the `THEME_OWNER`, `THEME_REPO`, and `THEME_REV`. This should change the Dockerfile to use your new theme. The [Quansight/qhub-jupyterhub-theme](https://github.com/Quansight/qhub-jupyterhub-theme) has detailed documentation. +For more serious modifications to the jupyterhub theme you will need to fork [Quansight/qhub-jupyterhub-theme](https://github.com/Quansight/qhub-jupyterhub-theme) and edit the +jupyterhub Dockerfile located at `image/Dockerfile.jupyterhub`. Modify the `THEME_OWNER`, `THEME_REPO`, and `THEME_REV`. This should change the Dockerfile to use your new theme. +The [Quansight/qhub-jupyterhub-theme](https://github.com/Quansight/qhub-jupyterhub-theme) has detailed documentation. #### JupyterLab Theme -Setting the JupyterLab theme is done via extensions. Edit the `image/postBuild` script to include the jupyterlab extension in the build. Within the `image` directory run the following to build JupyterLab. +Setting the JupyterLab theme is done via extensions. Edit the `image/postBuild` script to include the jupyterlab extension in the build. Within the `image` directory run the +following to build JupyterLab. ```shell docker build -f Docker.jupyterlab -t Quansight/qhub-jupyterlab:latest . @@ -98,7 +108,8 @@ docker run -p 8000:8000 -it Quansight/qhub-jupyterlab:latest jupyter lab --port By default, images such as the default JupyterLab image specified as `quansight/qhub-jupyterhub:v||QHUB_VERSION||` will be pulled from Docker Hub. -To specify a private AWS ECR (and this technique should work regardless of which cloud your QHub is deployed to), first provide details of the ECR and AWS access keys in `qhub-config.yaml`: +To specify a private AWS ECR (and this technique should work regardless of which cloud your QHub is deployed to), first provide details of the ECR and AWS access keys in +`qhub-config.yaml`: ```yaml external_container_reg: @@ -109,4 +120,5 @@ external_container_reg: extcr_region: us-west-1 ``` -This will mean you can specify private Docker images such as `12345678.dkr.ecr.us-west-1.amazonaws.com/quansight/qhub-jupyterlab:mytag` in your `qhub-config.yaml` file. The AWS key and secret provided must have relevant ecr IAMS permissions to authenticate and read from the ECR container registry. +This will mean you can specify private Docker images such as `12345678.dkr.ecr.us-west-1.amazonaws.com/quansight/qhub-jupyterlab:mytag` in your `qhub-config.yaml` file. The AWS key +and secret provided must have relevant ecr IAMS permissions to authenticate and read from the ECR container registry. diff --git a/docs/source/admin_guide/upgrade.md b/docs/source/admin_guide/upgrade.md index a6bfbbb97..2b9b82c7e 100644 --- a/docs/source/admin_guide/upgrade.md +++ b/docs/source/admin_guide/upgrade.md @@ -4,13 +4,15 @@ This is a guide to the general upgrade of QHub to a new version. You should always [backup your data](./backup.md) before upgrading. -> Note that for some releases (e.g. to v0.4), the cluster cannot be upgraded in-situ so you must perform a redeployment (backup the old cluster, redeploy a new upgraded cluster and then restore your data). +> Note that for some releases (e.g. to v0.4), the cluster cannot be upgraded in-situ so you must perform a redeployment (backup the old cluster, redeploy a new upgraded cluster and +> then restore your data). > > To perform a redeployment upgrade see the [breaking upgrade documentation](./breaking-upgrade.md). Here we suppose a user would like to upgrade to a version ``, probably the latest full release of [QHub on PyPI](https://pypi.org/project/qhub/). -You may be deploying QHub based on a local configuration file, or you may be using CI/CD workflows in GitHub or GitLab. Either way, you will need to locate a copy of your `qhub-config.yaml` configuration file to upgrade it (and commit back to your git repo in the CI/CD case). +You may be deploying QHub based on a local configuration file, or you may be using CI/CD workflows in GitHub or GitLab. Either way, you will need to locate a copy of your +`qhub-config.yaml` configuration file to upgrade it (and commit back to your git repo in the CI/CD case). For CI/CD deployments, you will need to `git clone ` into a folder on your local machine if you haven't done so already. @@ -36,11 +38,14 @@ In the folder containing your QHub configuration file, run: qhub upgrade -c qhub-config.yaml ``` -This will output a newer version of `qhub-config.yaml` that's compatible with the new version of `qhub`. The process outputs a list of changes it has made. The `upgrade` command creates a copy of the original unmodified config file (`qhub-config.yaml.old.backup`) as well as any other files that may be required by the upgraded cluster (if any). +This will output a newer version of `qhub-config.yaml` that's compatible with the new version of `qhub`. The process outputs a list of changes it has made. The `upgrade` command +creates a copy of the original unmodified config file (`qhub-config.yaml.old.backup`) as well as any other files that may be required by the upgraded cluster (if any). ## Step 3: Validate special customizations to `qhub-config.yaml` -You may have made special customizations to your `qhub-config.yaml`, such as using your own versions of Docker images. Please check your `qhub-config.yaml` and decide if you need to update any values that would not have been changed automatically - or, for example, you may need to build new versions of your custom Docker images to match any changes in QHub's images. +You may have made special customizations to your `qhub-config.yaml`, such as using your own versions of Docker images. Please check your `qhub-config.yaml` and decide if you need +to update any values that would not have been changed automatically - or, for example, you may need to build new versions of your custom Docker images to match any changes in +QHub's images. ## Step 4: Redeploy QHub @@ -50,13 +55,17 @@ If you are deploying QHub from your local machine (not using CI/CD) then you wil qhub deploy -c qhub-config.yaml ``` -At this point you may see an error message saying that deployment is prevented due to the `prevent_deploy` setting in your YAML file. This is a safeguard to ensure that you only proceed if you are aware of possible breaking changes in the current upgrade. +At this point you may see an error message saying that deployment is prevented due to the `prevent_deploy` setting in your YAML file. This is a safeguard to ensure that you only +proceed if you are aware of possible breaking changes in the current upgrade. -For example, we may be aware that you will lose data due to this upgrade, so need to note a specific upgrade process to keep your data safe. Always check the release notes of the release in this case and get in touch with us if you need assistance. For example, you may find that your existing cluster is intentionally deleted so that a new replacement can be deployed instead, in which case your data must be backed up so it can be restored after the upgrade. +For example, we may be aware that you will lose data due to this upgrade, so need to note a specific upgrade process to keep your data safe. Always check the release notes of the +release in this case and get in touch with us if you need assistance. For example, you may find that your existing cluster is intentionally deleted so that a new replacement can be +deployed instead, in which case your data must be backed up so it can be restored after the upgrade. ### CI/CD: render and commit to git -For CI/CD (GitHub/GitLab) workflows, then as well as generating the updated `qhub-config.yaml` files as above, you will also need to regenerate the workflow files based on the latest `qhub` version's templates. +For CI/CD (GitHub/GitLab) workflows, then as well as generating the updated `qhub-config.yaml` files as above, you will also need to regenerate the workflow files based on the +latest `qhub` version's templates. With the newly upgraded `qhub-config.yaml` file, run: diff --git a/docs/source/dev_guide/architecture.md b/docs/source/dev_guide/architecture.md index 880af6f4a..aa50a9253 100644 --- a/docs/source/dev_guide/architecture.md +++ b/docs/source/dev_guide/architecture.md @@ -1,10 +1,7 @@ # Developer docs -QHub admins are **DevOps engineers**, **system administrators**, -**scientists**, and **network architects** who are responsible for the -critical infrastructure that data scientists and engineers need to -thrive. QHub is bundled with features that make installation easy -while providing the ability to scale with your organization and data. +QHub admins are **DevOps engineers**, **system administrators**, **scientists**, and **network architects** who are responsible for the critical infrastructure that data scientists +and engineers need to thrive. QHub is bundled with features that make installation easy while providing the ability to scale with your organization and data. > The content below is particularly for QHub producers, and those looking to learn more about the QHub architecture. @@ -12,89 +9,119 @@ while providing the ability to scale with your organization and data. After you have cloned the QHub repo locally, you can install QHub through `pip`: - python -m pip install -e .[dev] +``` +python -m pip install -e .[dev] +``` -> NOTE: `zsh` users may need to escape the square brackets `\[dev\]` -To install the pre-commit hooks, run: +> NOTE: `zsh` users may need to escape the square brackets `\[dev\]` To install the pre-commit hooks, run: - pre-commit install +``` +pre-commit install +``` After the installation, the next step is to configure QHub. ## Configuration -QHub is entirely controlled from a configuration file, which allows you to manage multiple environments and multiple teams, as well as their permissions and authorization in a robust way. +QHub is entirely controlled from a configuration file, which allows you to manage multiple environments and multiple teams, as well as their permissions and authorization in a +robust way. -+ **The Configuration File** - + QHub comes with configuration file templates for each of the cloud providers it currently supports: **AWS**, **DO**, **GCP**, and **Azure**. The templates can be found [**here**](../installation/configuration.md). - + You can create a simple qhub-config.yaml configuration panel as a starting point using the `qhub init` command as [described here](../installation/usage.md). +- **The Configuration File** + - QHub comes with configuration file templates for each of the cloud providers it currently supports: **AWS**, **DO**, **GCP**, and **Azure**. The templates can be found + [**here**](../installation/configuration.md). + - You can create a simple qhub-config.yaml configuration panel as a starting point using the `qhub init` command as [described here](../installation/usage.md). ## Why QHub -With QHub, managing configurable data science environments and attaining seamless deployment with [**Github Actions**](https://github.com/marketplace/actions/deployment-action) become remarkably easy. Let's look at how you can customize QHub for a data science architecture that meets **your team's needs**. +With QHub, managing configurable data science environments and attaining seamless deployment with [**Github Actions**](https://github.com/marketplace/actions/deployment-action) +become remarkably easy. Let's look at how you can customize QHub for a data science architecture that meets **your team's needs**. ## Staging & Production Environments and Shell Access -With QHub, you can have shell access and remote editing access through KubeSSH. The complete linux style permissions allows for different shared folders for different groups of users. +With QHub, you can have shell access and remote editing access through KubeSSH. The complete linux style permissions allows for different shared folders for different groups of +users. QHub comes with staging and production environments, as well as JupyterHub deploys. ## QHub Architecture - In addition to a robust integration of [**Dask**](https://dask.org/) and a new way of distributing environments with [**conda-store**](https://github.com/quansight/conda-store), QHub brings together some of the widely used cloud deployment components in its architecture. +In addition to a robust integration of [**Dask**](https://dask.org/) and a new way of distributing environments with [**conda-store**](https://github.com/quansight/conda-store), +QHub brings together some of the widely used cloud deployment components in its architecture. - QHub integrates [**Network File System (NFS)**](https://en.wikipedia.org/wiki/Network_File_System) protocol is used to allow Kubernetes applications to access storage. Files in containers in a [**Kubernetes Pod**](https://kubernetes.io/docs/concepts/workloads/pods/pod/) are not persistent, which means if a container crashes, [**kubelet**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/#:~:text=Synopsis,object%20that%20describes%20a%20pod) will restart the container, however, the files will not be preserved. The [**Kubernetes Volume**](https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes) abstraction that QHub utilizes solves this problem. +QHub integrates [**Network File System (NFS)**](https://en.wikipedia.org/wiki/Network_File_System) protocol is used to allow Kubernetes applications to access storage. Files in +containers in a [**Kubernetes Pod**](https://kubernetes.io/docs/concepts/workloads/pods/pod/) are not persistent, which means if a container crashes, +[**kubelet**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/#:~:text=Synopsis,object%20that%20describes%20a%20pod) will restart the container, however, +the files will not be preserved. The [**Kubernetes Volume**](https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes) abstraction that QHub utilizes solves this +problem. -NFS shares files directly from a container in a Kubernetes Pod, and sets up a [**Kubernetes Persistent Volume**](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) accessed via NFS. Kubernetes' built‑in configuration for HTTP load balancing [**Ingress**](https://kubernetes.io/docs/concepts/services-networking/ingress/) defines and controls the rules for external connectivity to Kubernetes services. Users who need to provide external access to their Kubernetes services create an Ingress resource that defines rules. +NFS shares files directly from a container in a Kubernetes Pod, and sets up a [**Kubernetes Persistent Volume**](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) +accessed via NFS. Kubernetes' built‑in configuration for HTTP load balancing [**Ingress**](https://kubernetes.io/docs/concepts/services-networking/ingress/) defines and controls +the rules for external connectivity to Kubernetes services. Users who need to provide external access to their Kubernetes services create an Ingress resource that defines rules. QHub streamlines and manages all the Kubernetes architecture detailed above and delivers a smooth deployment process to its users through its intuitive interface. ![QHub_Architecture](../images/high_level_architecture.png) QHub architecture and features allows you to: -+ manage configurable data science environments +- manage configurable data science environments -+ handle multiple environments in a robust way +- handle multiple environments in a robust way -+ have seamless deployment with github actions +- have seamless deployment with github actions -+ meet the needs of multiple teams and control permissions +- meet the needs of multiple teams and control permissions ## Cloud Deployment on QHub -QHub deployments on the clouds follow the architectural structure shown for each provider in the diagrams below. To make cloud deployments, the respective configuration file needs to be configured based on the user's cloud provider account credentials, as well as the details of users they would allow access to the deployment. +QHub deployments on the clouds follow the architectural structure shown for each provider in the diagrams below. To make cloud deployments, the respective configuration file needs +to be configured based on the user's cloud provider account credentials, as well as the details of users they would allow access to the deployment. ### Infrastructure Provisioning (Common for all Clouds) -To provision the infrastructure, QHub uses [**Terraform**](https://www.terraform.io/), a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform enables QHub to have Infrastructure as Code to provision and manage cloud, infrastructure or service. Terraform has a system of modules/provider for dealing with various cloud providers and various kinds of infrastructure, for instance it has modules for [**Amazon Web Services (AWS)**](https://aws.amazon.com/), [**Google Cloud Platform (GCP)**](https://cloud.google.com/gcp/?utm_source=google&utm_medium=cpc&utm_campaign=na-US-all-en-dr-bkws-all-all-trial-e-dr-1009135&utm_content=text-ad-lpsitelinkCCexp2-any-DEV_c-CRE_113120492887-ADGP_Hybrid+%7C+AW+SEM+%7C+BKWS+%7C+US+%7C+en+%7C+EXA+~+Google+Cloud+Platform-KWID_43700009942847400-kwd-26415313501&utm_term=KW_google%20cloud%20platform-ST_google+cloud+platform&gclid=CjwKCAjw9vn4BRBaEiwAh0muDLoAixDimMW9Sq12jfyBy6dMzxOU7ZW6-w44qWTJo-zRdpnBojzbexoCNGsQAvD_BwE), [**Digital Ocean (DO)**](https://www.digitalocean.com/), as well as for [**Kubernetes**](https://kubernetes.io/) and [**Helm**](https://helm.sh/). +To provision the infrastructure, QHub uses [**Terraform**](https://www.terraform.io/), a tool for building, changing, and versioning infrastructure safely and efficiently. +Terraform enables QHub to have Infrastructure as Code to provision and manage cloud, infrastructure or service. Terraform has a system of modules/provider for dealing with various +cloud providers and various kinds of infrastructure, for instance it has modules for [**Amazon Web Services (AWS)**](https://aws.amazon.com/), +[**Google Cloud Platform (GCP)**](https://cloud.google.com/gcp/?utm_source=google&utm_medium=cpc&utm_campaign=na-US-all-en-dr-bkws-all-all-trial-e-dr-1009135&utm_content=text-ad-lpsitelinkCCexp2-any-DEV_c-CRE_113120492887-ADGP_Hybrid+%7C+AW+SEM+%7C+BKWS+%7C+US+%7C+en+%7C+EXA+~+Google+Cloud+Platform-KWID_43700009942847400-kwd-26415313501&utm_term=KW_google%20cloud%20platform-ST_google+cloud+platform&gclid=CjwKCAjw9vn4BRBaEiwAh0muDLoAixDimMW9Sq12jfyBy6dMzxOU7ZW6-w44qWTJo-zRdpnBojzbexoCNGsQAvD_BwE), +[**Digital Ocean (DO)**](https://www.digitalocean.com/), as well as for [**Kubernetes**](https://kubernetes.io/) and [**Helm**](https://helm.sh/). ### Kubernetes (Common for all Clouds) -To manage the deployments on the Kubernetes cluster, QHub uses Helm, a package manager for Kubernetes. Helm packages Kubernetes configurations for deployment for ease of distribution so that you can simply use a ready made package and deploy it to your Kubernetes cluster. +To manage the deployments on the Kubernetes cluster, QHub uses Helm, a package manager for Kubernetes. Helm packages Kubernetes configurations for deployment for ease of +distribution so that you can simply use a ready made package and deploy it to your Kubernetes cluster. -The services are exposed via an [**Ingress**](https://kubernetes.io/docs/concepts/services-networking/ingress/) component of Kubernetes. Helm uses a packaging format called [**Charts**](https://helm.sh/docs/topics/charts/), which is a collection of files that describe a related set of Kubernetes resources. Charts can be packaged into versioned archives to be deployed. They are also easy to rollback. +The services are exposed via an [**Ingress**](https://kubernetes.io/docs/concepts/services-networking/ingress/) component of Kubernetes. Helm uses a packaging format called +[**Charts**](https://helm.sh/docs/topics/charts/), which is a collection of files that describe a related set of Kubernetes resources. Charts can be packaged into versioned +archives to be deployed. They are also easy to rollback. -The [**Helm provider of Terraform**](https://github.com/hashicorp/terraform-provider-helm) takes the overrides supported by Helm. This makes it easier to use a standard chart with custom settings, such as a custom image. +The [**Helm provider of Terraform**](https://github.com/hashicorp/terraform-provider-helm) takes the overrides supported by Helm. This makes it easier to use a standard chart with +custom settings, such as a custom image. -For JupyterHub and Dask, QHub uses the official Helm Charts and provide custom settings, which can be seen in: `dask-gateway.yaml` and `jupyterhub.yaml`, also with custom images, which are stored in respective container registry of the cloud provider uses. +For JupyterHub and Dask, QHub uses the official Helm Charts and provide custom settings, which can be seen in: `dask-gateway.yaml` and `jupyterhub.yaml`, also with custom images, +which are stored in respective container registry of the cloud provider uses. ### SSL and Ingress (Common for all Clouds) -To expose various services, such as the JupyterHub and Dask, present in the Kubernetes Cluster, QHub uses [Traefik Proxy](https://traefik.io/traefik/) which is a reverse proxy and load balancer. - -[**SSL**](https://www.ssl.com/faqs/faq-what-is-ssl/) is a crucial part of any service exposed to the Internet. To handle this in Kubernetes, QHub utilizes [**cert manager**](https://github.com/jetstack/cert-manager), a popular Kubernetes add-on to automate the management and issuance of TLS certificates from various issuing sources. +To expose various services, such as the JupyterHub and Dask, present in the Kubernetes Cluster, QHub uses [Traefik Proxy](https://traefik.io/traefik/) which is a reverse proxy and +load balancer. +[**SSL**](https://www.ssl.com/faqs/faq-what-is-ssl/) is a crucial part of any service exposed to the Internet. To handle this in Kubernetes, QHub utilizes +[**cert manager**](https://github.com/jetstack/cert-manager), a popular Kubernetes add-on to automate the management and issuance of TLS certificates from various issuing sources. ### AWS Cloud Architecture -The architecture of AWS uses [**Virtual Private Cloud (VPC)**](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html), which enables you to launch resources into a virtual network. The VPC is the logically isolated section of AWS, which enables you to control how your network and AWS resources inside your network are exposed to the Internet. There are subnets inside the VPC in multiple availability zones. The Kubernetes Cluster is inside the VPC, which by default isolates it from the internet by the very nature of VPC. - -QHub uses AWS’s managed Kubernetes service: [**Elastic Kubernetes Service (EKS)**](https://aws.amazon.com/eks/) to create a Kubernetes Cluster. Since VPC is an isolated part of the AWS, you need a way to expose the services running inside the Kubernetes to the Internet, so that others can access it. This is achieved by an [**Internet Gateway**](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html). It’s a VPC component that allows communication between the VPC and the Internet. +The architecture of AWS uses [**Virtual Private Cloud (VPC)**](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html), which enables you to launch resources into +a virtual network. The VPC is the logically isolated section of AWS, which enables you to control how your network and AWS resources inside your network are exposed to the +Internet. There are subnets inside the VPC in multiple availability zones. The Kubernetes Cluster is inside the VPC, which by default isolates it from the internet by the very +nature of VPC. +QHub uses AWS’s managed Kubernetes service: [**Elastic Kubernetes Service (EKS)**](https://aws.amazon.com/eks/) to create a Kubernetes Cluster. Since VPC is an isolated part of the +AWS, you need a way to expose the services running inside the Kubernetes to the Internet, so that others can access it. This is achieved by an +[**Internet Gateway**](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html). It’s a VPC component that allows communication between the VPC and the Internet. ### Autoscaling -With QHub, system admins can customize and maintain their teams' compute needs and environments. The autoscaling of computers (Kubernetes and Pods) is done through Dask autoscaling with CPU & GPU workers. +With QHub, system admins can customize and maintain their teams' compute needs and environments. The autoscaling of computers (Kubernetes and Pods) is done through Dask autoscaling +with CPU & GPU workers. ### Authentication diff --git a/docs/source/dev_guide/changelog.md b/docs/source/dev_guide/changelog.md index 2eedccf1b..ede2feeac 100644 --- a/docs/source/dev_guide/changelog.md +++ b/docs/source/dev_guide/changelog.md @@ -1,2 +1,2 @@ ```{include} ../../../RELEASE.md -``` \ No newline at end of file +``` diff --git a/docs/source/dev_guide/contribution.md b/docs/source/dev_guide/contribution.md index 4eba29a85..0f5dae949 100644 --- a/docs/source/dev_guide/contribution.md +++ b/docs/source/dev_guide/contribution.md @@ -6,15 +6,10 @@ Please see [QHub Contribution Guidelines](https://github.com/Quansight/qhub/blob ## Adding new Integration and Features to Qhub -The preferred way to add new features/integrations to the -`qhub-config.yaml` is via a new key as a namespace. If the new -integration requires multiple `images` then use `images` otherwise use -`image`. Additionally `enabled` key determines is the feature is -enabled or disabled. Ensure that the configuration options are in -[qhub/schema.py](https://github.com/Quansight/qhub/blob/main/qhub/schema.py). Additionally -the configuration documentation in Qhub must reflect the -configuration. At a minimum the new feature should also be detailed in -the administration guide and user guide. +The preferred way to add new features/integrations to the `qhub-config.yaml` is via a new key as a namespace. If the new integration requires multiple `images` then use `images` +otherwise use `image`. Additionally `enabled` key determines is the feature is enabled or disabled. Ensure that the configuration options are in +[qhub/schema.py](https://github.com/Quansight/qhub/blob/main/qhub/schema.py). Additionally the configuration documentation in Qhub must reflect the configuration. At a minimum the +new feature should also be detailed in the administration guide and user guide. ```yaml : diff --git a/docs/source/dev_guide/keycloak.md b/docs/source/dev_guide/keycloak.md index e257140e9..0d564b577 100644 --- a/docs/source/dev_guide/keycloak.md +++ b/docs/source/dev_guide/keycloak.md @@ -44,18 +44,18 @@ The `users` group also needs to be configured so that it is a default group assi Within the qhub realm, you will create a new client. Within QHub, a separate client exists for each of jupyterhub, conda-store, dask etc. In the side nav, click `Clients`, then click the `Create` button. Fill out the form as show below: -| Form field | Value | +| Form field | Value | | --------------- | -------------- | -| Client ID | myclient | +| Client ID | myclient | | Client Protocol | openid-connect | After clicking `Save`, you will be taken to the client settings form. Make sure the form fields are filled in as follows: **Settings tab:** -| Setting | Value | +| Setting | Value | | ------------------- | ------------------------------------ | -| Access Type | confidential | +| Access Type | confidential | | Valid Redirect URIs | http://localhost:7010/oauth_callback | > The redirect URI you use here will depend on how you want to test OAuth2 login flows. The example above would make sense if you are running your OAuth2 client (e.g. JupyterHub or @@ -63,20 +63,20 @@ After clicking `Save`, you will be taken to the client settings form. Make sure > > If you plan to test using Postman (see below) the callback will be `https://oauth.pstmn.io/v1/browser-callback`. -You will next create a new mapper for the myclient client. Go to the `Mapper` tab and click the `Create` button. Make sure the form is filled out as shown below and then click the -`Save` button. +You will next create a new mapper for the `myclient` client. Go to the `Mapper` tab and click the `Create` button. Make sure the form is filled out as shown below and then click +the `Save` button. **Mappers (create):** -| Name | Value | +| Name | Value | | ------------------- | ---------------- | -| Name | groups | -| Mapper Type | Group Membership | -| Token Claim Name | groups | -| Full group path | OFF | -| Add to ID token | OFF | -| Add to access token | OFF | -| Add to userinfo | ON | +| Name | groups | +| Mapper Type | Group Membership | +| Token Claim Name | groups | +| Full group path | OFF | +| Add to ID token | OFF | +| Add to access token | OFF | +| Add to userinfo | ON | **Update: You may also want to set mappers for roles, which are now used for conda-store and dask.** @@ -88,7 +88,7 @@ In Keycloak, go to `Users` in the side nav and click `Add user`. Give the user a the `Credentials` tab, toggle off the `Temporary` field, and set a password for your user (we will assume `quser` for the password). In order for your new user to access the Qhub control panel, they must belong to the admin group. Go to `Users` in the side nav, click `View all users`, find your user, then click -`Edit` under the `Actions` column. Go to the `Groups` tab for Quser. Under `Available Groups`, you should see `admin`. Click on `admin` then click `Join`. You should see the +`Edit` under the `Actions` column. Go to the `Groups` tab for `quser`. Under `Available Groups`, you should see `admin`. Click on `admin` then click `Join`. You should see the `Group Membership` box update with `/admin`. ## Understanding JupyterHub OAuth2 diff --git a/docs/source/dev_guide/logo.md b/docs/source/dev_guide/logo.md index 80dd95eb8..884b63ab3 100644 --- a/docs/source/dev_guide/logo.md +++ b/docs/source/dev_guide/logo.md @@ -1,13 +1,19 @@ # Logos and Icons ## Quansight + ### logo solid white background -![logo transparent background](../images/quansight_logo_white.png) ---- + +## ![logo transparent background](../images/quansight_logo_white.png) + ## Quansight Labs + ### Logo solid white background -![logo solid background](../images/labs_logo_white.png) ---- + +## ![logo solid background](../images/labs_logo_white.png) + ## Qhub Cloud + ### transparent background + ![logo transparent background](../images/qhub_logo.png) diff --git a/docs/source/dev_guide/minikube.md b/docs/source/dev_guide/minikube.md index bc2b7ed11..c9e6b5318 100644 --- a/docs/source/dev_guide/minikube.md +++ b/docs/source/dev_guide/minikube.md @@ -4,13 +4,15 @@ It's possible to run QHub on Minikube, and this can allow quicker feedback loops for development, as well as being less expensive than running cloud Kubernetes clusters. -Local testing is a great way to test the components of QHub. It's important to highlight that while it's possible to test most of QHub with this version, components that are Cloud provisioned such as VPCs, managed Kubernetes cluster and managed container registries can't be locally tested, due to their Cloud dependencies. +Local testing is a great way to test the components of QHub. It's important to highlight that while it's possible to test most of QHub with this version, components that are Cloud +provisioned such as VPCs, managed Kubernetes cluster and managed container registries can't be locally tested, due to their Cloud dependencies. ## Compatibility -Currently, **QHub local deployment is primarily compatible with Linux-based Operating Systems**. The main limitation for the installation on -MacOS relates to [Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/networking/#known-limitations-use-cases-and-workarounds) -being unable to route traffic to containers. Theoretically, the installation of HyperKit Driver could solve the issue, although the proposed solution isn't tested. There some workarounds for running [Minikube on Mac below](#minikube-on-mac). +Currently, **QHub local deployment is primarily compatible with Linux-based Operating Systems**. The main limitation for the installation on MacOS relates to +[Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/networking/#known-limitations-use-cases-and-workarounds) being unable to route traffic to containers. Theoretically, +the installation of HyperKit Driver could solve the issue, although the proposed solution isn't tested. There some workarounds for running +[Minikube on Mac below](#minikube-on-mac). This guide assumes that you have the QHub repository downloaded, and you are at the root of the repository. @@ -25,9 +27,8 @@ To deploy QHub locally requires the installation of the following dependencies: The installation of a hypervisor isn't necessary. -> NOTE: Minikube requires `kubectl` OR you can use the embedded kubectl appropriate for your Minikube cluster version using `minikube kubectl`. -> To install `kubectl` [follow the instructions](https://kubernetes.io/docs/tasks/tools/) according to your operating system. - +> NOTE: Minikube requires `kubectl` OR you can use the embedded kubectl appropriate for your Minikube cluster version using `minikube kubectl`. To install `kubectl` +> [follow the instructions](https://kubernetes.io/docs/tasks/tools/) according to your operating system. ## Initialize Kubernetes cluster @@ -38,8 +39,8 @@ Testing is done with Minikube. To confirm successful installation of both Docker ```shell minikube start --cpus 2 --memory 4096 --driver=docker ``` -The command downloads a Docker image of around 500Mb in size and initialise a cluster with 2 CPUs and 4 GB of RAM, with Docker as the chosen driver. +The command downloads a Docker image of around 500Mb in size and initialise a cluster with 2 CPUs and 4 GB of RAM, with Docker as the chosen driver. Once `minikube start` finishes, run the command below to select the status of the cluster: @@ -47,8 +48,7 @@ Once `minikube start` finishes, run the command below to select the status of th minikube status ``` -If your cluster is running, the output from minikube status should be -similar to: +If your cluster is running, the output from minikube status should be similar to: ```bash minikube @@ -81,7 +81,8 @@ For more details on PVs and PVCs, read the [JupyterHub documentation](https://ze ### Why pre-pull Docker images -As part of deployment, Minikube downloads Docker images that have a combined size of several Gigabytes. Each time minikube is destroyed and created it re-pulls these images. Also, Terraform times out on slower internet connections if it takes longer than 10 minutes to pull the images. +As part of deployment, Minikube downloads Docker images that have a combined size of several Gigabytes. Each time minikube is destroyed and created it re-pulls these images. Also, +Terraform times out on slower internet connections if it takes longer than 10 minutes to pull the images. Images can be pre-pulled and added to the Minikube cache. This greatly reduce the time required for future deployments and reduces the data requiring download during deployment. @@ -119,7 +120,6 @@ The preceding process is repeated with the updated tags when a new version of QH - ## MetalLB [MetalLB](https://metallb.universe.tf/) is the load balancer for bare-metal Kubernetes clusters. The user needs to configure MetalLB to match the QHub configuration. @@ -128,10 +128,11 @@ The preceding process is repeated with the updated tags when a new version of QH *Skip to next section for configuration without Python* -Minikube doesn't provide a simple interactive way to configure addons, ([as shown in this repository issue](https://github.com/kubernetes/minikube/issues/8283)). It's recommended to set load balancer start/stop IP address using a Python script with pre-established values. This recommendation is due to an existing DNS name that uses some addresses. +Minikube doesn't provide a simple interactive way to configure addons, ([as shown in this repository issue](https://github.com/kubernetes/minikube/issues/8283)). It's recommended +to set load balancer start/stop IP address using a Python script with pre-established values. This recommendation is due to an existing DNS name that uses some addresses. -To do so, paste -[this Python script](https://github.com/Quansight/qhub/blob/main/tests/scripts/minikube-loadbalancer-ip.py) in a text file named `minikube-loadbalancer-ip.py` and then run: +To do so, paste [this Python script](https://github.com/Quansight/qhub/blob/main/tests/scripts/minikube-loadbalancer-ip.py) in a text file named `minikube-loadbalancer-ip.py` and +then run: ```shell python minikube-loadbalancer-ip.py @@ -154,7 +155,9 @@ Copy the output image id and use it in the following command to obtain the Docke $ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}/{{.IPPrefixLen}}{{end}}' ``` -A example subnet range looks like `192.168.49.2/24`. This CIDR range has a starting IP of `192.168.49.0` and ending address of `192.168.49.255`. The `metallb` load balancer is provided a range of IP addresses contained in the Docker CIDR range. If your CIDR is different, you can determine your range IP addresses from a CIDR address at [this website](https://www.ipaddressguide.com/cidr). +A example subnet range looks like `192.168.49.2/24`. This CIDR range has a starting IP of `192.168.49.0` and ending address of `192.168.49.255`. The `metallb` load balancer is +provided a range of IP addresses contained in the Docker CIDR range. If your CIDR is different, you can determine your range IP addresses from a CIDR address at +[this website](https://www.ipaddressguide.com/cidr). For this example case, the user assigns `metallb` a start IP address of `192.168.49.100` and an end of `192.168.49.150`. @@ -171,31 +174,40 @@ If successful, the output should be `✅ metallb was successfully configured`. ### Enable MetalLB After configuration enable MetalLB by running + ```shell minikube addons enable metallb ``` + The output should be `The 'metallb' addon is enabled`. ---- +______________________________________________________________________ ## Note for development on Windows Subsystem for Linux 2
Click to expand note -The browser can have trouble reaching the load balancer running on WSL2. A workaround is to port forward the proxy-pod to the host IP 0.0.0.0. Get the ip address of the WSL2 machine via ```ip a```, which should be a 127.x.x.x address. To change the port forwarding after opening `k9s` you can type ```:pods ```, hover over the proxy-... pod and type ``````, and enter the IP addresses. +The browser can have trouble reaching the load balancer running on WSL2. A workaround is to port forward the proxy-pod to the host IP 0.0.0.0. Get the ip address of the WSL2 +machine via `ip a`, which should be a 127.x.x.x address. To change the port forwarding after opening `k9s` you can type `:pods `, hover over the proxy-... pod and type +``, and enter the IP addresses.
## Deploy QHub + To deploy QHub handle setup dependencies and create a new sub-directory by running: + ```bash pip install -e . mkdir -p data cd data ``` + ## Initialize configuration + Then, initialize the configuration file `qhub-config.yaml` with: + ```shell python -m qhub init local --project=thisisatest --domain github-actions.qhub.dev --auth-provider=password --terraform-state=local ``` @@ -208,10 +220,11 @@ Next, the user renders the infrastructure files from `qhub-config.yaml` running. python -m qhub deploy --config qhub-config.yaml --disable-prompt ``` -To ease development, the DNS record `github-actions.qhub.dev` is pointed to `192.168.49.100` so the next step is optional unless you end up with the load-balancer giving you a different IP address. +To ease development, the DNS record `github-actions.qhub.dev` is pointed to `192.168.49.100` so the next step is optional unless you end up with the load-balancer giving you a +different IP address. -Make sure to point the DNS domain `github-actions.qhub.dev` to `192.168.49.100` from the previous commands. This is done in many -ways, the easiest one is by modifying `/etc/hosts` and adding the line below. The command overrides any DNS server. +Make sure to point the DNS domain `github-actions.qhub.dev` to `192.168.49.100` from the previous commands. This is done in many ways, the easiest one is by modifying `/etc/hosts` +and adding the line below. The command overrides any DNS server. ```ini 192.168.49.100 github-actions.qhub.dev @@ -227,7 +240,8 @@ curl -k https://github-actions.qhub.dev/hub/login It's also possible to visit `https://github-actions.qhub.dev` in your web browser to select the deployment. -Since this is a local deployment, hence it's not visible to the internet; `https` certificates isn't signed by [Let's Encrypt](https://letsencrypt.org/). Thus, the certificates is [self-signed by Traefik](https://en.wikipedia.org/wiki/Self-signed_certificate). +Since this is a local deployment, hence it's not visible to the internet; `https` certificates isn't signed by [Let's Encrypt](https://letsencrypt.org/). Thus, the certificates is +[self-signed by Traefik](https://en.wikipedia.org/wiki/Self-signed_certificate). Several browsers makes it difficult to view a self-signed certificate that's not added to the certificate registry. @@ -237,11 +251,13 @@ Each web browser handles this differently. A workaround for Firefox: And a workaround for Chrome: -- Type `badidea` or `thisisunsafe` while viewing the rendered page (this has to do with [how Chrome preloads some domains for its HTTP Strict Transport Security](https://hstspreload.org/) list in a way that can't be manually removed) +- Type `badidea` or `thisisunsafe` while viewing the rendered page (this has to do with + [how Chrome preloads some domains for its HTTP Strict Transport Security](https://hstspreload.org/) list in a way that can't be manually removed) ## Cleanup -To delete all the QHub resources run the `destroy` command. Note that this won't delete your `qhub-config.yaml` and related rendered files thus a re-deployment via `deploy` is possible afterwards. +To delete all the QHub resources run the `destroy` command. Note that this won't delete your `qhub-config.yaml` and related rendered files thus a re-deployment via `deploy` is +possible afterwards. ```shell python -m qhub destroy --config qhub-config.yaml @@ -252,15 +268,17 @@ To delete the Minikube Kubernetes cluster run the following command: ```shell minikube delete ``` + The command deletes all instances of QHub, cleaning up the deployment environment. ---- +______________________________________________________________________ # Minikube on Mac The earlier instructions for Minikube on Linux _nearly_ works on Mac except things that break without clever use of port forwarding at the right times. 1 - When working out the IP addresses to configure metallb try this: + ``` docker ps --format "{{.Names}} {{.ID}}" docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}/{{.IPPrefixLen}}{{end}}' @@ -269,23 +287,29 @@ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}/{{.IP This displays something like `192.168.49.2/24`, in which case a suitable IP range would be on the same subnet, for example start IP 192.168.49.100, end IP 192.168.49.150. 2 - This load balancer won't actually work, so you need to port-forward directly to the JupyterHub service: + ``` minikube kubectl -- --namespace=dev port-forward svc/proxy-public 8000:80 ``` + Then you could access QHub on http://127.0.0.1:8000/ -3 - However, the `qhub deploy` step needs to communicate with the Keycloak server, but this isn't possible -without the correct hostname. +3 - However, the `qhub deploy` step needs to communicate with the Keycloak server, but this isn't possible without the correct hostname. -It might be possible to set `/etc/hosts` to include `github-actions.qhub.dev` as they are done for the AWS minikube, below. And meanwhile use kubectl port-forward to actually forward the traffic (from port 443 to something similar?). But you'd have to start that forwarding at the right point in the deployment. (When Kubernetes is ready, but before terraform runs the Keycloak operator...) +It might be possible to set `/etc/hosts` to include `github-actions.qhub.dev` as they are done for the AWS minikube, below. And meanwhile use kubectl port-forward to actually +forward the traffic (from port 443 to something similar?). But you'd have to start that forwarding at the right point in the deployment. (When Kubernetes is ready, but before +terraform runs the Keycloak operator...) ---- +______________________________________________________________________ # Minikube on AWS -It's possible to run Minikube on AWS (and probably the other clouds). This is useful where you don't have enough memory to run QHub in a local Minikube cluster on your laptop, or if you are using Mac or Windows and struggling to get Minikube to work. +It's possible to run Minikube on AWS (and probably the other clouds). This is useful where you don't have enough memory to run QHub in a local Minikube cluster on your laptop, or +if you are using Mac or Windows and struggling to get Minikube to work. -Please understand that running Minikube on an AWS EC2 instance isn't the same as 'proper' deployment of QHub to AWS EKS (Kubernetes service). You might prefer Minikube on AWS over full AWS EKS deployment for testing purposes if you find Minikube easier to debug, cheaper to run, or if you want to replicate the Minikube setup directly - for example, if trying to fix the automated Cypress tests which use Minikube within a GitHub actions workflow. +Please understand that running Minikube on an AWS EC2 instance isn't the same as 'proper' deployment of QHub to AWS EKS (Kubernetes service). You might prefer Minikube on AWS over +full AWS EKS deployment for testing purposes if you find Minikube easier to debug, cheaper to run, or if you want to replicate the Minikube setup directly - for example, if trying +to fix the automated Cypress tests which use Minikube within a GitHub actions workflow. There are some tricks that can make allow Minikube on AWS to feel much like local Minikube for development. @@ -319,7 +343,8 @@ chmod 400 ~/.ssh/${MYKEYNAME}.pem ## Run the EC2 instance -The recommended image is an Ubuntu 20.04 with Docker installed. It's recommended to be to run on a 16 GB/4 Core image, and increase the EBS disk space to 48 GB or so, up from the standard 8 GB. +The recommended image is an Ubuntu 20.04 with Docker installed. It's recommended to be to run on a 16 GB/4 Core image, and increase the EBS disk space to 48 GB or so, up from the +standard 8 GB. ```bash aws ec2 run-instances --image-id ami-0cd5fb602c264fbd6 --instance-type t3a.xlarge --count 1 --key-name ${MYKEYNAME} --block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=48}' @@ -437,11 +462,13 @@ mkdir .minikube_remote ``` Copy these files from the remote instance (home folder): + - .minikube/ca.crt to .minikube_remote/ca.crt - .minikube/profiles/minikube/client.crt to .minikube_remote/client.crt - .minikube/profiles/minikube/client.key to .minikube_remote/client.key For example: + ```bash cd .minikube_remote scp -i ~/.ssh/${MYKEYNAME}.pem ubuntu@ec2-35-177-109-173.eu-west-2.compute.amazonaws.com:~/.minikube/ca.crt . @@ -481,7 +508,8 @@ Now SSH into the AWS instance, enabling port forwarding so you can access the Mi ssh -i ~/.ssh/${MYKEYNAME}.pem ubuntu@ec2-18-130-21-222.eu-west-2.compute.amazonaws.com -L 127.0.0.1:8443:192.168.49.2:8443 ``` -You should now find that `kubectl` and `k9` work for the Minikube cluster if you run them on your Mac. This can include `kubectl port-forward` to access Kubernetes services individually. +You should now find that `kubectl` and `k9` work for the Minikube cluster if you run them on your Mac. This can include `kubectl port-forward` to access Kubernetes services +individually. ## Access the full QHub website @@ -501,4 +529,5 @@ sudo ssh -i ~/.ssh/${MYKEYNAME}.pem ubuntu@ec2-35-177-109-173.eu-west-2.compute. This is executed with the `sudo` privileges because forwarding a low-numbered port, like 443, is not allowed otherwise. -Now you can access https://github-actions.qhub.dev/ in a browser and you should be able to use your QHub. You have to bypass the self-signed cert warnings though - see [verify the local deployment](#verify-the-local-deployment) for instructions. +Now you can access https://github-actions.qhub.dev/ in a browser and you should be able to use your QHub. You have to bypass the self-signed cert warnings though - see +[verify the local deployment](#verify-the-local-deployment) for instructions. diff --git a/docs/source/dev_guide/release.md b/docs/source/dev_guide/release.md index 7c6a6492e..99ec3c017 100644 --- a/docs/source/dev_guide/release.md +++ b/docs/source/dev_guide/release.md @@ -5,48 +5,55 @@ Although we do rely on end-to-end integration tests that run (in a private repo) on a weekly basis. This process is currently not fully integrated into the release process. Cloud providers to validate: - - [ ] `azure` - Azure - - [ ] `aws` - Amazon Web Services - - [ ] `do` - Digital Ocean - - [ ] `gcp` - Google Cloud Platform - - [ ] `local` - Existing Kubernetes Cluster / Minikube + +- `azure` - Azure +- `aws` - Amazon Web Services +- `do` - Digital Ocean +- `gcp` - Google Cloud Platform +- `local` - Existing Kubernetes Cluster / Minikube Authentication providers to validate: -- [ ] password -- [ ] GitHub -- [ ] Auth0 + +- password +- GitHub +- Auth0 CI/CD providers to validate: -- [ ] GitHub-Actions -- [ ] GitLab-CI + +- GitHub-Actions +- GitLab-CI Although some of the tasks listed below are tested during the end-to-end integration tests, many others still need to be tested manually. Validate the following services: -- [ ] Initialize `qhub-config.yaml` -- [ ] QHub deploy -- [ ] Commit to repo and use CI/CD to deploy -- [ ] Log into Keycloak as root user and add user -- [ ] Add user from command line, `qhub keycloak` -- [ ] Launch JupyterLab session with new user -- [ ] Launch dask-cluster and test auto-scaler -- [ ] Launch dask-gateway dashboard -- [ ] Launch conda-store and validate environments are available -- [ ] Launch basic CDS Dashboard -- [ ] Launch Grafana (validate SSO) -- [ ] Qhub destroy -- [ ] Test Qhub upgrade command to assert compatibility +- Initialize `qhub-config.yaml` +- QHub deploy +- Commit to repo and use CI/CD to deploy +- Log into Keycloak as root user and add user +- Add user from command line, `qhub keycloak` +- Launch JupyterLab session with new user +- Launch dask-cluster and test auto-scaler +- Launch dask-gateway dashboard +- Launch conda-store and validate environments are available +- Launch basic CDS Dashboard +- Launch Grafana (validate SSO) +- Qhub destroy +- Test Qhub upgrade command to assert compatibility ## Release After testing any release-candidates, to create an official release: -1. On the Conda-Forge [`qhub-dask-feedstock`](https://github.com/conda-forge/qhub-dask-feedstock) repo, update the `qhub-dask` version to match the version to be released. Detailed documentation for updating conda-forge packages can be found [here](https://conda-forge.org/docs/maintainer/updating_pkgs.html#updating-recipes). +1. On the Conda-Forge [`qhub-dask-feedstock`](https://github.com/conda-forge/qhub-dask-feedstock) repo, update the `qhub-dask` version to match the version to be released. Detailed + documentation for updating conda-forge packages can be found [here](https://conda-forge.org/docs/maintainer/updating_pkgs.html#updating-recipes). -2. On the GitHub repo homepage, select "Release" on the left-hand side and then click "Draft a new release". Add any breaking changes, features/improvements and bug fixes. Give it a title of `Release - //`. +2. On the GitHub repo homepage, select "Release" on the left-hand side and then click "Draft a new release". Add any breaking changes, features/improvements and bug fixes. Give it + a title of `Release - , ` (spelt out). Make sure to copy these notes over `RELEASE.md` and commit them before releasing. -3. When ready, create the new tag name and select branch from which the release will be created, then click "Publish release". This will automatically upload the new release to [PyPI](https://pypi.org/project/qhub/) and also automatically -trigger the all appropriate Docker images to be built, tagged, and pushed up to DockerHub. +3. When ready, create the new tag name and select branch from which the release will be created, then click "Publish release". This will automatically upload the new release to + [PyPI](https://pypi.org/project/qhub/) and also automatically trigger the all appropriate Docker images to be built, tagged, and pushed up to DockerHub. -4. Finally, when the new release is published on PyPI, it's time to release the package on Conda-Forge. On the Conda-Forge [`qhub-feedstock`](https://github.com/conda-forge/qhub-feedstock) repo, update the `qhub` version to match the version to be released as well any other related package information that needs updating. +4. Finally, when the new release is published on PyPI, it's time to release the package on Conda-Forge. On the Conda-Forge + [`qhub-feedstock`](https://github.com/conda-forge/qhub-feedstock) repo, update the `qhub` version to match the version to be released as well any other related package + information that needs updating. diff --git a/docs/source/dev_guide/testing.md b/docs/source/dev_guide/testing.md index eacadebcc..c965e36ed 100644 --- a/docs/source/dev_guide/testing.md +++ b/docs/source/dev_guide/testing.md @@ -8,16 +8,22 @@ To use qhub from a development branch such as `main` set the environment variabl export QHUB_GH_BRANCH=main ``` -Then `qhub init` will create a qhub-config.yaml containing, for example, `quansight/qhub-jupyterlab:main` which is the Docker image built based on the Dockerfiles specified in the main branch of the QHub repo (see below for more info on how these are specified). There is a GitHub workflow that will build these images and push to Docker Hub whenever a change is made to the relevant files on GitHub. +Then `qhub init` will create a qhub-config.yaml containing, for example, `quansight/qhub-jupyterlab:main` which is the Docker image built based on the Dockerfiles specified in the +main branch of the QHub repo (see below for more info on how these are specified). There is a GitHub workflow that will build these images and push to Docker Hub whenever a change +is made to the relevant files on GitHub. In addition, `qhub deploy` can use QHUB_GH_BRANCH to create GitHub/GitLab workflows which install the development branch of QHub for their own deploy steps. -If you want to use the development version of QHub for your init and deploy but want your resulting deployment to be based on a full release version, don't set the QHUB_GH_BRANCH environment variable. In that case, Docker tags and workflow `pip install qhub` commands will be based on the qhub version specified in the `qhub/version.py` file, but these tags and releases may not yet exist, -perhaps if the version has been updated to include a beta/dev component which has not been released. So you may need to manually modify the qhub-config.yaml to 'downgrade' the tags to a full release version. +If you want to use the development version of QHub for your init and deploy but want your resulting deployment to be based on a full release version, don't set the QHUB_GH_BRANCH +environment variable. In that case, Docker tags and workflow `pip install qhub` commands will be based on the qhub version specified in the `qhub/version.py` file, but these tags +and releases may not yet exist, perhaps if the version has been updated to include a beta/dev component which has not been released. So you may need to manually modify the +qhub-config.yaml to 'downgrade' the tags to a full release version. ### Kubernetes Version Check for Cloud Providers -When `qhub init ` is called, it checks that the `--kubernetes-version` provided is supported by the preferred cloud provider. This flag is optional and if not provided, the `kubernetes_version` is set to the most recent kubernetes version available. This is achieved by using the cloud provider's SDK which thus requires their appropriate credentials to be set. To get around this, simply set the `QHUB_K8S_VERSION` environment variable like so: +When `qhub init ` is called, it checks that the `--kubernetes-version` provided is supported by the preferred cloud provider. This flag is optional and if not +provided, the `kubernetes_version` is set to the most recent kubernetes version available. This is achieved by using the cloud provider's SDK which thus requires their appropriate +credentials to be set. To get around this, simply set the `QHUB_K8S_VERSION` environment variable like so: ``` export QHUB_K8S_VERSION=1.20 @@ -25,11 +31,9 @@ export QHUB_K8S_VERSION=1.20 ## Modifying Docker Images -All QHub docker images are located in [`qhub/templates/{{ -cookiecutter.repo_directory -}}/image/`](https://github.com/Quansight/qhub-cloud/tree/main/qhub/template/%7B%7B%20cookiecutter.repo_directory%20%7D%7D/image). You -can build any image locally. Additionally, on Pull Requests each -Docker-build will be tested. +All QHub docker images are located in +[`qhub/template/image`](https://github.com/Quansight/qhub/tree/main/qhub/template/image). +You can build any image locally. Additionally, on Pull Requests each Docker-build will be tested. ```shell docker build -f Dockerfile. . @@ -55,9 +59,13 @@ Then open the localhost (127.0.0.1) link that's in the terminal ## Linting Dockerfiles -To lint Dockerfiles, developers use a tool called [Hadolint](https://github.com/hadolint/hadolint). Hadolint is a Dockerfile linter that allows to discover issues with the Dockerfiles and recommends [best practices to be followed](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/). QHub CI automates Hadolint code reviews on every commit and pull request, reporting code style and error prone issues. +To lint Dockerfiles, developers use a tool called [Hadolint](https://github.com/hadolint/hadolint). Hadolint is a Dockerfile linter that allows to discover issues with the +Dockerfiles and recommends [best practices to be followed](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/). QHub CI automates Hadolint code reviews on +every commit and pull request, reporting code style and error prone issues. -To run Hadolint locally you can either install it locally or use a container image. Instructions are available on the [install documentation for HadoLint](https://github.com/hadolint/hadolint#install). The `.hadolint.yml` on the root directory defines the ignored rules. To run Hadolint on Dockerfiles run: +To run Hadolint locally you can either install it locally or use a container image. Instructions are available on the +[install documentation for HadoLint](https://github.com/hadolint/hadolint#install). The `.hadolint.yml` on the root directory defines the ignored rules. To run Hadolint on +Dockerfiles run: ```shell hadolint ./qhub/template/\{\{\ cookiecutter.repo_directory\ \}\}/image/Dockerfile.conda-store @@ -71,13 +79,16 @@ Hadolint will report `error`, `warning`, `info` and `style` while linting Docker ## Debug Kubernetes clusters -To debug Kubernetes clusters, checkout [`k9s`](https://k9scli.io/), a terminal-based UI that aims to simplify navigation, observation, and management of applications in Kubernetes. `k9s` continuously monitors Kubernetes clusters for changes and provides shortcut commands to interact with the observed resources becoming a fast way to review and resolve day-to-day issues in deployed clusters. +To debug Kubernetes clusters, checkout [`k9s`](https://k9scli.io/), a terminal-based UI that aims to simplify navigation, observation, and management of applications in Kubernetes. +`k9s` continuously monitors Kubernetes clusters for changes and provides shortcut commands to interact with the observed resources becoming a fast way to review and resolve +day-to-day issues in deployed clusters. -Installation can be done on a macOS, in Windows, and Linux and instructions are located [here](https://github.com/derailed/k9s). For more details on usage, review the [Troubleshooting documentation](https://docs.qhub.dev/en/stable/source/admin_guide/troubleshooting.html#debug-your-kubernetes-cluster). +Installation can be done on a macOS, in Windows, and Linux and instructions are located [here](https://github.com/derailed/k9s). For more details on usage, review the +[Troubleshooting documentation](https://docs.qhub.dev/en/stable/source/admin_guide/troubleshooting.html#debug-your-kubernetes-cluster). ## Cypress Tests -Cypress automates testing within a web browser environment. It's integrated into the GitHub Actions tests.yaml workflows in this repo, and you can also run it locally. To do so: +Cypress automates testing within a web browser environment. It's integrated into the GitHub Actions tests.yaml workflows in this repo, and you can also run it locally. To do so: ```shell cd tests_e2e @@ -90,7 +101,10 @@ export CYPRESS_EXAMPLE_USER_PASSWORD= npm run cypress:open ``` -The Base URL can point anywhere that should be accessible - it can be the URL of a QHub cloud deployment. The QHub Config Path should point to the associated yaml file for that site. Most importantly, the tests will inspect the yaml file to understand what tests are relevant. To start with, it checks security.authentication.type to determine what should be available on the login page, and how to test it. If the login type is 'password' then it uses the value in `CYPRESS_EXAMPLE_USER_PASSWORD` as the password (default username is `example-user` but this can be changed by setting `CYPRESS_EXAMPLE_USER_NAME`). +The Base URL can point anywhere that should be accessible - it can be the URL of a QHub cloud deployment. The QHub Config Path should point to the associated yaml file for that +site. Most importantly, the tests will inspect the yaml file to understand what tests are relevant. To start with, it checks security.authentication.type to determine what should +be available on the login page, and how to test it. If the login type is 'password' then it uses the value in `CYPRESS_EXAMPLE_USER_PASSWORD` as the password (default username is +`example-user` but this can be changed by setting `CYPRESS_EXAMPLE_USER_NAME`). The final command, in the preceding code-snippet, opens the Cypress UI where you can run the tests manually and see the actions in the browser. @@ -98,8 +112,8 @@ Note that tests are heavily state dependent, so any changes or use of the deploy ## Deployment and integration tests -Deployment and Integration testing makes it easier to test various features of deployed QHub on Minikube such as Dask Gateway, external integrations, state of the kubernetes cluster via -simple Python code. You can run the integration and deployment tests via the following command: +Deployment and Integration testing makes it easier to test various features of deployed QHub on Minikube such as Dask Gateway, external integrations, state of the kubernetes +cluster via simple Python code. You can run the integration and deployment tests via the following command: ```shell pytest tests_deployment/ -v @@ -107,15 +121,20 @@ pytest tests_deployment/ -v # Cloud Testing -Cloud testing on AWS, GCP, Azure, and Digital Ocean can be significantly more complicated and time consuming. But it's the only way to truly test the cloud deployments, including infrastructure, of course. To test on cloud Kubernetes, just deploy QHub in the normal way on those clouds, but using the [linked pip install](./index.md) of the QHub package. +Cloud testing on AWS, GCP, Azure, and Digital Ocean can be significantly more complicated and time consuming. But it's the only way to truly test the cloud deployments, including +infrastructure, of course. To test on cloud Kubernetes, just deploy QHub in the normal way on those clouds, but using the [linked pip install](./index.md) of the QHub package. -Even with the dev install of the qhub package, you may find that the deployed cluster doesn't actually reflect any development changes, for example to the Docker images for JupyterHub or JupyterLab. That will be because your qhub-config.yaml references fully released versions. See [Using a development branch](#using-a-development-branch) above for how to encourage the Docker images to be specified based on the latest development code. +Even with the dev install of the qhub package, you may find that the deployed cluster doesn't actually reflect any development changes, for example to the Docker images for +JupyterHub or JupyterLab. That will be because your qhub-config.yaml references fully released versions. See [Using a development branch](#using-a-development-branch) above for how +to encourage the Docker images to be specified based on the latest development code. You should always prefer the local testing when possible as it will be easier to debug, may be quicker to deploy, and is likely to be less expensive. # Docs testing -QHub uses [Vale](https://github.com/errata-ai/vale), a syntax-aware linter to lint documentation and recommend regions that needs improvement. Vale works with the [Google developer documentation style guide](https://developers.google.com/style), with specific configurations that are specific to Quansight. To test the documentation on the local machine, follow these steps: +QHub uses [Vale](https://github.com/errata-ai/vale), a syntax-aware linter to lint documentation and recommend regions that needs improvement. Vale works with the +[Google developer documentation style guide](https://developers.google.com/style), with specific configurations that are specific to Quansight. To test the documentation on the +local machine, follow these steps: - [Install Vale command-line tool](https://docs.errata.ai/vale/install). - Run Vale on the entire documentation source or a specific documentation piece. @@ -129,4 +148,10 @@ QHub uses [Vale](https://github.com/errata-ai/vale), a syntax-aware linter to li - Utilize the errors, warnings and the suggestions to make appropriate changes to the documentation. - In case of false positives, make appropriate changes to the Vale configurations hosted in the `tests/vale/styles` directory. -Vale runs on the GitHub Actions CI to automatically validate the documentation language. By default, Vale only checks the modified documentation to ensure that Vale doesn't generate a lot of noise over the Pull Requests. +Vale runs on the GitHub Actions CI to automatically validate the documentation language. By default, Vale only checks the modified documentation to ensure that Vale doesn't +generate a lot of noise over the Pull Requests. + +# Links Testing + +Make sure to add tests for any links present in error message displayed to the user. These tests +can be added easily here: `tests/test_links.py` diff --git a/docs/source/images/dev_postman_for_keycloak.png b/docs/source/images/dev_postman_for_keycloak.png index a361529ee66706765cc51629ef64a8471a01dcd7..04b37a972c2bffe404bada8bdb456786ae06f445 100644 GIT binary patch literal 277092 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

{+?7i1i_gZRvA3zwRcmsX>laJKj?Uz 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

  • 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 ZRvundm!h@#W-H*=eovphkKIEO{s-y@(Xs#l diff --git a/docs/source/installation/configuration.md b/docs/source/installation/configuration.md index 882db4b47..6ca8d1b86 100644 --- a/docs/source/installation/configuration.md +++ b/docs/source/installation/configuration.md @@ -1,7 +1,11 @@ # Advanced configuration -This is a page dedicated to the `qhub-config.yaml` file, the file that `qhub` uses to deploy and redeploy changes to your infrastructure. The `qhub-config.yaml` configuration file is split into several sections and in this page, we detail the requirements necessary for this YAML-formatted configuration file. In the [Usage](usage.md) section we covered how you can auto-generate this file using `qhub init` (and properly set options/flags and environment variables). -> NOTE: The configuration file is always validated by a [pydantic schema](https://pydantic-docs.helpmanual.io/) in [qhub/schema.py](https://github.com/Quansight/qhub/blob/main/qhub/schema.py) +This is a page dedicated to the `qhub-config.yaml` file, the file that `qhub` uses to deploy and redeploy changes to your infrastructure. The `qhub-config.yaml` configuration file +is split into several sections and in this page, we detail the requirements necessary for this YAML-formatted configuration file. In the [Usage](usage.md) section we covered how +you can auto-generate this file using `qhub init` (and properly set options/flags and environment variables). + +> NOTE: The configuration file is always validated by a [pydantic schema](https://pydantic-docs.helpmanual.io/) in +> [qhub/schema.py](https://github.com/Quansight/qhub/blob/main/qhub/schema.py) ## General @@ -12,32 +16,28 @@ provider: # determines the choice of cloud provider for the dep domain: "do.qhub.dev" # top level URL exposure to monitor JupyterLab ``` - - `project_name`: should be compatible with the Cloud provider naming - convention. Generally only use `A-Z`, `a-z`, `-`, and `_` - (see [Project Naming Conventions](usage.md#project-naming-convention) for more details). +- `project_name`: should be compatible with the Cloud provider naming convention. Generally only use `A-Z`, `a-z`, `-`, and `_` (see + [Project Naming Conventions](usage.md#project-naming-convention) for more details). + +- `namespace`: is used in combination with `project_name` to label resources. In addition `namespace` also determines the `namespace` that used when deploying kubernetes resources + for qhub. + + - Default value: `dev` - - `namespace`: is used in combination with `project_name` to label - resources. In addition `namespace` also determines the `namespace` - that used when deploying kubernetes resources for qhub. - - Default value: `dev` +- `provider`: possible values are - - `provider`: possible values are - - `do` for DigitalOcean - - `aws` for Amazon AWS - - `gcp` for Google Could Provider - - `azure` for Microsoft Azure - - `local` for a local or existing kubernetes deployment + - `do` for DigitalOcean + - `aws` for Amazon AWS + - `gcp` for Google Could Provider + - `azure` for Microsoft Azure + - `local` for a local or existing kubernetes deployment - - `domain`: is the top level URL to put JupyterLab and future - services under (such a monitoring). For example `qhub.dev` - would be the domain for JupyterHub to be exposed under. +- `domain`: is the top level URL to put JupyterLab and future services under (such a monitoring). For example `qhub.dev` would be the domain for JupyterHub to be exposed under. ## Continuous integration and continuous deployment -`ci_cd`: is optional and specifies the continuous integration and -continuous deployment framework to use. QHub uses infrastructure-as-code to allow developers and users of QHub to request change to the -environment via pull requests (PRs) which then get approved by administration. -You may configure CI/CD process to watch for pull-requests or commits on +`ci_cd`: is optional and specifies the continuous integration and continuous deployment framework to use. QHub uses infrastructure-as-code to allow developers and users of QHub to +request change to the environment via pull requests (PRs) which then get approved by administration. You may configure CI/CD process to watch for pull-requests or commits on specific branches. Currently CI/CD can be setup for either GitHub Actions or GitLab CI. ```yaml @@ -52,45 +52,32 @@ ci_cd: - echo "additional commands to run" ``` - - `type`: current supported CI providers are `github-actions` and `gitlab-ci` - - `branch`: branch to use to commit `qhub render` changes to - - `commit_render`: whether to commit the rendered changes back into the repo. Optional, defaults to `true`. - - `before_script`: optional script to run before CI starts QHub - infrastructure deployment. This is useful in cases that additional - setup is required for QHub to deploy the resources. Only supported - on `gitlab-ci` at the moment. - - `after_script`: optional script to run after CI ends QHub - infrastructure deployment. This is useful in cases to notify - resources of successful QHub deployment. Only supported on - `gitlab-ci` at the moment. - -If `ci_cd` is not supplied, no CI/CD will be auto-generated, however, -we advise employing an infrastructure-as-code approach. This allows teams -to more quickly modify their QHub deployment, empowering developers and -data sciencists to request the changes and have them approved by an -administrator. +- `type`: current supported CI providers are `github-actions` and `gitlab-ci` +- `branch`: branch to use to commit `qhub render` changes to +- `commit_render`: whether to commit the rendered changes back into the repo. Optional, defaults to `true`. +- `before_script`: optional script to run before CI starts QHub infrastructure deployment. This is useful in cases that additional setup is required for QHub to deploy the + resources. Only supported on `gitlab-ci` at the moment. +- `after_script`: optional script to run after CI ends QHub infrastructure deployment. This is useful in cases to notify resources of successful QHub deployment. Only supported on + `gitlab-ci` at the moment. + +If `ci_cd` is not supplied, no CI/CD will be auto-generated, however, we advise employing an infrastructure-as-code approach. This allows teams to more quickly modify their QHub +deployment, empowering developers and data sciencists to request the changes and have them approved by an administrator. ## Certificate -By default, to simplify initial deployment `qhub` uses traefik to -create a self-signed certificate. In order to create a certificate -that's signed so that web browsers don't throw errors we currently -support [Let's Encrypt](https://letsencrypt.org/). +By default, to simplify initial deployment `qhub` uses traefik to create a self-signed certificate. In order to create a certificate that's signed so that web browsers don't throw +errors we currently support [Let's Encrypt](https://letsencrypt.org/). ```yaml certificate: type: self-signed ``` -To use Let's Encrypt you must specify an email address that Let's -Encrypt will associate the generated certificate with and whether to -use the [staging -server](https://acme-staging-v02.api.letsencrypt.org/directory) or -[production -server](https://acme-v02.api.letsencrypt.org/directory). In general -you should use the production server, as seen below. -> NOTE: Let's Encrypt heavily rate limits their production endpoint and -> provisioning https certificates can often fail due to this limit. +To use Let's Encrypt you must specify an email address that Let's Encrypt will associate the generated certificate with and whether to use the +[staging server](https://acme-staging-v02.api.letsencrypt.org/directory) or [production server](https://acme-v02.api.letsencrypt.org/directory). In general you should use the +production server, as seen below. + +> NOTE: Let's Encrypt heavily rate limits their production endpoint and provisioning https certificates can often fail due to this limit. ```yaml certificate: @@ -101,10 +88,8 @@ certificate: Note the above snippet will already be present if you provided an `--ssl-cert-email` when you ran `qhub init`. -You may also supply a custom self-signed certificate and secret -key. Note that the kubernetes default namespace that QHub uses is -`dev`. Otherwise, it will be your `namespace` defined -in the `qhub-config.yaml`. +You may also supply a custom self-signed certificate and secret key. Note that the kubernetes default namespace that QHub uses is `dev`. Otherwise, it will be your `namespace` +defined in the `qhub-config.yaml`. ```yaml certificate: @@ -112,27 +97,31 @@ certificate: secret_name: ``` -To add the tls certificate to kubernetes run the following command -with existing files. +To add the tls certificate to kubernetes run the following command with existing files. ```shell kubectl create secret tls \ --namespace= \ --cert=path/to/cert/file --key=path/to/key/file ``` + > NOTE: the default kubernetes namespace that QHub uses is `dev`, however you can change the `namespace` key in the `qhub-config.yaml`. ### Wildcard certificates -Some of QHub services might require special subdomains under your certificate, Wildcard certificates allow you to secure all subdomains of a domain with a single certificate. Defining a wildcard certificate decreases the amount of CN names you would need to define under the certificate configuration and reduces the chance of generating a wrong subdomain. +Some of QHub services might require special subdomains under your certificate, Wildcard certificates allow you to secure all subdomains of a domain with a single certificate. +Defining a wildcard certificate decreases the amount of CN names you would need to define under the certificate configuration and reduces the chance of generating a wrong +subdomain. -> NOTE: It's not possible to request a double wildcard certificate for a domain (for example *.*.local.com). As a default behaviour of [Traefik](https://doc.traefik.io/traefik/https/tls/#default-certificate), if the Domain Name System (DNS) and Common Name (CN) name doesn't match, Traefik generates and uses a self-signed certificate. This may lead to some unexpected [TLS](https://www.internetsociety.org/deploy360/tls/basics) issues, so as alternative to including each specific domain under the certificate CN list, you may also define a wildcard certificate. +> NOTE: It's not possible to request a double wildcard certificate for a domain (for example *.*.local.com). As a default behaviour of +> [Traefik](https://doc.traefik.io/traefik/https/tls/#default-certificate), if the Domain Name System (DNS) and Common Name (CN) name doesn't match, Traefik generates and uses a +> self-signed certificate. This may lead to some unexpected [TLS](https://www.internetsociety.org/deploy360/tls/basics) issues, so as alternative to including each specific domain +> under the certificate CN list, you may also define a wildcard certificate. ## Security -This section walks through security and user authentication as it -relates to QHub deployments. There are a few different ways to handle -user authentication: +This section walks through security and user authentication as it relates to QHub deployments. There are a few different ways to handle user authentication: + - Auth0 - GitHub - Password @@ -147,16 +136,14 @@ security: client_secret: ``` -In previous QHub versions (prior to `v0.4.0`), users and groups were added directly into the `qhub-config.yaml`. Starting with `v0.4.0`, user and group management is handled by [Keycloak as described below](#keycloak). +In previous QHub versions (prior to `v0.4.0`), users and groups were added directly into the `qhub-config.yaml`. Starting with `v0.4.0`, user and group management is handled by +[Keycloak as described below](#keycloak). ### Omitting sensitive values -If you wish to avoid storing secrets etc. directly in the config yaml file you -can instead set the values in environment variables. This substitution is -triggered by setting config values to "QHUB_SECRET_" followed by the -environment variable name. For example, you could set the environment variables -"github_client_id" and "github_client_key" and write the following in your config -file: +If you wish to avoid storing secrets etc. directly in the config yaml file you can instead set the values in environment variables. This substitution is triggered by setting config +values to "QHUB_SECRET\_" followed by the environment variable name. For example, you could set the environment variables "github_client_id" and "github_client_key" and write the +following in your config file: ```yaml security: @@ -169,25 +156,20 @@ security: ### Authentication -`security.authentication` is for configuring the OAuth and GitHub -Provider, password based authentication, or custom -authentication. +`security.authentication` is for configuring the OAuth and GitHub Provider, password based authentication, or custom authentication. #### Auth0 based authentication -[Auth0](https://auth0.com/#!) can be used for authentication. While it -is not free, there is a reasonable free tier that allows deployment of -QHub clusters using many different social providers, passwordless, and -email based authentication methods. +[Auth0](https://auth0.com/#!) can be used for authentication. While it is not free, there is a reasonable free tier that allows deployment of QHub clusters using many different +social providers, passwordless, and email based authentication methods. -QHub has command line options for `qhub init` which automates the creation -Auth0 web app via: -`--auth-provider=auth0 --auth-auto-provision`. +QHub has command line options for `qhub init` which automates the creation Auth0 web app via: `--auth-provider=auth0 --auth-auto-provision`. -Otherwise here are docs on [creating an Auth0 Application](https://auth0.com/docs/applications). -Make sure to select `Regular Web Application`. Important to note is the `auth0_subdomain` field which must be only the `.auth0.com`. So for the following `qhub-dev.auth0.com` the subdomain would be `qhub-dev`. Note that all the usernames will be the email addresses of users (not usernames). -> NOTE: This is a different and distinct step from one outlined in the [Setup](setup.md#auth0) -stage. +Otherwise here are docs on [creating an Auth0 Application](https://auth0.com/docs/applications). Make sure to select `Regular Web Application`. Important to note is the +`auth0_subdomain` field which must be only the `.auth0.com`. So for the following `qhub-dev.auth0.com` the subdomain would be `qhub-dev`. Note that all the +usernames will be the email addresses of users (not usernames). + +> NOTE: This is a different and distinct step from one outlined in the [Setup](setup.md#auth0) stage. ```yaml security: @@ -201,9 +183,8 @@ security: #### GitHub based authentication -GitHub has instructions for [creating OAuth -applications](https://docs.github.com/en/developers/apps/creating-an-oauth-app). Note -that QHub usernames will be their GitHub usernames. +GitHub has instructions for [creating OAuth applications](https://docs.github.com/en/developers/apps/creating-an-oauth-app). Note that QHub usernames will be their GitHub +usernames. ```yaml security: @@ -216,7 +197,9 @@ security: #### Password based authentication -This is the simpliest authenication method. This just defers to however Keycloak is configured. That's also true for GitHub/Auth0 cases, except that for the single-sign on providers the deployment will also configure those providers in Keycloak to save manual configuration. But it's also possible to add GitHub, or Google etc, as an Identity Provider in Keycloak even if you formally select `password` authentication in the `qhub-config.yaml` file. +This is the simpliest authenication method. This just defers to however Keycloak is configured. That's also true for GitHub/Auth0 cases, except that for the single-sign on +providers the deployment will also configure those providers in Keycloak to save manual configuration. But it's also possible to add GitHub, or Google etc, as an Identity Provider +in Keycloak even if you formally select `password` authentication in the `qhub-config.yaml` file. ```yaml security: @@ -228,7 +211,8 @@ security: The `security.keycloak` section allows you to specify an initial password for the `root` user (to login at `https://myqhubsite.com/auth/admin/`) to manage your Keycloak database. -We strongly recommend changing this `initial_root_password` after your initial deployment and deleting this value from your `qhub-config.yaml`. Any changes to this value on the `qhub-config.yaml` after the initial deployment will have no affect. +We strongly recommend changing this `initial_root_password` after your initial deployment and deleting this value from your `qhub-config.yaml`. Any changes to this value on the +`qhub-config.yaml` after the initial deployment will have no affect. For more information on how to do this, see the ["Change Keycloak root password"](./login.md#change-keycloak-root-password) section. @@ -245,22 +229,19 @@ security: #### User and group management -Groups and users of QHub are all defined in Keycloak. As above, access Keycloak as the `root` user, noting that the `root` user is not actually a QHub user - you cannot access the main features of QHub such as JupyterLab with at user. It is only for Keycloak management. +Groups and users of QHub are all defined in Keycloak. As above, access Keycloak as the `root` user, noting that the `root` user is not actually a QHub user - you cannot access the +main features of QHub such as JupyterLab with at user. It is only for Keycloak management. Follow this links for more detailed information on [Keycloak user management](./login.md#add-user-using-keycloak-console) and [Keycloak group management](./login.md#groups). - ## Provider Infrastructure -Finally, the Kubernetes infrastructure deployment. Although -quite similar, each provider has a slightly different configuration. +Finally, the Kubernetes infrastructure deployment. Although quite similar, each provider has a slightly different configuration. -The following configuration sets up a kubernetes deployment with -autoscaling node groups. Depending on the cloud provider there might -be restrictions, which are detailed on each section. +The following configuration sets up a kubernetes deployment with autoscaling node groups. Depending on the cloud provider there might be restrictions, which are detailed on each +section. -For any of the providers (besides local), adding a node group is as -easy as the following: which adds a `high-memory` group: +For any of the providers (besides local), adding a node group is as easy as the following: which adds a `high-memory` group: ```yaml : @@ -273,45 +254,33 @@ easy as the following: which adds a `high-memory` group: ... ``` -> NOTE: For each provider, details such as **instance names**, **availability zones**, -and **Kubernetes versions** will be DIFFERENT. +> NOTE: For each provider, details such as **instance names**, **availability zones**, and **Kubernetes versions** will be DIFFERENT. ### Providers -To take advantage of the auto-scaling and dask-distributed computing capabilities, -QHub can be deployed on a handful of the most commonly used cloud providers. QHub -utilizes many of the resources these cloud providers have to offer, however, -at it's core, is the Kubernetes engine (or service). Each cloud provider has slightly -different ways Kubernetes is configured but fear not, all of this is handled by QHub. +To take advantage of the auto-scaling and dask-distributed computing capabilities, QHub can be deployed on a handful of the most commonly used cloud providers. QHub utilizes many +of the resources these cloud providers have to offer, however, at it's core, is the Kubernetes engine (or service). Each cloud provider has slightly different ways Kubernetes is +configured but fear not, all of this is handled by QHub. Listed below are the cloud providers QHub currently supports. -> NOTE: Many of the cloud providers regularly update their internal Kubernetes -> versions so if you wish to specify a particular version, please check the following -> resources. This is *completely optional* as QHub will, by default, select the most -> recent version available for your preferred cloud provider. -> [Digital Ocean](https://docs.digitalocean.com/products/kubernetes/changelog/) -> [Google Cloud Platform](https://cloud.google.com/kubernetes-engine/docs/release-notes-stable) +> NOTE: Many of the cloud providers regularly update their internal Kubernetes versions so if you wish to specify a particular version, please check the following resources. This +> is *completely optional* as QHub will, by default, select the most recent version available for your preferred cloud provider. +> [Digital Ocean](https://docs.digitalocean.com/products/kubernetes/changelog/) [Google Cloud Platform](https://cloud.google.com/kubernetes-engine/docs/release-notes-stable) > [Amazon Web Services](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html) > [Microsoft Azure](https://docs.microsoft.com/en-us/azure/aks/supported-kubernetes-versions?tabs=azure-cli) #### DigitalOcean -DigitalOcean has a restriction with autoscaling in that the minimum -nodes allowed (`min_nodes` = 1) is one but is by far the cheapest -provider even accounting for spot/preemptible instances. In addition -Digital Ocean doesn't have accelerator/gpu support. Digital Ocean is -a great default choice for tying out QHub. Below is the recommended -setup. +DigitalOcean has a restriction with autoscaling in that the minimum nodes allowed (`min_nodes` = 1) is one but is by far the cheapest provider even accounting for spot/preemptible +instances. In addition Digital Ocean doesn't have accelerator/gpu support. Digital Ocean is a great default choice for tying out QHub. Below is the recommended setup. -> NOTE: DigitalOcean regularly updates Kubernetes versions hence, the field `kubernetes_version` will most likely have to be changed. [See available instance types for DigitalOcean](https://www.digitalocean.com/docs/droplets/). -> If you used `qhub init` this version will automatically be computed for you. -> Do not copy the version you see below. +> NOTE: DigitalOcean regularly updates Kubernetes versions hence, the field `kubernetes_version` will most likely have to be changed. +> [See available instance types for DigitalOcean](https://www.digitalocean.com/docs/droplets/). If you used `qhub init` this version will automatically be computed for you. Do not +> copy the version you see below. -To see available instance types refer to [Digital Ocean Instance -Types](https://www.digitalocean.com/docs/droplets/). Additionally the -Digital Ocean cli `doctl` has [support for listing -droplets](https://www.digitalocean.com/docs/apis-clis/doctl/reference/compute/droplet/list/). +To see available instance types refer to [Digital Ocean Instance Types](https://www.digitalocean.com/docs/droplets/). Additionally the Digital Ocean cli `doctl` has +[support for listing droplets](https://www.digitalocean.com/docs/apis-clis/doctl/reference/compute/droplet/list/). ```yaml digital_ocean: @@ -334,12 +303,10 @@ digital_ocean: #### Google cloud provider -Google Cloud has the best support for QHub and is a great default -choice for a production deployment. It allows auto-scaling to zero -within the node group. There are no major restrictions. +Google Cloud has the best support for QHub and is a great default choice for a production deployment. It allows auto-scaling to zero within the node group. There are no major +restrictions. -To see available instance types refer to -[GCP docs](https://cloud.google.com/compute/docs/machine-types). +To see available instance types refer to [GCP docs](https://cloud.google.com/compute/docs/machine-types). ```yaml google_cloud_platform: @@ -363,11 +330,9 @@ google_cloud_platform: #### Amazon Web Services (AWS) -Amazon Web Services has similar support to DigitalOcean and doesn't -allow auto-scaling below 1 node. +Amazon Web Services has similar support to DigitalOcean and doesn't allow auto-scaling below 1 node. -Consult [AWS instance types](https://aws.amazon.com/ec2/instance-types/) -for possible options. +Consult [AWS instance types](https://aws.amazon.com/ec2/instance-types/) for possible options. ```yaml amazon_web_services: @@ -392,7 +357,8 @@ amazon_web_services: Microsoft Azure has similar settings for Kubernetes version, region, and instance names - using Azure's available values of course. -Azure also requires a field named `storage_account_postfix` which will have been generated by `qhub init`. This allows qhub to create a Storage Account bucket that should be globally unique. +Azure also requires a field named `storage_account_postfix` which will have been generated by `qhub init`. This allows qhub to create a Storage Account bucket that should be +globally unique. ``` azure: @@ -416,21 +382,15 @@ azure: #### Local (existing) Kubernetes cluster -Originally designed for QHub deployments on a "local" minikube cluster, -this feature has now expanded to allow users to deploy QHub to any -existing kubernetes cluster. The default options for a `local` deployment -are still set deploy QHub to a minikube cluster. +Originally designed for QHub deployments on a "local" minikube cluster, this feature has now expanded to allow users to deploy QHub to any existing kubernetes cluster. The default +options for a `local` deployment are still set deploy QHub to a minikube cluster. -If you wish to deploy QHub to an existing kubernetes cluster on one -of the cloud providers, please refer to a more detailed walkthrough found -in the [Deploy QHub to an Existing Kubernetes Cluster](./existing.md). +If you wish to deploy QHub to an existing kubernetes cluster on one of the cloud providers, please refer to a more detailed walkthrough found in the +[Deploy QHub to an Existing Kubernetes Cluster](./existing.md). -Deploying to a local existing kubernetes cluster has different options -than the cloud providers. `kube_context` is an optional key that can -be used to deploy to a non-default context. The default node selectors -will allow pods to be scheduled anywhere. This can be adjusted to -schedule pods on different labeled nodes. Allowing for similar -functionality to node groups in the cloud. +Deploying to a local existing kubernetes cluster has different options than the cloud providers. `kube_context` is an optional key that can be used to deploy to a non-default +context. The default node selectors will allow pods to be scheduled anywhere. This can be adjusted to schedule pods on different labeled nodes. Allowing for similar functionality +to node groups in the cloud. ```yaml local: @@ -449,23 +409,14 @@ local: ## Terraform state -Terraform manages the state of all the deployed resources via -[backends](https://www.terraform.io/language/settings/backends). Terraform -requires storing the state in order to keep track of the names, ids, -and states of deployed resources. The simplest approach is storing the -state on the local filesystem but isn't recommended and isn't the -default of QHub. `terraform_state` is either `remote`, `existing` or -`local` with a default value of `remote`. This decides whether to -control the state of the cluster `local` via tfstate file (not -recommended), on an already `existing` terraform state store or -remotely and auto creating the terraform state store. See [terraform -remote state](https://www.terraform.io/language/state/remote) -docs. If you are doing anything other than testing we highly recommend -`remote` unless you know what you are doing. - -The following are examples. `remote` and `local` are -straightforward. For a `local` provider that deploys on an existing -kubernetes cluster the kubernetes remote backend is used. +Terraform manages the state of all the deployed resources via [backends](https://www.terraform.io/language/settings/backends). Terraform requires storing the state in order to keep +track of the names, ids, and states of deployed resources. The simplest approach is storing the state on the local filesystem but isn't recommended and isn't the default of QHub. +`terraform_state` is either `remote`, `existing` or `local` with a default value of `remote`. This decides whether to control the state of the cluster `local` via tfstate file (not +recommended), on an already `existing` terraform state store or remotely and auto creating the terraform state store. See +[terraform remote state](https://www.terraform.io/language/state/remote) docs. If you are doing anything other than testing we highly recommend `remote` unless you know what you +are doing. + +The following are examples. `remote` and `local` are straightforward. For a `local` provider that deploys on an existing kubernetes cluster the kubernetes remote backend is used. ```yaml terraform_state: @@ -477,8 +428,7 @@ terraform_state: type: local ``` -Using an existing terraform backend can be done by specifying the -`backend` and arbitrary key/value pairs in the `config`. +Using an existing terraform backend can be done by specifying the `backend` and arbitrary key/value pairs in the `config`. ```yaml terraform_state: @@ -492,11 +442,8 @@ terraform_state: ## Default Images -Default images are to the default image run if not specified in a -profile (described in the next section). The `jupyterhub` key controls -the jupyterhub image run. These control the docker image used to run -JupyterHub, the default JupyterLab image, and the default Dask worker -image. +Default images are to the default image run if not specified in a profile (described in the next section). The `jupyterhub` key controls the jupyterhub image run. These control the +docker image used to run JupyterHub, the default JupyterLab image, and the default Dask worker image. ```yaml default_images: @@ -509,11 +456,8 @@ default_images: Control the amount of storage allocated to shared filesystems. -> NOTE 1: when the storage size is changed, for most providers it will -> automatically delete (!) the previous storage place. -> NOTE 2: changing the storage size on an AWS deployment after the initial -> deployment can be especially tricky so it might be worthwhile padding -> these storage sizes. +> NOTE 1: when the storage size is changed, for most providers it will automatically delete (!) the previous storage place. NOTE 2: changing the storage size on an AWS deployment +> after the initial deployment can be especially tricky so it might be worthwhile padding these storage sizes. ```yaml storage: @@ -523,14 +467,14 @@ storage: ## Profiles -Profiles are used to control the JupyterLab user instances and -Dask workers provided by Dask Gateway. +Profiles are used to control the JupyterLab user instances and Dask workers provided by Dask Gateway. ```yaml profiles: jupyterlab: - display_name: Small Instance description: Stable environment with 1 cpu / 1 GB ram + access: all default: true kubespawner_override: cpu_limit: 1 @@ -539,11 +483,25 @@ profiles: mem_guarantee: 1G - display_name: Medium Instance description: Stable environment with 1.5 cpu / 2 GB ram + access: yaml + groups: + - admin + - developers + users: + - bob kubespawner_override: cpu_limit: 1.5 cpu_guarantee: 1.25 mem_limit: 2G mem_guarantee: 2G + - display_name: Large Instance + description: Stable environment with 2 cpu / 4 GB ram + access: keycloak + kubespawner_override: + cpu_limit: 2 + cpu_guarantee: 2 + mem_limit: 4G + mem_guarantee: 4G dask_worker: "Small Worker": worker_cores_limit: 1 @@ -557,39 +515,42 @@ profiles: worker_memory: 2G ``` -For each `profiles.jupyterlab` is a named JupyterLab profile. It -closely follows the -[KubeSpawner](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html) -API. The only exception is that two keys are added `users` and -`groups` which allow restriction of profiles to a given set of groups -and users. We recommend using groups to manage profile access. - -Finally, we allow for configuration of the Dask workers. In general, -similar to the JupyterLab instances you only need to configuration the -cores and memory. - -When configuring the memory and CPUs for profiles there are some -important considerations to make. Two important terms to understand are: - - `limit`: the absolute max memory that a given pod can consume. If a - process within the pod consumes more than the `limit` memory the - linux OS will kill the process. LimIt is not used for scheduling - purposes with kubernetes. - - `guarantee`: is the amount of memory the kubernetes scheduler uses - to place a given pod. In general the `guarantee` will be less than - the limit. Often times the node itself has less available memory - than the node specification. See this [guide from digital - ocean](https://docs.digitalocean.com/products/kubernetes/#allocatable-memory) - which is generally applicable to other clouds. - -For example if a node has 8 GB of ram and 2 CPUs you should -guarantee/schedule roughly 75% and follow the digital ocean guide -linked above. For example 1.5 CPU guarantee and 5.5 GB guaranteed. +### JupyterLab Profiles + +For each `profiles.jupyterlab` is a named JupyterLab profile. + +Use the `kubespawner_override` field to define behavior as per the [KubeSpawner](https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html) API. + +It is possible to control which users have access to which JupyterLab profiles. Each profile has a field named `access` which can be set to `all` (default if omitted), `yaml`, or +`keycloak`. + +`all` means every user will have access to the profile. + +`yaml` means that access is restricted to anyone with their username in the `users` field of the profile or who belongs to a group named in the `groups` field. + +`keycloak` means that access is restricted to any user who in Keycloak has either their group(s) or user with the attribute `jupyterlab_profiles` containing this profile name. For +example, if the user is in a Keycloak group named `developers` which has an attribute `jupyterlab_profiles` set to `Large Instance`, they will have access to the Large Instance +profile. To specify multiple profiles for one group (or user) delimit their names using `##` - for example, `Large Instance##Another Instance`. + +### Dask Profiles + +Finally, we allow for configuration of the Dask workers. In general, similar to the JupyterLab instances you only need to configuration the cores and memory. + +When configuring the memory and CPUs for profiles there are some important considerations to make. Two important terms to understand are: + +- `limit`: the absolute max memory that a given pod can consume. If a process within the pod consumes more than the `limit` memory the linux OS will kill the process. LimIt is not + used for scheduling purposes with kubernetes. +- `guarantee`: is the amount of memory the kubernetes scheduler uses to place a given pod. In general the `guarantee` will be less than the limit. Often times the node itself has + less available memory than the node specification. See this [guide from digital ocean](https://docs.digitalocean.com/products/kubernetes/#allocatable-memory) which is generally + applicable to other clouds. + +For example if a node has 8 GB of ram and 2 CPUs you should guarantee/schedule roughly 75% and follow the digital ocean guide linked above. For example 1.5 CPU guarantee and 5.5 GB +guaranteed. ### Dask Scheduler -In a few instances, the Dask worker node-group might be running on quite a large -instance, perhaps with 8 CPUs and 32 GB of memory (or more). When this is the case, you -might also want to increase the resource levels associated with the Dask Scheduler. +In a few instances, the Dask worker node-group might be running on quite a large instance, perhaps with 8 CPUs and 32 GB of memory (or more). When this is the case, you might also +want to increase the resource levels associated with the Dask Scheduler. ```yaml dask_worker: @@ -606,10 +567,8 @@ dask_worker: ### JupyterLab Profile Node Selectors -A common operation is to target jupyterlab profiles to specific node -labels. In order to target a specific node groups add the -following. This example shows a GKE node groups with name -`user-large`. Other cloud providers will have different node labels. +A common operation is to target jupyterlab profiles to specific node labels. In order to target a specific node groups add the following. This example shows a GKE node groups with +name `user-large`. Other cloud providers will have different node labels. ```yaml profiles: @@ -643,9 +602,8 @@ profiles: ### Customizing JupyterHub theme -JupyterHub can be customized since QHub uses -[Quansight/qhub-jupyterhub-theme](https://github.com/quansight/qhub-jupyterhub-theme). Available -theme options. +JupyterHub can be customized since QHub uses [Quansight/qhub-jupyterhub-theme](https://github.com/quansight/qhub-jupyterhub-theme). Available theme options. + > NOTE: if you want to change the logo it must be an accessible URL to the logo. ```yaml @@ -703,16 +661,12 @@ environments: - pyyaml ``` -QHub is experimenting with a new way of distributing environments -using [conda-store](https://github.com/quansight/conda-store). Please -expect this environment distribution method to change over time. +QHub is experimenting with a new way of distributing environments using [conda-store](https://github.com/quansight/conda-store). Please expect this environment distribution method +to change over time. -Each environment configuration is a `environment.` mapping to a -conda environment definition file. If you need to pin a specific version, -please include it in the definition. One current requirement is that -each environment include `ipykernel`, `ipywidgets`, `qhub-dask==0.2.3`. Upon changing the -environment definition expect 1-10 minutes upon deployment of the -configuration for the environment to appear. +Each environment configuration is a `environment.` mapping to a conda environment definition file. If you need to pin a specific version, please include it in the +definition. One current requirement is that each environment include `ipykernel`, `ipywidgets`, `qhub-dask==0.2.3`. Upon changing the environment definition expect 1-10 minutes +upon deployment of the configuration for the environment to appear. ## qhub_version @@ -720,15 +674,13 @@ All `qhub-config.yaml` files must now contain a `qhub_version` field displaying QHub will refuse to deploy if it doesn't contain the same version as that of the `qhub` command. -Typically, you can upgrade the qhub-config.yaml file itself using the [`qhub upgrade` command](../admin_guide/upgrade.md). This will update image numbers, plus updating qhub_version to match the installed version of `qhub`, as well as any other bespoke changes required. +Typically, you can upgrade the qhub-config.yaml file itself using the [`qhub upgrade` command](../admin_guide/upgrade.md). This will update image numbers, plus updating +qhub_version to match the installed version of `qhub`, as well as any other bespoke changes required. ## JupyterHub -JupyterHub uses the [zero to jupyterhub helm -chart](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/). This -chart has many options that are not configured in the QHub default -installation. You can override specific values in the -[values.yaml](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/main/jupyterhub/values.yaml). `jupyterhub.overrides` +JupyterHub uses the [zero to jupyterhub helm chart](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/). This chart has many options that are not configured in the QHub default +installation. You can override specific values in the [values.yaml](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/main/jupyterhub/values.yaml). `jupyterhub.overrides` is optional. ```yaml @@ -738,6 +690,36 @@ jupyterhub: users: true ``` +## Terraform Overrides + +The QHub configuration file provides a huge number of configuration options for customizing your +QHub Infrastructure, while these options are sufficient for an average user, but aren't +exhaustive by any means. There are still a plenty of things you might want to achieve which +cannot be configured directly by the above mentioned options, hence we've introduced a +new option called terraform overrides (`terraform_overrides`), which lets you override +the values of terraform variables in specific modules/resource. This is a relatively +advance feature and must be used with utmost care and you should really know, what +you're doing. + +Here we describe the overrides supported via QHub config file: + +### Ingress + +You can configure the IP of the load balancer and add annotations for the same via `ingress`'s +terraform overrides, one such example for GCP is: + + +```yaml +ingress: + terraform_overrides: + load-balancer-annotations: + "networking.gke.io/load-balancer-type": "Internal" + "networking.gke.io/internal-load-balancer-subnet": "pre-existing-subnet" + load-balancer-ip: "1.2.3.4" +``` + +This is quite useful for pinning the IP Address of the load balancer. + # Full configuration example ```yaml @@ -812,6 +794,7 @@ profiles: jupyterlab: - display_name: Small Instance description: Stable environment with 1 cpu / 1 GB ram + access: yaml groups: - admin kubespawner_override: diff --git a/docs/source/installation/existing.md b/docs/source/installation/existing.md index a1ada21ba..e7dd17187 100644 --- a/docs/source/installation/existing.md +++ b/docs/source/installation/existing.md @@ -1,84 +1,82 @@ # Deploy QHub to an existing kubernetes cluster -If you have an existing kubernetes cluster running in the cloud and -would like to deploy QHub on the same cluster, this is the guide for you. +If you have an existing kubernetes cluster running in the cloud and would like to deploy QHub on the same cluster, this is the guide for you. -To illustrate how this is done, the guide walks through a simple example. -The guide below is meant to serve as a reference, the setup of your existing -kubernetes might differ rending some of these additional setups steps -unnecessary. +To illustrate how this is done, the guide walks through a simple example. The guide below is meant to serve as a reference, the setup of your existing kubernetes might differ +rending some of these additional setups steps unnecessary. ## Deploy QHub to an existing AWS EKS cluster -In this example, there already exists a basic web app running on an EKS -cluster. [Here is the tutorial on how to setup this particular Guestbook web -app](https://logz.io/blog/amazon-eks-cluster/). +In this example, there already exists a basic web app running on an EKS cluster. +[Here is the tutorial on how to setup this particular Guestbook web app](https://logz.io/blog/amazon-eks-cluster/). -The existing EKS cluster has one VPC with three subnets (each in their own -Availability Zone) and no node groups. There are three nodes each running on -a `t3.medium` EC2 instance, unfortunately QHub's `general` node group requires -a more powerful instance type. +The existing EKS cluster has one VPC with three subnets (each in their own Availability Zone) and no node groups. There are three nodes each running on a `t3.medium` EC2 instance, +unfortunately QHub's `general` node group requires a more powerful instance type. -Now create three new node groups in preparation for the incoming QHub -deployment. Before proceeding, ensure the following: -- that the subnets can ["automatically -assign public IP addresses to instances launched into it"](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-ip-addressing.html#subnet-public-ip) +Now create three new node groups in preparation for the incoming QHub deployment. Before proceeding, ensure the following: + +- that the subnets can + ["automatically assign public IP addresses to instances launched into it"](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-ip-addressing.html#subnet-public-ip) - there exists an IAM role with the following permissions: - - AmazonEKSWorkerNodePolicy - - AmazonEC2ContainerRegistryReadOnly - - AmazonEKS_CNI_Policy - - The following custom policy: -
    - - ```json - { - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "eksWorkerAutoscalingAll", - "Effect": "Allow", - "Action": [ - "ec2:DescribeLaunchTemplateVersions", - "autoscaling:DescribeTags", - "autoscaling:DescribeLaunchConfigurations", - "autoscaling:DescribeAutoScalingInstances", - "autoscaling:DescribeAutoScalingGroups" - ], - "Resource": "*" - }, - { - "Sid": "eksWorkerAutoscalingOwn", - "Effect": "Allow", - "Action": [ - "autoscaling:UpdateAutoScalingGroup", - "autoscaling:TerminateInstanceInAutoScalingGroup", - "autoscaling:SetDesiredCapacity" - ], - "Resource": "*", - "Condition": { - "StringEquals": { - "autoscaling:ResourceTag/k8s.io/cluster-autoscaler/enabled": [ - "true" - ], - "autoscaling:ResourceTag/kubernetes.io/cluster/eaeeks": [ - "owned" - ] - } + - AmazonEKSWorkerNodePolicy + + - AmazonEC2ContainerRegistryReadOnly + + - AmazonEKS_CNI_Policy + + - The following custom policy: + +
    + + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "eksWorkerAutoscalingAll", + "Effect": "Allow", + "Action": [ + "ec2:DescribeLaunchTemplateVersions", + "autoscaling:DescribeTags", + "autoscaling:DescribeLaunchConfigurations", + "autoscaling:DescribeAutoScalingInstances", + "autoscaling:DescribeAutoScalingGroups" + ], + "Resource": "*" + }, + { + "Sid": "eksWorkerAutoscalingOwn", + "Effect": "Allow", + "Action": [ + "autoscaling:UpdateAutoScalingGroup", + "autoscaling:TerminateInstanceInAutoScalingGroup", + "autoscaling:SetDesiredCapacity" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "autoscaling:ResourceTag/k8s.io/cluster-autoscaler/enabled": [ + "true" + ], + "autoscaling:ResourceTag/kubernetes.io/cluster/eaeeks": [ + "owned" + ] } } - ] - } - ``` - -
    + } + ] + } + ``` +
    ### Create node groups Skip this step if node groups already exist. -For AWS, [follow this guide to create new node groups](https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html). Be sure to fill in the following -fields carefully: +For AWS, [follow this guide to create new node groups](https://docs.aws.amazon.com/eks/latest/userguide/create-managed-node-group.html). Be sure to fill in the following fields +carefully: + - "Node Group configuration" - `Name` must be either `general`, `user` or `worker` - `Node IAM Role` must be the IAM role described proceeding @@ -93,22 +91,22 @@ fields carefully: - "Node Group subnet configuration" - `subnet` include all existing EKS subnets - ## Deploy QHub to Existing EKS Cluster Ensure that you are using the existing cluster's `kubectl` context. Initialize in the usual manner: + ``` python -m qhub init aws --project --domain --ci-provider github-actions --auth-provider github --auth-auto-provision ``` Then update the `qhub-config.yaml` file. The important keys to update are: + - Replace `provider: aws` with `provider: local` - Replace `amazon_web_services` with `local` - And update the `node_selector` and `kube_context` appropriately -
    ``` @@ -241,13 +239,12 @@ environments:
    - Once updated, deploy QHub. When prompted be ready to manually update the DNS record. + - `local` or "existing" deployments fail if you pass `--dns-auto-provision` or `--disable-prompt` ``` python -m qhub deploy --config qhub-config.yaml ``` -The deployment completes successfully and all the pods appear to be running and so do the -pre-existing Guestbook web app. +The deployment completes successfully and all the pods appear to be running and so do the pre-existing Guestbook web app. diff --git a/docs/source/installation/index.md b/docs/source/installation/index.md index 99511ec11..93a85c036 100644 --- a/docs/source/installation/index.md +++ b/docs/source/installation/index.md @@ -1,4 +1,3 @@ - # Installation ```{toctree} diff --git a/docs/source/installation/installation.md b/docs/source/installation/installation.md index eca6a5945..963dc4872 100644 --- a/docs/source/installation/installation.md +++ b/docs/source/installation/installation.md @@ -2,28 +2,27 @@ ## Pre-requisites -* QHub is supported on the macOS and Linux operating systems. +- QHub is supported on the macOS and Linux operating systems. > NOTE: **Currently, QHub cannot be installed on Windows**. -* We recommend the adoption of virtual environments (`conda`, `pipenv` or `venv`) for successful usage. +- We recommend the adoption of virtual environments (`conda`, `pipenv` or `venv`) for successful usage. ## Install QHub CLI QHub's installation can be performed by using: - * `conda`: +- `conda`: ```bash conda install -c conda-forge qhub ``` - * or `pip` (instead): +- or `pip` (instead): ```bash pip install qhub ``` -Once finished, you can check QHub's version (and additional CLI args) -by typing: +Once finished, you can check QHub's version (and additional CLI args) by typing: ```bash qhub --help diff --git a/docs/source/installation/management.md b/docs/source/installation/management.md index 85d6ec733..2984b8ac0 100644 --- a/docs/source/installation/management.md +++ b/docs/source/installation/management.md @@ -12,12 +12,13 @@ This can be done through the Keycloak web console. See [Adding a QHub user](./lo To update a current conda environment and redeploy you will need to: -* Create a new branch on your repository -* Make changes to the `qhub-config.yaml` file under the `environments` key. -> NOTE: in [YAML](https://yaml.org/spec/1.2/spec.html#mapping//), - each level is a dictionary key, and every 2 white spaces represent values for those keys. +- Create a new branch on your repository +- Make changes to the `qhub-config.yaml` file under the `environments` key. + +> NOTE: in [YAML](https://yaml.org/spec/1.2/spec.html#mapping//), each level is a dictionary key, and every 2 white spaces represent values for those keys. To add a new environment, add two spaces below the `environments` key such as the example below. + ```yaml environments: "example.yaml": @@ -29,14 +30,17 @@ environments: - pandas ``` -Commit the changes, and make a [PR](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request) into a master branch. The update will take from 5 to 30 minutes to complete, depending on the environment's complexity. If after 30 minutes the new environment is still not available, check the latest -log files from the user instance in the `/home/conda/store/.logs` directory to troubleshoot. +Commit the changes, and make a [PR](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request) into a master branch. The update will +take from 5 to 30 minutes to complete, depending on the environment's complexity. If after 30 minutes the new environment is still not available, check the latest log files from +the user instance in the `/home/conda/store/.logs` directory to troubleshoot. -* Note that the current version will not notify you if an environment fails to solve. The only way to see failures is by manually checking the above logs.* +- Note that the current version will not notify you if an environment fails to solve. The only way to see failures is by manually checking the above logs.\* ## Copy Files into Users' Home Folders -Within their own JupyterLab sessions, admins can add files to a folder called `shared/.userskel`. Any files in there will be copied to a user's own home folder whenever they start a new JupyterLab session. Existing files with the same name will not be overwritten. Admin users are defined as members of the admin group as specified in your `qhub-config.yaml` file. +Within their own JupyterLab sessions, admins can add files to a folder called `shared/.userskel`. Any files in there will be copied to a user's own home folder whenever they start +a new JupyterLab session. Existing files with the same name will not be overwritten. Admin users are defined as members of the admin group as specified in your `qhub-config.yaml` +file. ## Monitor your QHub deployment diff --git a/docs/source/installation/setup.md b/docs/source/installation/setup.md index b57fd0d2c..f6f569119 100644 --- a/docs/source/installation/setup.md +++ b/docs/source/installation/setup.md @@ -1,86 +1,67 @@ # Setup Initialization -QHub handles the initial setup and management of configurable data -science environments, allowing users to deploy seamlessly -using Github Actions. +QHub handles the initial setup and management of configurable data science environments, allowing users to deploy seamlessly using Github Actions. -QHub can be installed on a bare-metal server using HPC, on a Cloud -provider or even locally for testing purposes. Review the options -below to discover which option best suits your needs. +QHub can be installed on a bare-metal server using HPC, on a Cloud provider or even locally for testing purposes. Review the options below to discover which option best suits your +needs. ## Local Deployment or Existing Kubernetes Cluster -The local version is recommended for testing QHub's components due to -its simplicity. Choose the local mode if: +The local version is recommended for testing QHub's components due to its simplicity. Choose the local mode if: - You already have Kubernetes clusters - You want to test these Kubernetes clusters - You have available local compute setup -- You want to try out QHub with a quick-install to see how it works, - without setting up environment variables +- You want to try out QHub with a quick-install to see how it works, without setting up environment variables -You should choose another installation option if you are starting from -scratch (i.e., no clusters yet) and aiming to have a production -environment. +You should choose another installation option if you are starting from scratch (i.e., no clusters yet) and aiming to have a production environment. -Found your match? Head over to the [Local install -docs](../dev_guide/testing.md#local-testing) for -more details. +Found your match? Head over to the [Local install docs](../dev_guide/testing.md#local-testing) for more details. ## HPC Deployment The [QHub HPC](https://hpc.qhub.dev/en/latest/) should be your choice if: + - You have highly optimized code that require highly performant infrastructure - You have existing infrastructure already available - You expect that your infrastructure will **not** exceed the existing resources capabilities -> NOTE: Although it is possible to deploy QHub HPC on the Cloud, it is not generally recommended due to possible high -> costs. For more information, check out the [base cost](../admin_guide/cost.md) section of the docs. + +> NOTE: Although it is possible to deploy QHub HPC on the Cloud, it is not generally recommended due to possible high costs. For more information, check out the +> [base cost](../admin_guide/cost.md) section of the docs. ## Kubernetes Deployment -The Kubernetes deployment of QHub is considered to be the default -option. If you are not sure which option to choose, try this one. It -is suitable for most use cases, especially if: +The Kubernetes deployment of QHub is considered to be the default option. If you are not sure which option to choose, try this one. It is suitable for most use cases, especially +if: + - You require scalable infrastructure - You aim to have a production environment with GitOps enabled by default -The QHub version requires a choice of [Cloud -provider](#cloud-provider), [authentication (using Auth0, GitHub, custom OAuth provider, or -password based)](#authentication), [domain -registration](#domain-registry), and CI provider (GitHub Actions, GitLab CI). +The QHub version requires a choice of [Cloud provider](#cloud-provider), [authentication (using Auth0, GitHub, custom OAuth provider, or password based)](#authentication), +[domain registration](#domain-registry), and CI provider (GitHub Actions, GitLab CI). -These services require global [environment -variables](https://linuxize.com/post/how-to-set-and-list-environment-variables-in-linux/) -that once set up, will trigger QHub's automatic deploy using your -CI/CD platform of choice. +These services require global [environment variables](https://linuxize.com/post/how-to-set-and-list-environment-variables-in-linux/) that once set up, will trigger QHub's automatic +deploy using your CI/CD platform of choice. -To find and set the environment variables, follow the steps described -on the subsections below. +To find and set the environment variables, follow the steps described on the subsections below. ### Cloud Provider -The first required step is to **choose a Cloud Provider to host the -project deployment**. The cloud installation is based on Kubernetes, -but knowledge of Kubernetes is **NOT** required nor is in depth -knowledge about the specific provider required either. QHub supports -[Amazon AWS](#amazon-web-services-aws), -[DigitalOcean](#digital-ocean), [GCP](#google-cloud-platform), and -[Azure](#microsoft-azure). +The first required step is to **choose a Cloud Provider to host the project deployment**. The cloud installation is based on Kubernetes, but knowledge of Kubernetes is **NOT** +required nor is in depth knowledge about the specific provider required either. QHub supports [Amazon AWS](#amazon-web-services-aws), [DigitalOcean](#digital-ocean), +[GCP](#google-cloud-platform), and [Azure](#microsoft-azure). -To deploy QHub, all access keys require fairly wide permissions to -create all the necessary cloud resources. Hence, once the Cloud -provider has been chosen, follow the steps below and set the -environment variables as specified with **owner/admin** level -permissions. +To deploy QHub, all access keys require fairly wide permissions to create all the necessary cloud resources. Hence, once the Cloud provider has been chosen, follow the steps below +and set the environment variables as specified with **owner/admin** level permissions. -For more details on configuration for each Cloud provider, check the -How-To Guides section of the documentation. +For more details on configuration for each Cloud provider, check the How-To Guides section of the documentation. #### Amazon Web Services (AWS) +
    Click for AWS configuration instructions -Please see these instructions for [creating an IAM role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create.html) with administrator permissions. Upon generation, the IAM role will provide a public **access -key ID** and a **secret key** which will need to be added to the environment variables. +Please see these instructions for [creating an IAM role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create.html) with administrator permissions. Upon generation, the +IAM role will provide a public **access key ID** and a **secret key** which will need to be added to the environment variables. To define the environment variables paste the commands below with your respective keys. @@ -88,13 +69,16 @@ To define the environment variables paste the commands below with your respectiv export AWS_ACCESS_KEY_ID="HAKUNAMATATA" export AWS_SECRET_ACCESS_KEY="iNtheJUng1etheMightyJUNgleTHEl10N51eEpsT0n1ghy;" ``` +
    ### Digital Ocean
    Click to expand DigitalOcean configuration directions -Please see these instructions for [creating a Digital Ocean token](https://www.digitalocean.com/docs/apis-clis/api/create-personal-access-token/). In addition to a `token`, a `spaces key` (similar to AWS S3) credentials are also required. Follow the instructions on the [official docs](https://www.digitalocean.com/community/tutorials/how-to-create-a-digitalocean-space-and-api-key) for more information. +Please see these instructions for [creating a Digital Ocean token](https://www.digitalocean.com/docs/apis-clis/api/create-personal-access-token/). In addition to a `token`, a +`spaces key` (similar to AWS S3) credentials are also required. Follow the instructions on the +[official docs](https://www.digitalocean.com/community/tutorials/how-to-create-a-digitalocean-space-and-api-key) for more information. > Note: DigitalOcean's permissions model isn't as fine-grained as the other supported Cloud providers. @@ -107,14 +91,16 @@ export SPACES_SECRET_ACCESS_KEY="" # the private key for access spaces export AWS_ACCESS_KEY_ID="" # set this variable with the same value as `SPACES_ACCESS_KEY_ID` export AWS_SECRET_ACCESS_KEY="" # set this variable identical to `SPACES_SECRET_ACCESS_KEY` ``` +
    ### Google Cloud Platform
    Click for CGP configuration specs -Follow [these detailed instructions](https://cloud.google.com/iam/docs/creating-managing-service-accounts) to create a Google Service Account with **owner level** permissions. Then, follow the steps described on the official -[GCP docs](https://cloud.google.com/iam/docs/creating-managing-service-account-keys#iam-service-account-keys-create-console) to create and download a JSON credentials file. Store this credentials file in a well known location and make sure to set yourself exclusive permissions. +Follow [these detailed instructions](https://cloud.google.com/iam/docs/creating-managing-service-accounts) to create a Google Service Account with **owner level** permissions. +Then, follow the steps described on the official [GCP docs](https://cloud.google.com/iam/docs/creating-managing-service-account-keys#iam-service-account-keys-create-console) to +create and download a JSON credentials file. Store this credentials file in a well known location and make sure to set yourself exclusive permissions. You can change the file permissions by running the command `chmod 600 ` on your terminal. @@ -125,15 +111,17 @@ export GOOGLE_CREDENTIALS="path/to/JSON/file/with/credentials" export PROJECT_ID="projectIDName" ``` -> NOTE: the [`PROJECT_ID` variable](https://cloud.google.com/resource-manager/docs/creating-managing-projects) can be -> found at the Google Console homepage, under `Project info`. +> NOTE: the [`PROJECT_ID` variable](https://cloud.google.com/resource-manager/docs/creating-managing-projects) can be found at the Google Console homepage, under `Project info`. +
    ### Microsoft Azure
    Click for Azure configuration details -Follow [these instructions](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret#creating-a-service-principal-in-the-azure-portal) to create a Service Principal in the Azure Portal. After completing the steps described on the link, set the following environment variables such as below: +Follow +[these instructions](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret#creating-a-service-principal-in-the-azure-portal) +to create a Service Principal in the Azure Portal. After completing the steps described on the link, set the following environment variables such as below: ```shell export ARM_CLIENT_ID="" # application (client) ID @@ -142,27 +130,31 @@ export ARM_SUBSCRIPTION_ID="" # value available at the `Subscription` sectio export ARM_TENANT_ID="" # field available under `Azure Active Directories` > `Properties` > `Tenant ID` ``` -> NOTE 1: Having trouble finding your Subscription ID? [Azure's official docs](https://docs.microsoft.com/en-us/azure/media-services/latest/how-to-set-azure-subscription?tabs=portal) -> might help. +> NOTE 1: Having trouble finding your Subscription ID? +> [Azure's official docs](https://docs.microsoft.com/en-us/azure/media-services/latest/how-to-set-azure-subscription?tabs=portal) might help. + +> NOTE 2: [Tenant ID](https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-how-to-find-tenant) values can be also found using PowerShell and CLI. -> NOTE 2: [Tenant ID](https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-how-to-find-tenant) -> values can be also found using PowerShell and CLI.
    ## Authentication -User identity in QHub is now managed within Keycloak which is a robust and highly flexible open source identity and access management solution. A Keycloak instance will be deployed inside your QHub. It can be configured to work with many OAuth 2.0 identity providers, it can federate users from existing databases (such as LDAP), or it can be used as a simple database of username/passwords. +User identity in QHub is now managed within Keycloak which is a robust and highly flexible open source identity and access management solution. A Keycloak instance will be deployed +inside your QHub. It can be configured to work with many OAuth 2.0 identity providers, it can federate users from existing databases (such as LDAP), or it can be used as a simple +database of username/passwords. -The full extent of possible configuration can't be covered here, so we provide three simple options that can be configured automatically by QHub when it sets up your new platform. These options are basic passwords, GitHub single-sign on, or Auth0 single-sign on (which in turn can be configured to allow identity to be provided by social login etc). +The full extent of possible configuration can't be covered here, so we provide three simple options that can be configured automatically by QHub when it sets up your new platform. +These options are basic passwords, GitHub single-sign on, or Auth0 single-sign on (which in turn can be configured to allow identity to be provided by social login etc). -You will actually instruct `qhub init` which method you have chosen when you move on to the [Usage](usage.md) section, but at this stage you may need to set environment variables corresponding to your choice: +You will actually instruct `qhub init` which method you have chosen when you move on to the [Usage](usage.md) section, but at this stage you may need to set environment variables +corresponding to your choice: ### Auth0
    Click for Auth0 configuration details -Auth0 is a great choice to enable flexible authentication via multiple providers. To create the necessary access tokens you will need to have an [Auth0](https://auth0.com/) account and be logged in. [Directions -for creating an Auth0 application](https://auth0.com/docs/applications/set-up-an-application/register-machine-to-machine-applications). +Auth0 is a great choice to enable flexible authentication via multiple providers. To create the necessary access tokens you will need to have an [Auth0](https://auth0.com/) account +and be logged in. [Directions for creating an Auth0 application](https://auth0.com/docs/applications/set-up-an-application/register-machine-to-machine-applications). - Click on the `Applications` button on the left - Select `Create Application` > `Machine to Machine Applications` > `Auth0 Management API` from the dropdown menu @@ -171,13 +163,14 @@ for creating an Auth0 application](https://auth0.com/docs/applications/set-up-an With the application created set the following environment variables: - - `AUTH0_CLIENT_ID`: client ID of Auth0 machine-to-machine application found at top of the newly created application page - - `AUTH0_CLIENT_SECRET`: secret ID of Auth0 machine-to-machine application found in the `Settings` tab of the newly created application - - `AUTH0_DOMAIN`: The `Tenant Name` which can be found in the general account settings on the left hand side of the page appended with `.auth0.com`, for example: +- `AUTH0_CLIENT_ID`: client ID of Auth0 machine-to-machine application found at top of the newly created application page +- `AUTH0_CLIENT_SECRET`: secret ID of Auth0 machine-to-machine application found in the `Settings` tab of the newly created application +- `AUTH0_DOMAIN`: The `Tenant Name` which can be found in the general account settings on the left hand side of the page appended with `.auth0.com`, for example: ```bash export AUTH_DOMAIN="qhub-test.auth0.com" # in case the Tenant Name was called 'qhub-test' ``` +
    ### GitHub Single-sign on @@ -186,25 +179,34 @@ export AUTH_DOMAIN="qhub-test.auth0.com" # in case the Tenant Name was called 'q To use GitHub as a single-sign on provider, you will need to create a new OAuth 2.0 app. -No environment variables are needed for this - you will be given the relevant information and prompted for various inputs during the next stage, when you run [`qhub init`](./usage.md) if you provide the flag `--auth-provider github`. This will be covered when you reach that point in this documentation. +No environment variables are needed for this - you will be given the relevant information and prompted for various inputs during the next stage, when you run +[`qhub init`](./usage.md) if you provide the flag `--auth-provider github`. This will be covered when you reach that point in this documentation. + ## CI/CD Pipeline -In the [Usage](usage.md) section, you will need to run `qhub init` (this only ever needs to be run once - it creates your configuration YAML file) and then `qhub deploy` to set up the cloud infrastructure and deploy QHub for the first time. +In the [Usage](usage.md) section, you will need to run `qhub init` (this only ever needs to be run once - it creates your configuration YAML file) and then `qhub deploy` to set up +the cloud infrastructure and deploy QHub for the first time. -For subsequent deployments, it's possible to run `qhub deploy` again in exactly the same way, providing the configuration YAML file as you would the first time. However, it's also possible to automate future deployments using 'DevOps' - the configuration YAML file stored in git will trigger automatic redeployment whenever it's edited. +For subsequent deployments, it's possible to run `qhub deploy` again in exactly the same way, providing the configuration YAML file as you would the first time. However, it's also +possible to automate future deployments using 'DevOps' - the configuration YAML file stored in git will trigger automatic redeployment whenever it's edited. -This DevOps approach can be provided by GitHub Actions or GitLab Workflows. As for the other choices, you will only need to specify the CI/CD provider when you come to run `qhub init`, but you may need to set relevant environment variables unless you choose 'none' because you plan to always redeploy manually. +This DevOps approach can be provided by GitHub Actions or GitLab Workflows. As for the other choices, you will only need to specify the CI/CD provider when you come to run +`qhub init`, but you may need to set relevant environment variables unless you choose 'none' because you plan to always redeploy manually. ### GitHub
    Click for GitHub Actions configuration details -QHub uses GitHub Actions to enable [Infrastructure as Code](https://en.wikipedia.org/wiki/Infrastructure_as_code) and trigger the CI/CD checks on the configuration file that automatically generates the deployment modules for the infrastructure. To do that, it will be necessary to set the GitHub username and token as environment variables. First create a github personal access token via [these instructions](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). The token needs permissions to create a repo and create secrets on the repo. At the moment we don't have the permissions well scoped out so to be on the safe side enable all permissions. +QHub uses GitHub Actions to enable [Infrastructure as Code](https://en.wikipedia.org/wiki/Infrastructure_as_code) and trigger the CI/CD checks on the configuration file that +automatically generates the deployment modules for the infrastructure. To do that, it will be necessary to set the GitHub username and token as environment variables. First create +a github personal access token via [these instructions](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). The token needs permissions to +create a repo and create secrets on the repo. At the moment we don't have the permissions well scoped out so to be on the safe side enable all permissions. + +- `GITHUB_USERNAME`: GitHub username +- `GITHUB_TOKEN`: GitHub-generated token - - `GITHUB_USERNAME`: GitHub username - - `GITHUB_TOKEN`: GitHub-generated token
    ### GitLab @@ -215,14 +217,19 @@ If you want to use GitLab CI to automatically deploy changes to your configurati All git repo and CI setup on GitLab will need to be done manually. At the next stage, when you run [`qhub init`](./usage.md) please provide the flag `--ci-provider gitlab-ci`. -After initial deploy, the documentation should tell you when to commit your configuration files into your GitLab repo. There should be your `qhub-config.yaml` file as well as a generated file called `.gitlab-ci.yml`. You will need to manually set environment variables for your cloud provider as secrets in your GitLab CI for the repo. +After initial deploy, the documentation should tell you when to commit your configuration files into your GitLab repo. There should be your `qhub-config.yaml` file as well as a +generated file called `.gitlab-ci.yml`. You will need to manually set environment variables for your cloud provider as secrets in your GitLab CI for the repo. + ## Domain registry Finally, you will need to have a domain name for hosting QHub. This domain will be where your application will be exposed. -Currently, QHub only supports CloudFlare for automatic DNS registration. If an alternate DNS provider is desired, change the `--dns-provider` flag from `cloudflare` to `none` on the `qhub deploy` command. The deployment then will be paused when it asks for an IP address (or CNAME, if using AWS) and prompt to register the desired URL. Setting a DNS record heavily depends on the provider thus it's not possible to have detailed docs on how to create a record on your provider. Googling `setting
    record on ` should yield good results on doing it for your specific provider. +Currently, QHub only supports CloudFlare for automatic DNS registration. If an alternate DNS provider is desired, change the `--dns-provider` flag from `cloudflare` to `none` on +the `qhub deploy` command. The deployment then will be paused when it asks for an IP address (or CNAME, if using AWS) and prompt to register the desired URL. Setting a DNS record +heavily depends on the provider thus it's not possible to have detailed docs on how to create a record on your provider. Googling `setting record on ` +should yield good results on doing it for your specific provider. ### Cloudflare @@ -230,23 +237,18 @@ Currently, QHub only supports CloudFlare for automatic DNS registration. If an a QHub supports Cloudflare as a DNS provider. If you choose to use Cloudflare, first create an account, then there are two possible following options: -1. You can register your application domain name on it, using the [Cloudflare nameserver](https://support.cloudflare.com/hc/en-us/articles/205195708-Changing-your-domain-nameservers-to-Cloudflare) -(recommended). +1. You can register your application domain name on it, using the + [Cloudflare nameserver](https://support.cloudflare.com/hc/en-us/articles/205195708-Changing-your-domain-nameservers-to-Cloudflare) (recommended). 2. You can outright buy a new domain with Cloudflare (this action isn't particularly recommended). To generate a token [follow these steps](https://developers.cloudflare.com/api/tokens/create): - Under `Profile`, select the `API Tokens` menu and click on `Create API Token`. -- On `Edit zone DNS` click on `Use Template`. -![screenshot Cloudflare edit Zone DNS](../images/cloudflare_auth_1.png) -- Configure `Permissions` such as the image below: -![screenshot Cloudflare Permissions edit](../images/cloudflare_permissions_2.1.1.png) -- On `Account Resources` set the configuration to include your desired account -![screenshot Cloudflare account resources](../images/cloudflare_account_resources_scr.png) -- On `Zone Resources` set it to `Include | Specific zone` and your domain name -![screenshot Cloudflare account resources](../images/cloudflare_zone_resources.png) -- Click continue to summary -![screenshot Cloudflare summary](../images/cloudflare_summary.png) +- On `Edit zone DNS` click on `Use Template`. ![screenshot Cloudflare edit Zone DNS](../images/cloudflare_auth_1.png) +- Configure `Permissions` such as the image below: ![screenshot Cloudflare Permissions edit](../images/cloudflare_permissions_2.1.1.png) +- On `Account Resources` set the configuration to include your desired account ![screenshot Cloudflare account resources](../images/cloudflare_account_resources_scr.png) +- On `Zone Resources` set it to `Include | Specific zone` and your domain name ![screenshot Cloudflare account resources](../images/cloudflare_zone_resources.png) +- Click continue to summary ![screenshot Cloudflare summary](../images/cloudflare_summary.png) - Click on the `Create Token` button and set the token generated as an environment variable on your machine. Finally, set the environment variable such as: @@ -257,7 +259,7 @@ Finally, set the environment variable such as: ----- +______________________________________________________________________ You are now done with the hardest part of the deployment. diff --git a/docs/source/installation/usage.md b/docs/source/installation/usage.md index c3b54589b..5025898d0 100644 --- a/docs/source/installation/usage.md +++ b/docs/source/installation/usage.md @@ -2,17 +2,13 @@ ## Cloud Deployment -Great, you've gone through the `qhub` [Installation](installation.md) and [Setup Initialization](setup.md) steps, -and have ensured that all the necessary environment variables have been properly set, it is time to deploy QHub -from your terminal. +Great, you've gone through the `qhub` [Installation](installation.md) and [Setup Initialization](setup.md) steps, and have ensured that all the necessary environment variables have +been properly set, it is time to deploy QHub from your terminal. ### Initialize configuration -There are several ways to generate your configuration file. You can -type the commands when prompted by terminal, or you can set -it all automatically from the start. In any case, we advise you to -start by creating a new project folder. Here, we will name the new -folder `qhub-test`. +There are several ways to generate your configuration file. You can type the commands when prompted by terminal, or you can set it all automatically from the start. In any case, we +advise you to start by creating a new project folder. Here, we will name the new folder `qhub-test`. On your terminal run: @@ -32,27 +28,29 @@ qhub init aws \ --auth-provider auth0 --auth-auto-provision \ --ssl-cert-email admin@test.com ``` -There are several **optional** (yet highly recommended) flags that -allow to configure the deployment: + +There are several **optional** (yet highly recommended) flags that allow to configure the deployment: The command above will generate the `qhub-config.yaml` config file with an infrastructure deployed on `aws`, named `projectname`, where the domain will be `qhub.dev`. -The deployment will use `github-actions` as the continuous integration (CI) provider, automatically provisioning a repository on GitHub under the URL `github.com/quansight/projectname` +The deployment will use `github-actions` as the continuous integration (CI) provider, automatically provisioning a repository on GitHub under the URL +`github.com/quansight/projectname` User authentication will be by `auth0`, and an OAuth 2.0 app will be created on Auth0 automatically. There are several flags that allow you to configure the deployment: - `aws` indicates that the project will be deployed on the Amazon AWS Cloud provider. - + Optional flags are: `gcp`, `do` and `azure`. -- `--project`: the name of the project is required to be a string compliant with the Cloud provider recommendations. For - more details see official Cloud provider docs on naming policies and see below on the [project naming convention](#project-naming-convention). + - Optional flags are: `gcp`, `do` and `azure`. +- `--project`: the name of the project is required to be a string compliant with the Cloud provider recommendations. For more details see official Cloud provider docs on naming + policies and see below on the [project naming convention](#project-naming-convention). - `--domain`: base domain for your cluster. This pattern is also applicable if you are setting your own DNS through a different provider. - + `qhub.dev` is the domain registered on CloudFlare. If you chose not to use Cloudflare, skip this flag. + - `qhub.dev` is the domain registered on CloudFlare. If you chose not to use Cloudflare, skip this flag. - `--ci-provider`: specifies what provider to use for CI/CD. Currently, supports GitHub Actions, GitLab CI, or none. - `--auth-provider`: This will set configuration file to use the specified provider for authentication. - `--auth-auto-provision`: This will automatically create and configure an application using OAuth. - `--repository`: Repository name that will be used to store the Infrastructure-as-Code on GitHub. - `--repository-auto-provision`: Sets the secrets for the GitHub repository used for CI/CD actions. -- `--ssl-cert-email`: Provide an admin's email address so that LetsEncrypt can generate a real SSL certificate for your site. If omitted, the site will use a self-signed cert that may cause problems for some browsers but may be sufficient for testing. +- `--ssl-cert-email`: Provide an admin's email address so that LetsEncrypt can generate a real SSL certificate for your site. If omitted, the site will use a self-signed cert that + may cause problems for some browsers but may be sufficient for testing. You will be prompted to enter values for some of the choices above if they are omitted as command line arguments (for example project name and domain). @@ -62,42 +60,43 @@ The `qhub init` command also generates an initial password for your root Keycloa Securely generated default random password=R1E8aWedaQVU6kKv for Keycloak root user stored at path=/tmp/QHUB_DEFAULT_PASSWORD ``` -This password is also available in the `qhub-config.yaml` file under the `security.keycloak.initial_root_password field`. It's required in the next page of these docs for logging in to your QHub. +This password is also available in the `qhub-config.yaml` file under the `security.keycloak.initial_root_password field`. It's required in the next page of these docs for logging +in to your QHub. -This `qhub init` command generates the `qhub-config.yaml` config file -with an infrastructure to be deployed on `aws`, named `projectname`, with a -domain name set to `qhub.dev`. The deployment uses `github-actions` as -the continuous integration provider, -automatically provisioned and authenticated by `auth0`. And finally, initialized on -GitHub under the URL `github.com/quansight/projectname`. +This `qhub init` command generates the `qhub-config.yaml` config file with an infrastructure to be deployed on `aws`, named `projectname`, with a domain name set to `qhub.dev`. The +deployment uses `github-actions` as the continuous integration provider, automatically provisioned and authenticated by `auth0`. And finally, initialized on GitHub under the URL +`github.com/quansight/projectname`. -If employing an infrastructure-as-code approach, this is where you would make the desired infrastructure changes -including adding users, changing Dask worker instance type and much more. Once you're happy with your changes you would redeploy those changes using GitHub Actions. For more details on the `qhub-config.yaml` please see [Configuration](configuration.md) +If employing an infrastructure-as-code approach, this is where you would make the desired infrastructure changes including adding users, changing Dask worker instance type and much +more. Once you're happy with your changes you would redeploy those changes using GitHub Actions. For more details on the `qhub-config.yaml` please see +[Configuration](configuration.md) -The proceeding command will generate the `qhub-config.yaml` config file -with an infrastructure deployed on `aws`, named `projectname`, where -the domain will be `qhub.dev`. The deployment -will use `github-actions` as the continuous integration (CI) provider, -automatically provisioned and authenticated by `auth0`, initialized on -GitHub under the URL `github.com/quansight/projectname`. +The proceeding command will generate the `qhub-config.yaml` config file with an infrastructure deployed on `aws`, named `projectname`, where the domain will be `qhub.dev`. The +deployment will use `github-actions` as the continuous integration (CI) provider, automatically provisioned and authenticated by `auth0`, initialized on GitHub under the URL +`github.com/quansight/projectname`. -If employing an infrastructure-as-code approach, this is where you would make the desired infrastructure changes -including adding environments, changing Dask worker instance type and much more. Once you're happy with your changes you would redeploy those changes using GitHub Actions. For more details on the `qhub-config.yaml` please see [Configuration](configuration.md) +If employing an infrastructure-as-code approach, this is where you would make the desired infrastructure changes including adding environments, changing Dask worker instance type +and much more. Once you're happy with your changes you would redeploy those changes using GitHub Actions. For more details on the `qhub-config.yaml` please see +[Configuration](configuration.md) ##### Project Naming Convention -In order to successfully deploy QHub, there are some project naming conventions which need to be followed. For starters, -make sure your project name is compatible with the specifics of your chosen Cloud provider. In addition, QHub `projectname` -should also obey to the following format requirements: -> + letters from A to Z (upper and lower case) and numbers; -> + Special characters are **NOT** allowed; -> + Maximum accepted length of the name string is 16 characters. -> + If using AWS names **SHOULD NOT** start with the string `aws` + +In order to successfully deploy QHub, there are some project naming conventions which need to be followed. For starters, make sure your project name is compatible with the +specifics of your chosen Cloud provider. In addition, QHub `projectname` should also obey to the following format requirements: + +> - letters from A to Z (upper and lower case) and numbers; +> - Special characters are **NOT** allowed; +> - Maximum accepted length of the name string is 16 characters. +> - If using AWS names **SHOULD NOT** start with the string `aws` ### Understanding the qhub-config.yaml file -The `qhub init` command may have some side-effects such automatically creating a GitHub repository and setting some repo secrets (if you used the `--repository-auto-provision` flag), and creating an Auth0 app, but the main output of the command is the `qhub-config.yaml` file. +The `qhub init` command may have some side-effects such automatically creating a GitHub repository and setting some repo secrets (if you used the `--repository-auto-provision` +flag), and creating an Auth0 app, but the main output of the command is the `qhub-config.yaml` file. -This file is the configuration file that will determine how the cloud infrastructure and QHub is built and deployed in the next step. But at this point it's just a text file. You could edit it manually if you are unhappy with the choices, or delete it and start over again. It is also possible to create this config file from scratch or re-use an existing one. Ulimately it's not essential to use `qhub init` at all, but it's often the easiest way to get started. +This file is the configuration file that will determine how the cloud infrastructure and QHub is built and deployed in the next step. But at this point it's just a text file. You +could edit it manually if you are unhappy with the choices, or delete it and start over again. It is also possible to create this config file from scratch or re-use an existing +one. Ulimately it's not essential to use `qhub init` at all, but it's often the easiest way to get started. To understand some ways in which you could decide to edit the YAML file, see [Advanced Configuration](configuration.md). @@ -108,6 +107,7 @@ Finally, with the `qhub-config.yaml` created, QHub can be deployed for the first ```shell qhub deploy -c qhub-config.yaml --dns-provider cloudflare --dns-auto-provision ``` + > Omit `--dns-provider cloudflare --dns-auto-provision` if you are not using Cloudflare and will set up your DNS manually. This creates the following folder structure: @@ -124,20 +124,22 @@ This creates the following folder structure: └── terraform-state # required by terraform to securely store the state of the deployment ``` -The terminal will prompt you to press `[enter]` to check auth credentials -(which were added by the `qhub init` command). That will trigger the -deployment which will take around 10 minutes to complete. +The terminal will prompt you to press `[enter]` to check auth credentials (which were added by the `qhub init` command). That will trigger the deployment which will take around 10 +minutes to complete. During the initial deployment, Digital Ocean, GCP and Azure are going to display an `"ip"` address whereas AWS is going to display a CNAME `"hostname"`. -+ Digital Ocean/Google Cloud Platform +- Digital Ocean/Google Cloud Platform + ```shell ingress_jupyter = { "hostname" = "" "ip" = "xxx.xxx.xxx.xxx" } ``` -+ AWS: + +- AWS: + ```shell ingress_jupyter = { "hostname" = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxx.us-east-1.elb.amazonaws.com" @@ -145,12 +147,14 @@ During the initial deployment, Digital Ocean, GCP and Azure are going to display } ``` -If you specified `--dns-provider cloudflare --dns-auto-provision` on the command line, your DNS records for your domain should be updated automatically on Cloudflare. If you omitted those flags, you will be prompted to set the A/CNAME records manually on your domain name registrar's nameservers. +If you specified `--dns-provider cloudflare --dns-auto-provision` on the command line, your DNS records for your domain should be updated automatically on Cloudflare. If you +omitted those flags, you will be prompted to set the A/CNAME records manually on your domain name registrar's nameservers. ### GitOps -If you chose `--ci-provider github-actions` (or `gitlab-ci`) then QHub will use a GitHub Actions workflow (or GitLab equivalent) to automatically handle future deployment of -the infrastructure. For that to work, your newly generated project must be pushed to GitHub. Using the URL under the `--repository` flag on the `qhub init` command, you need to commit all files to the git repo. +If you chose `--ci-provider github-actions` (or `gitlab-ci`) then QHub will use a GitHub Actions workflow (or GitLab equivalent) to automatically handle future deployment of the +infrastructure. For that to work, your newly generated project must be pushed to GitHub. Using the URL under the `--repository` flag on the `qhub init` command, you need to commit +all files to the git repo. To add the project to the initialized remote git repository run: @@ -165,17 +169,14 @@ Push the changes to the repository (your primary branch may be called `master` i git push origin main ``` -Once the files are in GitHub, all CI/CD changes will be triggered by -commits to main, and deployed via GitHub Actions. Since the -infrastructure state is reflected in the repository, this workflow -allows for team members to submit pull requests that can be reviewed -before modifying the infrastructure, easing the maintenance process. +Once the files are in GitHub, all CI/CD changes will be triggered by commits to main, and deployed via GitHub Actions. Since the infrastructure state is reflected in the +repository, this workflow allows for team members to submit pull requests that can be reviewed before modifying the infrastructure, easing the maintenance process. To automatically deploy (and to keep track of changes more effectively): + - make changes to the `qhub-config.yaml` file on a new branch. - create a pull request (PR) to main. -- Trigger the deployment by merging the PR. All changes will be - automatically applied to the new QHub instance. +- Trigger the deployment by merging the PR. All changes will be automatically applied to the new QHub instance. Having issues? Head over to our [Troubleshooting](../admin_guide/troubleshooting.md) section for tips on how to debug your QHub. Or try our [FAQ](../admin_guide/faq.md). diff --git a/docs/source/introduction/index.md b/docs/source/introduction/index.md index 970f7dd1e..2a697dd43 100644 --- a/docs/source/introduction/index.md +++ b/docs/source/introduction/index.md @@ -2,9 +2,11 @@ QHub is an open source tool for data science research, development, and deployment. -QHub is [**Infrastructure as Code**](https://en.wikipedia.org/wiki/Infrastructure_as_code) that simplifies the deployment of data science projects using JupyterHub and Dask Gateway for you and your team. +QHub is [**Infrastructure as Code**](https://en.wikipedia.org/wiki/Infrastructure_as_code) that simplifies the deployment of data science projects using JupyterHub and Dask Gateway +for you and your team. -Designed to simplify the deployment and maintenance of scalable computational platforms in the cloud, QHub is ideal for organizations that need a shared compute platform that's flexible, accessible, and scalable. +Designed to simplify the deployment and maintenance of scalable computational platforms in the cloud, QHub is ideal for organizations that need a shared compute platform that's +flexible, accessible, and scalable. ## QHub Technology Stack @@ -14,49 +16,48 @@ Designed to simplify the deployment and maintenance of scalable computational pl The technology stack is an integration of the following existing open source libraries: -+ [**Terraform**](https://www.terraform.io/intro/index.html) a tool for building, changing, and versioning infrastructure. -+ [**Kubernetes**](https://kubernetes.io/docs/home/) a cloud-agnostic orchestration system -+ [**Helm**](https://helm.sh/): a package manager for Kubernetes -+ [**JupyterHub**](https://jupyter.org/hub): a shareable compute platform for data science -+ [**JupyterLab**](https://jupyterlab.readthedocs.io/en/stable/): a web-based interactive development environment for Jupyter Notebooks -+ [**Dask**](https://docs.dask.org/en/latest/): a scalable and flexible library for parallel computing in Python - + [**Dask-Gateway**](https://gateway.dask.org/): a secure, multi-tenant server for managing Dask clusters -+ [**Keycloak**](https://www.keycloak.org/) Open Source Identity and Access Management -+ [**GitHub Actions**](https://docs.github.com/en/actions): a tool to automate, customize, and execute software - development workflows in a GitHub repository. -+ [**traefik**](https://traefik.io/) for routing web/tcp traffic inside cluster - + [**traefik-forward-auth**](https://github.com/thomseddon/traefik-forward-auth) single sign on and easy securing of web applications +- [**Terraform**](https://www.terraform.io/intro/index.html) a tool for building, changing, and versioning infrastructure. +- [**Kubernetes**](https://kubernetes.io/docs/home/) a cloud-agnostic orchestration system +- [**Helm**](https://helm.sh/): a package manager for Kubernetes +- [**JupyterHub**](https://jupyter.org/hub): a shareable compute platform for data science +- [**JupyterLab**](https://jupyterlab.readthedocs.io/en/stable/): a web-based interactive development environment for Jupyter Notebooks +- [**Dask**](https://docs.dask.org/en/latest/): a scalable and flexible library for parallel computing in Python + - [**Dask-Gateway**](https://gateway.dask.org/): a secure, multi-tenant server for managing Dask clusters +- [**Keycloak**](https://www.keycloak.org/) Open Source Identity and Access Management +- [**GitHub Actions**](https://docs.github.com/en/actions): a tool to automate, customize, and execute software development workflows in a GitHub repository. +- [**traefik**](https://traefik.io/) for routing web/tcp traffic inside cluster + - [**traefik-forward-auth**](https://github.com/thomseddon/traefik-forward-auth) single sign on and easy securing of web applications Amongst the newly created open source libraries on the tech stack are: -+ [**jupyterhub-ssh**](https://github.com/yuvipanda/jupyterhub-ssh) brings the SSH experience to a modern cluster manager. -+ [**jupyter-videochat**](https://github.com/yuvipanda/jupyter-videochat) allows video-chat with JupyterHub peers inside - JupyterLab, powered by Jitsi. -+ [**conda-store**](https://github.com/quansight/conda-store) serves identical conda environments and controls its life-cycle. -+ [**conda-docker**](https://github.com/conda-incubator/conda-docker), an extension to the docker concept of having - declarative environments that are associated with Docker images allowing tricks and behaviour that otherwise would not be allowed. -+ [**vscode**](https://github.com/cdr/code-server) built-in web editor tied to jupyterlab server + +- [**jupyterhub-ssh**](https://github.com/yuvipanda/jupyterhub-ssh) brings the SSH experience to a modern cluster manager. +- [**jupyter-videochat**](https://github.com/yuvipanda/jupyter-videochat) allows video-chat with JupyterHub peers inside JupyterLab, powered by Jitsi. +- [**conda-store**](https://github.com/quansight/conda-store) serves identical conda environments and controls its life-cycle. +- [**conda-docker**](https://github.com/conda-incubator/conda-docker), an extension to the docker concept of having declarative environments that are associated with Docker images + allowing tricks and behaviour that otherwise would not be allowed. +- [**vscode**](https://github.com/cdr/code-server) built-in web editor tied to jupyterlab server ### Integrations In an effort for QHub to serve as a core that services can integrate with. -+ [**prefect**](https://www.prefect.io/) workflow management -+ [**clearml**](https://clear.ml/) machine learning platform -+ [**prometheus**](https://prometheus.io/) cluster monitoring -+ [**grafana**](https://grafana.com/) cluster monitoring visualizations +- [**prefect**](https://www.prefect.io/) workflow management +- [**clearml**](https://clear.ml/) machine learning platform +- [**prometheus**](https://prometheus.io/) cluster monitoring +- [**grafana**](https://grafana.com/) cluster monitoring visualizations ## Why use QHub? QHub provides enables teams to build their own scalable compute infrastructure with: -+ Easy installation and maintenance controlled by a single configuration file. -+ Autoscaling JupyterHub installation deployed on the Cloud provider of your choice. -+ Option to choose from multiple compute instances, such as: **namely normal**, **high memory**, **GPU**, etc. -+ Autoscaling Dask compute clusters for big data using any instance type. -+ Shell access and remote editing access (VSCode remote) through KubeSSH. -+ Shared filesystem allowing users to work on projects privately, within groups, or across the organisation. -+ Robust compute environment handling allowing both prebuilt and ad-hoc environment creation. -+ Integrated video conferencing, using [Jitsi](https://meet.jit.si/). +- Easy installation and maintenance controlled by a single configuration file. +- Autoscaling JupyterHub installation deployed on the Cloud provider of your choice. +- Option to choose from multiple compute instances, such as: **namely normal**, **high memory**, **GPU**, etc. +- Autoscaling Dask compute clusters for big data using any instance type. +- Shell access and remote editing access (VSCode remote) through KubeSSH. +- Shared filesystem allowing users to work on projects privately, within groups, or across the organisation. +- Robust compute environment handling allowing both prebuilt and ad-hoc environment creation. +- Integrated video conferencing, using [Jitsi](https://meet.jit.si/). ```{toctree} :maxdepth: 2 diff --git a/docs/source/introduction/qhub-101.md b/docs/source/introduction/qhub-101.md index ea1368b71..6fc3874bc 100644 --- a/docs/source/introduction/qhub-101.md +++ b/docs/source/introduction/qhub-101.md @@ -1,8 +1,10 @@ # QHub 101 -QHub is an open source framework that allows data science team to initialize and maintain their data science stack on cloud. QHub makes use of Terraform to deploy JupyterHub, JupyterLab, Dask, and Conda environments on Kubernetes clusters across all major cloud providers. +QHub is an open source framework that allows data science team to initialize and maintain their data science stack on cloud. QHub makes use of Terraform to deploy JupyterHub, +JupyterLab, Dask, and Conda environments on Kubernetes clusters across all major cloud providers. -Through QHub, the deployment is managed using a single configuration file and is powered by GitHub Actions. This allows teams to build and maintain cost-effective and scalable infrastructure for compute/data science on cloud or on-premises. QHub is designed to be used and deployed by anyone, requiring minimal DevOps experience. +Through QHub, the deployment is managed using a single configuration file and is powered by GitHub Actions. This allows teams to build and maintain cost-effective and scalable +infrastructure for compute/data science on cloud or on-premises. QHub is designed to be used and deployed by anyone, requiring minimal DevOps experience. ## Features @@ -25,9 +27,11 @@ The QHub architecture facilitates: - Seamless deployment with GitHub Actions using a single configuration file. - Allow multiple teams to collaborate together with control permissions. -At a high-level, QHub makes use of Network File System (NFS) to provide storage access to Kubernetes applications. This creates a Kubernetes Persistent Volume that allows NFS to share files directly. With the aid of Dask integration and environment management with conda-store, QHub provides users with a simple deployment process. +At a high-level, QHub makes use of Network File System (NFS) to provide storage access to Kubernetes applications. This creates a Kubernetes Persistent Volume that allows NFS to +share files directly. With the aid of Dask integration and environment management with conda-store, QHub provides users with a simple deployment process. -For infrastructure provisioning, QHub uses Terraform to deploy Kubernetes clusters on AWS, GCP, Azure, and Digital Ocean. For Kubernetes deployments, QHub uses Helm Charts to allow ease of distribution and to deploy QHub on any Kubernetes cluster. +For infrastructure provisioning, QHub uses Terraform to deploy Kubernetes clusters on AWS, GCP, Azure, and Digital Ocean. For Kubernetes deployments, QHub uses Helm Charts to allow +ease of distribution and to deploy QHub on any Kubernetes cluster. To learn more about the nitty gritty of QHub's internal architecture, refer to the [QHub Architecture](../dev_guide/architecture.md) section. @@ -35,33 +39,40 @@ To learn more about the nitty gritty of QHub's internal architecture, refer to t QHub can be easily installed using either `conda` or `pip`. -- `conda`: - `conda install -c conda-forge qhub` -- `pip`: - `pip install qhub` +- `conda`: `conda install -c conda-forge qhub` +- `pip`: `pip install qhub` -QHub CLI will be installed automatically as part of the install process. After installation, QHub CLI can be used to deploy and manage your environment on HPC, cloud, on-premises or even locally. To install QHub locally, follow the [testing](../dev_guide/testing.md) section. +QHub CLI will be installed automatically as part of the install process. After installation, QHub CLI can be used to deploy and manage your environment on HPC, cloud, on-premises +or even locally. To install QHub locally, follow the [testing](../dev_guide/testing.md) section. -For HPC deployment, follow the [QHub HPC](https://hpc.qhub.dev/en/latest/) documentation. For individual cloud deployment, follow the [installation instructions](../installation/setup.md). After setting up all the credentials, you can deploy QHub using: +For HPC deployment, follow the [QHub HPC](https://hpc.qhub.dev/en/latest/) documentation. For individual cloud deployment, follow the +[installation instructions](../installation/setup.md). After setting up all the credentials, you can deploy QHub using: ```sh qhub init qhub deploy ``` -After installing QHub, you can further manage your deployment by adding new users, upgrading dependencies, managing your environment, and monitoring your deployment. Refer to the [management instructions](../installation/management.md) for more details. +After installing QHub, you can further manage your deployment by adding new users, upgrading dependencies, managing your environment, and monitoring your deployment. Refer to the +[management instructions](../installation/management.md) for more details. ## Using QHub -After setting up QHub, you can visit the URL where QHub is running. Based on your authentication mechanism, you will be greeted by a login page after which the user will be prompted to use a set of profile available to them. With fixed resources allocated to each user, you can start a cluster by clicking `Start` which will initiate the launch. +After setting up QHub, you can visit the URL where QHub is running. Based on your authentication mechanism, you will be greeted by a login page after which the user will be +prompted to use a set of profile available to them. With fixed resources allocated to each user, you can start a cluster by clicking `Start` which will initiate the launch. -After the launch, you will be greeted by specific Python environments, which when clicked will start a JupyterLab notebook. To use VS Code, you can use Code Server by clicking `VS Code IDE` icon. To remotely access the clusters, use the [jupyterhub-ssh](https://github.com/yuvipanda/jupyterhub-ssh) extension. For further usage instructions, follow the [using QHub](../user_guide/index.md) section. +After the launch, you will be greeted by specific Python environments, which when clicked will start a JupyterLab notebook. To use VS Code, you can use Code Server by clicking +`VS Code IDE` icon. To remotely access the clusters, use the [jupyterhub-ssh](https://github.com/yuvipanda/jupyterhub-ssh) extension. For further usage instructions, follow the +[using QHub](../user_guide/index.md) section. ## Community & support -QHub is supported by the [Quansight](https://quansight.com) community. We maintain a [Frequently Asked Questions (FAQ) page](https://github.com/Quansight/qhub/blob/main/docs/source/user_guide/faq.md) for QHub users. For QHub queries, we ideally rely upon the following channels: +QHub is supported by the [Quansight](https://quansight.com) community. We maintain a +[Frequently Asked Questions (FAQ) page](https://github.com/Quansight/qhub/blob/main/docs/source/user_guide/faq.md) for QHub users. For QHub queries, we ideally rely upon the +following channels: -- [GitHub Discussions](https://github.com/Quansight/qhub/discussions): Raise discussions around particular subjects and specific queries around usage, maintenance and administration. +- [GitHub Discussions](https://github.com/Quansight/qhub/discussions): Raise discussions around particular subjects and specific queries around usage, maintenance and + administration. - [GitHub Issues](https://github.com/Quansight/qhub/issues/new/choose): Use Issues to report bugs, request new features, new documentation or potential refactors. @@ -69,4 +80,5 @@ QHub is supported by the [Quansight](https://quansight.com) community. We mainta QHub welcomes new contributors. If you are interested in contributing to QHub, please refer to the [contributing guide](../dev_guide/contribution.md) for more details. -We require contributors to strictly follow our [Code of Conduct](https://github.com/Quansight/.github/blob/master/CODE_OF_CONDUCT.md) and propose features, bug fixes and documentation changes on our [issues page](https://github.com/Quansight/qhub/issues/new/choose). +We require contributors to strictly follow our [Code of Conduct](https://github.com/Quansight/.github/blob/master/CODE_OF_CONDUCT.md) and propose features, bug fixes and +documentation changes on our [issues page](https://github.com/Quansight/qhub/issues/new/choose). diff --git a/docs/source/user_guide/code_server.md b/docs/source/user_guide/code_server.md index d1aac6933..7aaff6d34 100644 --- a/docs/source/user_guide/code_server.md +++ b/docs/source/user_guide/code_server.md @@ -1,16 +1,11 @@ # In Browser VSCode -Code Server is a packaging of VS Code in the browser. Within QHub we -have packaged Code Server such that every user's JupyterLab has a -full-featured code editor. This editor will have access to all the same -files that your regular JupyterLab session has access to. To launch -`Code Server` click on the `VS Code IDE` icon from the Launcher screen, see below. +Code Server is a packaging of VS Code in the browser. Within QHub we have packaged Code Server such that every user's JupyterLab has a full-featured code editor. This editor will +have access to all the same files that your regular JupyterLab session has access to. To launch `Code Server` click on the `VS Code IDE` icon from the Launcher screen, see below. ![QHub Kernel Selection](../images/qhub_kernel_selection.png) -A new VS Code tab will be opened, and from there you can access -all of the same files as in your JupyterLab file browser. The VS Code -state will be saved between sessions so feel free to add extensions, -plugins, etc. to enhance your user experience. +A new VS Code tab will be opened, and from there you can access all of the same files as in your JupyterLab file browser. The VS Code state will be saved between sessions so feel +free to add extensions, plugins, etc. to enhance your user experience. ![VSCode in browser](../images/qhub_vscode.png) diff --git a/docs/source/user_guide/dashboard.md b/docs/source/user_guide/dashboard.md index a87de34e0..18e1a6309 100644 --- a/docs/source/user_guide/dashboard.md +++ b/docs/source/user_guide/dashboard.md @@ -1,16 +1,12 @@ # Dashboards -QHub encourages users to create dashboards that can be shared with other -users and groups via [ContainDS -Dashboards](https://cdsdashboards.readthedocs.io/en/stable/). Currently, -this dashboarding solution supports Panel, Bokeh, Voila, Streamlit, -and Plotly. The solution is general purpose enough to support any web app. For a more detailed guide on using CDSDashboards, see the -[documentation](https://cdsdashboards.readthedocs.io/en/stable/index.html). +QHub encourages users to create dashboards that can be shared with other users and groups via [ContainDS Dashboards](https://cdsdashboards.readthedocs.io/en/stable/). Currently, +this dashboarding solution supports Panel, Bokeh, Voila, Streamlit, and Plotly. The solution is general purpose enough to support any web app. For a more detailed guide on using +CDSDashboards, see the [documentation](https://cdsdashboards.readthedocs.io/en/stable/index.html). ![qhub dashboard notebook](../images/qhub_dashboard_notebook.png) -Create a notebook in your jupyterlab environment with the following -code in a notebook named `mydashboard.ipynb` in the home directory. +Create a notebook in your jupyterlab environment with the following code in a notebook named `mydashboard.ipynb` in the home directory. ```python import panel @@ -30,38 +26,25 @@ dashboard = panel.Row(content, png, widget) dashboard.servable() ``` -Once you execute the notebook you should see the output shown -above. We will now show how to create a dashboard from this -notebook. Keep in mind that for other dashboard-based solutions, -for example Voila, the instructions will be slightly different, -in which case we recommend visiting the [cds -docs](https://cdsdashboards.readthedocs.io/en/stable/index.html). Visit -your hub homepage which is at `https:///hub/dashboards` or -click the dashboard tab in the hub home menu. +Once you execute the notebook you should see the output shown above. We will now show how to create a dashboard from this notebook. Keep in mind that for other dashboard-based +solutions, for example Voila, the instructions will be slightly different, in which case we recommend visiting the +[cds docs](https://cdsdashboards.readthedocs.io/en/stable/index.html). Visit your hub homepage which is at `https:///hub/dashboards` or click the dashboard tab in the hub +home menu. ![qhub dashboard new](../images/qhub_new_dashboard.png) -Click `New Dashboard` and give the dashboard any name and -description. For now, allow `all users` and use the `jupyter -tree`. Note that `bokeh` was selected for the framework since panel -uses bokeh under the covers. Choose the conda environment -`dashboard`. Finally, supply a relative path to the dashboard you would -like to launch. In this case `./mydashboard.ipynb` since this is the -name of the dashboard created above in the notebook. +Click `New Dashboard` and give the dashboard any name and description. For now, allow `all users` and use the `jupyter tree`. Note that `bokeh` was selected for the framework since +panel uses bokeh under the covers. Choose the conda environment `dashboard`. Finally, supply a relative path to the dashboard you would like to launch. In this case +`./mydashboard.ipynb` since this is the name of the dashboard created above in the notebook. ![qhub new dashboard filled in](../images/qhub_new_dashboard_filled_in.png) -Once you have saved the dashboard, you will be taken to the screen to -select the resources the dashboard will have available to it. +Once you have saved the dashboard, you will be taken to the screen to select the resources the dashboard will have available to it. ![qhub dashboard resources](../images/qhub_dashboard_resources.png) -Once the resources have been chosen, click save and the dashboard will launch. This -should provide a dedicated url that you can share with other QHub -users to view the dashboard. In the case of this dashboard the url was -`https://training.qhub.dev/user/costrouchov@quansight.com/dash-my-awesome-dashboard/`, -but your url will be different. The url will force authentication for the -user to view the dashboard. The dashboard for the notebook in this example is -shown below. +Once the resources have been chosen, click save and the dashboard will launch. This should provide a dedicated url that you can share with other QHub users to view the dashboard. +In the case of this dashboard the url was `https://training.qhub.dev/user/costrouchov@quansight.com/dash-my-awesome-dashboard/`, but your url will be different. The url will force +authentication for the user to view the dashboard. The dashboard for the notebook in this example is shown below. ![qhub dashboard simple](../images/qhub_dashboard_simple.png) diff --git a/docs/source/user_guide/dask_gateway.md b/docs/source/user_guide/dask_gateway.md index 21b48a193..6737b405f 100644 --- a/docs/source/user_guide/dask_gateway.md +++ b/docs/source/user_guide/dask_gateway.md @@ -1,6 +1,7 @@ # Using Dask Gateway -[Dask Gateway](https://gateway.dask.org/) provides a secure way to managing dask clusters. QHub uses dask-gateway to expose auto-scaling compute clusters automatically configured for the user. For a full guide on dask-gateway please [see the docs](https://gateway.dask.org/usage.html). However here we try to detail the important usage on QHub. +[Dask Gateway](https://gateway.dask.org/) provides a secure way to managing dask clusters. QHub uses dask-gateway to expose auto-scaling compute clusters automatically configured +for the user. For a full guide on dask-gateway please [see the docs](https://gateway.dask.org/usage.html). However here we try to detail the important usage on QHub. QHub already has the connection information pre-configured for the user. If you would like to see the pre-configured settings, run @@ -8,9 +9,9 @@ QHub already has the connection information pre-configured for the user. If you cat /etc/dask/gateway.yaml ``` - - `address` :: is the rest API that dask-gateway exposes for managing clusters - - `proxy_address` :: is a secure tls connection to a user-started dask scheduler - - `auth` is the form of authentication used, which should always be `jupyterhub` for QHub +- `address` :: is the rest API that dask-gateway exposes for managing clusters +- `proxy_address` :: is a secure tls connection to a user-started dask scheduler +- `auth` is the form of authentication used, which should always be `jupyterhub` for QHub ## Starting a Cluster @@ -19,8 +20,10 @@ from dask_gateway import Gateway gateway = Gateway() ``` -QHub has [a section](https://docs.qhub.dev/en/stable/source/installation/configuration.html#profiles) for configuring the dask profiles that users have access to. These can -be accessed via Dask Gateway options. Once the [ipywidget](https://ipywidgets.readthedocs.io/en/latest/) shows up the user can select the options they care about. If you are interacting in a terminal there are also ways to configure the options. Please see the dask-gateway docs. It's important that the environment used for your notebook matches the dask worker environment. +QHub has [a section](https://docs.qhub.dev/en/stable/source/installation/configuration.html#profiles) for configuring the dask profiles that users have access to. These can be +accessed via Dask Gateway options. Once the [ipywidget](https://ipywidgets.readthedocs.io/en/latest/) shows up the user can select the options they care about. If you are +interacting in a terminal there are also ways to configure the options. Please see the dask-gateway docs. It's important that the environment used for your notebook matches the +dask worker environment. ![qhub dask options](../images/qhub_dask_cluster_options.png) @@ -38,13 +41,16 @@ cluster = gateway.new_cluster(options) cluster ``` -The user is presented with a GUI to scale up the number of workers. At first, users start with `0` workers. In addition you can scale up via Python functions. Additionally the GUI has a `dashboard` link that you can click to view [cluster diagnostics](https://docs.dask.org/en/latest/diagnostics-distributed.html). This link is especially useful for debugging and benchmarking. +The user is presented with a GUI to scale up the number of workers. At first, users start with `0` workers. In addition you can scale up via Python functions. Additionally the GUI +has a `dashboard` link that you can click to view [cluster diagnostics](https://docs.dask.org/en/latest/diagnostics-distributed.html). This link is especially useful for debugging +and benchmarking. ```python cluster.scale(1) ``` -Once you have created a cluster and scaled to an appropriate number of workers we can grab our dask client to start the computation. You may also use the cluster menu with the dashboard link to scale the number of workers. +Once you have created a cluster and scaled to an appropriate number of workers we can grab our dask client to start the computation. You may also use the cluster menu with the +dashboard link to scale the number of workers. ```python client = cluster.get_client() @@ -66,7 +72,7 @@ If a result was returned, your cluster is working. Dask Gateway allows users to configure their clusters via cluster options. Here are some configuration options exposed in QHub's Dask Gateway deployment. -* Get cluster options +- Get cluster options ```python import dask_gateway @@ -93,14 +99,18 @@ Note: The above configuration options are valid for QHub's Dask Gateway deployme ## Accessing Cluster Outside of QHub -A long requested feature was the ability to access a dask cluster from outside of the cluster itself. In general this is possible but at the moment can break due to version mismatches between [dask](https://dask.org/), [distributed](https://distributed.dask.org/en/latest/), and [dask-gateway](https://gateway.dask.org/). Also we have had issues with other libraries not matching so don't consider this check exhaustive. At a minimum, check that your local environment matches. It's possible that it will work if the versions don't match exactly, but it's not recommended. +A long requested feature was the ability to access a dask cluster from outside of the cluster itself. In general this is possible but at the moment can break due to version +mismatches between [dask](https://dask.org/), [distributed](https://distributed.dask.org/en/latest/), and [dask-gateway](https://gateway.dask.org/). Also we have had issues with +other libraries not matching so don't consider this check exhaustive. At a minimum, check that your local environment matches. It's possible that it will work if the versions don't +match exactly, but it's not recommended. ```python import dask, distributed, dask_gateway print(dask.__version__, distributed.__version__, dask_gateway.__version__) ``` -Next you need to supply a JupyterHub API token to validate with the Dask Gateway API. This was not required within QHub since this is automatically set in JupyterLab sessions. There are several ways to get a JupyterHub API token. +Next you need to supply a JupyterHub API token to validate with the Dask Gateway API. This was not required within QHub since this is automatically set in JupyterLab sessions. +There are several ways to get a JupyterHub API token. The easiest way is to visit `https:///hub/token` when you are logged in and click `Request new API token`. This should show a long string to copy as your API token. @@ -115,7 +125,8 @@ Finally you will need to manually configure the `Gateway` connection parameters. gateway = Gateway(address='https:///gateway', auth='jupyterhub', proxy_address='tcp://:8786') ``` -Now your gateway is properly configured. You can follow the usage tutorial above. If your dask, distributed, and dask-gateway versions don't match, connecting to these APIs may (most likely will) break in unexpected ways. +Now your gateway is properly configured. You can follow the usage tutorial above. If your dask, distributed, and dask-gateway versions don't match, connecting to these APIs may +(most likely will) break in unexpected ways. ## Common Errors @@ -130,4 +141,5 @@ ValueError: 404: Not Found This error is due to a version mismatch between the dask-gateway client and dask-gateway server. -If you get `struct unpack` related errors when using dask this is most likely a mismatch in versions for [Dask](https://pypi.org/project/dask/) or [distributed](https://pypi.org/project/distributed/). The last issue Quansight has run into was due to the version of bokeh being used for the dask dashboard. +If you get `struct unpack` related errors when using dask this is most likely a mismatch in versions for [Dask](https://pypi.org/project/dask/) or +[distributed](https://pypi.org/project/distributed/). The last issue Quansight has run into was due to the version of bokeh being used for the dask dashboard. diff --git a/docs/source/user_guide/environments.md b/docs/source/user_guide/environments.md index 73e5ca524..8c883ad05 100644 --- a/docs/source/user_guide/environments.md +++ b/docs/source/user_guide/environments.md @@ -1,8 +1,7 @@ # Managing Conda Environments -QHub has several ways to manage environments for users. The traditional -approach, available in older QHub deployments, is still available by editing the -`qhub-config.yaml` `environments:` key within the configuration file. Here's an example: +QHub has several ways to manage environments for users. The traditional approach, available in older QHub deployments, is still available by editing the `qhub-config.yaml` +`environments:` key within the configuration file. Here's an example: ```yaml environments: @@ -21,27 +20,16 @@ environments: - pandas ``` -When the environments are updated in this file and an automated `qhub deploy` -is kicked off, the environments are updated for all users. There is also a way to -easily create ad-hoc environments without modifying the file. Visiting -`https:///conda-store/` will take you to -[Conda-Store](https://conda-store.readthedocs.io/en/latest/) an open source -tool for managing conda environments within enterprise environments. For now -the username is anything with a password of `password`, but soon this will be -integrated with central authentication via keycloak. The [create environment -endpoint](https://conda-store.readthedocs.io/en/latest/user_guide.html#create-create-environment) -will allow you to easily create a new environment. Additionally, you can update -existing environments by [visiting the -environment](https://conda-store.readthedocs.io/en/latest/user_guide.html#environment-namespace-name-environments) -and clicking edit. +When the environments are updated in this file and an automated `qhub deploy` is kicked off, the environments are updated for all users. There is also a way to easily create ad-hoc +environments without modifying the file. Visiting `https:///conda-store/` will take you to [Conda-Store](https://conda-store.readthedocs.io/en/latest/) an open source +tool for managing conda environments within enterprise environments. For now the username is anything with a password of `password`, but soon this will be integrated with central +authentication via keycloak. The [create environment endpoint](https://conda-store.readthedocs.io/en/latest/user_guide.html#create-create-environment) will allow you to easily +create a new environment. Additionally, you can update existing environments by +[visiting the environment](https://conda-store.readthedocs.io/en/latest/user_guide.html#environment-namespace-name-environments) and clicking edit. -In order for your new environment to be properly visible in the list of -available kernels, you will need to include `ipykernel` and `ipywidgets` in -your environment's dependency list. Also, if using Dask, you will need to -include -[extra dependencies](./faq.md/#whats-included-in-the-user-environment-if-a-user-wants-to-use-dask) -to maintain version compatibility between the Dask client and server. +In order for your new environment to be properly visible in the list of available kernels, you will need to include `ipykernel` and `ipywidgets` in your environment's dependency +list. Also, if using Dask, you will need to include [extra dependencies](./faq.md/#whats-included-in-the-user-environment-if-a-user-wants-to-use-dask) to maintain version +compatibility between the Dask client and server. -We are working towards developing an extension within JupyterLab for editing -these environments, but it is not complete at the moment. Follow +We are working towards developing an extension within JupyterLab for editing these environments, but it is not complete at the moment. Follow [gator](https://github.com/mamba-org/gator) for progress on this extension. diff --git a/docs/source/user_guide/experimental.md b/docs/source/user_guide/experimental.md index 7cb48c0d0..1c003a0ff 100644 --- a/docs/source/user_guide/experimental.md +++ b/docs/source/user_guide/experimental.md @@ -1,5 +1,3 @@ # Experimental features > NOTE: The features listed below are experimental, proceed with caution. - - diff --git a/docs/source/user_guide/faq.md b/docs/source/user_guide/faq.md index 61656c17b..a31834ff1 100644 --- a/docs/source/user_guide/faq.md +++ b/docs/source/user_guide/faq.md @@ -1,53 +1,40 @@ # Frequently asked questions -Additional FAQ questions are available in the -[GitHub discussions](https://github.com/Quansight/qhub/discussions/categories/q-a). +Additional FAQ questions are available in the [GitHub discussions](https://github.com/Quansight/qhub/discussions/categories/q-a). ## Environments ### How are QHub conda user environments created? Who creates them? -The environment specifications are available in `qhub_config.yml` in the -deployment repo, which serves to the QHub deployment using -[conda-store](https://conda-store.readthedocs.io/). When the user manages their -environments in this way, they get all of the benefits of environment -versioning that QHub does under the hood, including future features, such as -convenient environment rollback and environment encapsulation in containers. +The environment specifications are available in `qhub_config.yml` in the deployment repo, which serves to the QHub deployment using +[conda-store](https://conda-store.readthedocs.io/). When the user manages their environments in this way, they get all of the benefits of environment versioning that QHub does +under the hood, including future features, such as convenient environment rollback and environment encapsulation in containers. -Anyone with access to the QHub deployment repo can add an environment, and -there are no limits to the number of included environments. +Anyone with access to the QHub deployment repo can add an environment, and there are no limits to the number of included environments. > Be careful of the YAML indentation as it differs from the conda `environment.yml` ### What to do when the user requires `X` package and it's not available in the environment? -The proper solution is to add the package to the `qhub_config.yml` (See #1). If -they don't have access to the deployment repo, the user needs to contact -their QHub maintainer to get the required package. They *can* do a user install -for pip packages if necessary (this is not recommended) but they won't be -available to Dask workers. +The proper solution is to add the package to the `qhub_config.yml` (See #1). If they don't have access to the deployment repo, the user needs to contact their QHub maintainer to +get the required package. They *can* do a user install for pip packages if necessary (this is not recommended) but they won't be available to Dask workers. ### What's included in the user environment if a user wants to use Dask? -The user needs to include the -[QHub Dask metapackage](https://github.com/conda-forge/qhub-dask-feedstock). -Example: `qhub-dask==||QHUB_VERSION||`. This replaces `distributed`, `dask`, -and `dask-gateway` with the correct pinned versions. +The user needs to include the [QHub Dask metapackage](https://github.com/conda-forge/qhub-dask-feedstock). Example: `qhub-dask==||QHUB_VERSION||`. This replaces `distributed`, +`dask`, and `dask-gateway` with the correct pinned versions. ### Why can't a user just create their own local conda environment or edit the existing conda environments? -The version of [conda-store](https://conda-store.readthedocs.io/) used in QHub -versions 0.3.11 and earlier is an alpha version. It doesn't support -using local conda environments or editing pre-exising environments directly. +The version of [conda-store](https://conda-store.readthedocs.io/) used in QHub versions 0.3.11 and earlier is an alpha version. It doesn't support using local conda environments or +editing pre-exising environments directly. -> See the answer to #2 for information on how to modify environments properly. -> In the near future, the support for user-defined environments via conda-store -> is going to be implemented. +> See the answer to #2 for information on how to modify environments properly. In the near future, the support for user-defined environments via conda-store is going to be +> implemented. ### How can a user install a local package? Is it available to the user's Dask workers? -If the user is using a `setuptools` package, they can install it into their -local user environment using: +If the user is using a `setuptools` package, they can install it into their local user environment using: ```shell pip install --no-build-isolation --user -e . @@ -63,10 +50,8 @@ These aren't available to the Dask workers. ### How to use .bashrc on QHub? -Users can use `.bashrc` on QHub, but it's important to note that by default QHub -sources `.bash_profile`. The users might need to be sure to source the -`.bashrc` inside of the `.bash_profile`. It's important to note that if they set -environment variables in this way, they aren't available inside the notebooks. +Users can use `.bashrc` on QHub, but it's important to note that by default QHub sources `.bash_profile`. The users might need to be sure to source the `.bashrc` inside of the +`.bash_profile`. It's important to note that if they set environment variables in this way, they aren't available inside the notebooks. ### How to use environment variables on dask workers which aren't loaded via a package? @@ -101,8 +86,5 @@ conda config --set changeps1 true ### What if a user wants to use the QHub server to compute a new pinned environment, which the user serves via the `qhub_config.yml`? -If the user needs to solve a conda env on a QHub server, they need to specify -the prefix. For example, -`conda env create -f env_test.yml --prefix/tmp/test-env` where `test-env` is -the env name. It's not recommended, but there are valid use cases of this -operation. +If the user needs to solve a conda env on a QHub server, they need to specify the prefix. For example, `conda env create -f env_test.yml --prefix/tmp/test-env` where `test-env` is +the env name. It's not recommended, but there are valid use cases of this operation. diff --git a/docs/source/user_guide/getting_started.md b/docs/source/user_guide/getting_started.md index 29b46ed81..626815aff 100644 --- a/docs/source/user_guide/getting_started.md +++ b/docs/source/user_guide/getting_started.md @@ -1,64 +1,44 @@ # Login to QHub -This guide aims to give a basic overview of the QHub login process. Your -organization's QHub will likely have a slightly different authentication -process due to the many authentication providers that QHub can integrate with. +This guide aims to give a basic overview of the QHub login process. Your organization's QHub will likely have a slightly different authentication process due to the many +authentication providers that QHub can integrate with. -The first step is to connect with your QHub cluster, for this example we will -be using `https://qhub-demo.qhub.dev`. Once on the site, you will be prompted -by a login, similar to the login page shown in the image below. +The first step is to connect with your QHub cluster, for this example we will be using `https://qhub-demo.qhub.dev`. Once on the site, you will be prompted by a login, similar to +the login page shown in the image below. ![QHub login screen](../images/qhub_login_screen.png) -Qhub now uses an open source tool called Keycloak for user management. This -makes it a little challenging to detail the exact process as it might differ -greatly between authentication providers (LDAP, OAuth 2.0, passwordless -authentication, password-based authentication and many others). A deeper -overview of the QHub authentication process is described in the -[Authentication Guide](../installation/login.md). +Qhub now uses an open source tool called Keycloak for user management. This makes it a little challenging to detail the exact process as it might differ greatly between +authentication providers (LDAP, OAuth 2.0, passwordless authentication, password-based authentication and many others). A deeper overview of the QHub authentication process is +described in the [Authentication Guide](../installation/login.md). -For this demonstration we will present the user with password-based or GitHub -authentication. +For this demonstration we will present the user with password-based or GitHub authentication. ![QHub Keycloak auth screen](../images/keycloak_qhub_login.png) -Once authenticated, the user will be forwarded to the main hub page where the -user will have access to `Token` management, JupyterLab server access, and -other features like `Dashboards` and `Admin` management. +Once authenticated, the user will be forwarded to the main hub page where the user will have access to `Token` management, JupyterLab server access, and other features like +`Dashboards` and `Admin` management. ![QHub main hub screen](../images/qhub_main_hub_page.png) -After `Start My Server` is selected, the user will be prompted with a set of -profiles that are available for the authenticated user. Your given -selections will likely differ from the image shown. The customized profiles -will give you access to fixed cloud resources. For example, you could choose -a resource with 2 CPUs, 8 GB RAM, and -1 dedicated GPU, all of which is configured by your administrator. A more -detailed explanation of dedicated profiles can be found in the -[Profiles](../installation/configuration.md#profiles) section of the advanced -configuration page. +After `Start My Server` is selected, the user will be prompted with a set of profiles that are available for the authenticated user. Your given selections will likely differ from +the image shown. The customized profiles will give you access to fixed cloud resources. For example, you could choose a resource with 2 CPUs, 8 GB RAM, and 1 dedicated GPU, all of +which is configured by your administrator. A more detailed explanation of dedicated profiles can be found in the [Profiles](../installation/configuration.md#profiles) section of +the advanced configuration page. ![QHub select profile](../images/qhub_select_profile.png) -Once an appropriate profile has been selected, click `start`. At this point, your -JupyterHub instance will be launched, a step which may take up to several minutes due to -QHub use of autoscaling under the hood. Ultimately this autoscaling feature -helps reduce costs when the cluster is idle. A successful launch should look -similar to the image below. +Once an appropriate profile has been selected, click `start`. At this point, your JupyterHub instance will be launched, a step which may take up to several minutes due to QHub use +of autoscaling under the hood. Ultimately this autoscaling feature helps reduce costs when the cluster is idle. A successful launch should look similar to the image below. ![QHub start server](../images/qhub_server_start.png) -Once your JupyterHub instance has been launched you will notice a -selection of available Python environments. These environments will also -represent the different kernel choices available for your notebooks. They are -created and managed by conda-store and can be easily configured. Learn more -at +Once your JupyterHub instance has been launched you will notice a selection of available Python environments. These environments will also represent the different kernel choices +available for your notebooks. They are created and managed by conda-store and can be easily configured. Learn more at [Managing environments](../installation/configuration.md#environments). ![QHub kernel selection](../images/qhub_kernel_selection.png) -From the Launcher, you can choose a JupyterLab notebook -with a given conda environment. Note that kernels can take several seconds -to become responsive. The circle in the top right-hand corner is a good -indicator of the status of the kernel. A lightning bold means that the kernel -has started, but it is not yet ready to run code. An open circle means it's ready. +From the Launcher, you can choose a JupyterLab notebook with a given conda environment. Note that kernels can take several seconds to become responsive. The circle in the top +right-hand corner is a good indicator of the status of the kernel. A lightning bold means that the kernel has started, but it is not yet ready to run code. An open circle means +it's ready. diff --git a/docs/source/user_guide/idle_culler.md b/docs/source/user_guide/idle_culler.md index 350cb8ddf..e57aaa0f6 100644 --- a/docs/source/user_guide/idle_culler.md +++ b/docs/source/user_guide/idle_culler.md @@ -1,26 +1,30 @@ # Culling idle notebook servers -Qhub uses a mix of the `idle culler `_ extension and internal Jupyterlab server cofiguration to periodically check for idle notebook servers and shut them down. +Qhub uses a mix of the `idle culler `\_ extension and internal Jupyterlab server configuration to periodically check for idle +notebook servers and shut them down. -JupyterHub pings the user's notebook server at certain time intervals. If no response is received from the -server during this checks and the timeout expires, the server is considered to be *inactive (idle)* and will -be culled. +JupyterHub pings the user's notebook server at certain time intervals. If no response is received from the server during this checks and the timeout expires, the server is +considered to be *inactive (idle)* and will be culled. -To help jupyterhub-idle-culler cull user servers, we configure the kernel manager to cull idle kernels that -would otherwise make the user servers report themselves as active which is part of what jupyterhub-idle-culler considers. +To help jupyterhub-idle-culler cull user servers, we configure the kernel manager to cull idle kernels that would otherwise make the user servers report themselves as active which +is part of what jupyterhub-idle-culler considers. -*** -The expected behavior is that the server will be shut down and removed from the Qhub namespace once all Terminals and Kernels are considered idle or terminated, as well as any remaning connection is closed. -*** +______________________________________________________________________ + +The expected behavior is that the server will be shut down and removed from the Qhub namespace once all Terminals and Kernels are considered idle or terminated, as well as any +remaining connection is closed. + +______________________________________________________________________ ## Default settings By default, JupyterHub will ping the user notebook servers every 5 minutes to check their status. Every server found to be idle for more than 30 minutes will be terminated. -Because the servers don't have a maximum age set, an active (has any open connection, terminal or kernel in execution ) server will not be shut down -regardless of how long it has been up and running. +Because the servers don't have a maximum age set, an active (has any open connection, terminal or kernel in execution ) server will not be shut down regardless of how long it has +been up and running. The process for culling and terminating follows these steps: + - Check if the Terminal and Notebooks kernels are idle for more than 15 minutes. With periodicaly culling checks of 5m. - If the kernel is idle for more than 15 minutes, terminate the kernel and the server. - Once no connections remains, after another 15m of no API calls from the user pod, the server is considered idle, and will be terminated. diff --git a/docs/source/user_guide/ssh.md b/docs/source/user_guide/ssh.md index 106a708e0..1cc7ed437 100644 --- a/docs/source/user_guide/ssh.md +++ b/docs/source/user_guide/ssh.md @@ -1,36 +1,25 @@ # SSH/SFTP Access -QHub provides a secure method for users to login while also providing additional -ways to connect to the cluster through -[`jupyterhub-ssh`](https://github.com/yuvipanda/jupyterhub-ssh). -This allows users to access a cluster and a JupyterLab environment via -[`ssh`](https://en.wikipedia.org/wiki/Secure_Shell). In addition, users -can easily transfer files back and forth via -[`sftp`](https://en.wikipedia.org/wiki/SSH_File_Transfer_Protocol). -And for users who prefer terminal based editors, such as emacs or vim, they -can log in and automate tasks on the cluster without browser access. -For more detailed information on using `jupyterhub-ssh`, please refer to the +QHub provides a secure method for users to login while also providing additional ways to connect to the cluster through +[`jupyterhub-ssh`](https://github.com/yuvipanda/jupyterhub-ssh). This allows users to access a cluster and a JupyterLab environment via +[`ssh`](https://en.wikipedia.org/wiki/Secure_Shell). In addition, users can easily transfer files back and forth via +[`sftp`](https://en.wikipedia.org/wiki/SSH_File_Transfer_Protocol). And for users who prefer terminal based editors, such as emacs or vim, they can log in and automate tasks on the +cluster without browser access. For more detailed information on using `jupyterhub-ssh`, please refer to the [documentation](https://jupyterhub-ssh.readthedocs.io/en/latest/index.html). -In order to login via `ssh` a user needs to generate an API token. Visit -`https:///hub/token`. Where `` is the domain name of -your QHub cluster. You will be shown a screen similar to the one below. -You need only generate the API token once; it can be reused going forward. -To revoke the API token, simply return to this page and click `revoke`. +In order to login via `ssh` a user needs to generate an API token. Visit `https:///hub/token`. Where `` is the domain name of your QHub cluster. You will be +shown a screen similar to the one below. You need only generate the API token once; it can be reused going forward. To revoke the API token, simply return to this page and click +`revoke`. ![qhub api token](../images/qhub_api_token.png) -To request a new token, add a short description, such as -`ssh login token`, and click on `Request new API token`. -Copy and save the generated api token (in this case `f0b80688484a4ac79a21b38ec277ca08`). +To request a new token, add a short description, such as `ssh login token`, and click on `Request new API token`. Copy and save the generated api token (in this case +`f0b80688484a4ac79a21b38ec277ca08`). ![qhub api token generated](../images/qhub_api_token_generated.png) -You can now log into the QHub cluster via the terminal using `ssh`. Note -that you will use your QHub username, shown in the top right-hand corner of -the screen. You will need to provide this username explicitly when connecting -via `ssh`. See the example below on using the `-o` option with `ssh`, and notice -the ports used by QHub for `ssh` and `sftp`. +You can now log into the QHub cluster via the terminal using `ssh`. Note that you will use your QHub username, shown in the top right-hand corner of the screen. You will need to +provide this username explicitly when connecting via `ssh`. See the example below on using the `-o` option with `ssh`, and notice the ports used by QHub for `ssh` and `sftp`. > - `ssh` uses port `8022` > - `sftp` uses port `8023` diff --git a/docs/source/user_guide/training.md b/docs/source/user_guide/training.md index e5a447532..8d774aa05 100644 --- a/docs/source/user_guide/training.md +++ b/docs/source/user_guide/training.md @@ -1,6 +1,8 @@ # QHub training cluster -Quansight provides training around the [PyData](https://pydata.org/) ecosystem. For this training material, a Qhub based training cluster is utilized. This guide explains to newcomers how to log into Quansight's own QHub Training server. If you are looking for instructions on logging into your own organization's QHub see the user [getting started docs](getting_started.md). +Quansight provides training around the [PyData](https://pydata.org/) ecosystem. For this training material, a Qhub based training cluster is utilized. This guide explains to +newcomers how to log into Quansight's own QHub Training server. If you are looking for instructions on logging into your own organization's QHub see the user +[getting started docs](getting_started.md). To access the training platform: diff --git a/docs/source/user_guide/troubleshooting.md b/docs/source/user_guide/troubleshooting.md index f6f8f5156..b05122a99 100644 --- a/docs/source/user_guide/troubleshooting.md +++ b/docs/source/user_guide/troubleshooting.md @@ -3,30 +3,44 @@ ## DNS domain=`your_qhub_domain` record does not exist ### Issue -During your initial QHub deployment, at the end of the `04-kubernetes-ingress` stage, you receive an output message stating that the DNS record for `your_qhub_domain` "appears not to exist, has recently been updated, or has yet to fully propagate." + +During your initial QHub deployment, at the end of the `04-kubernetes-ingress` stage, you receive an output message stating that the DNS record for `your_qhub_domain` "appears not +to exist, has recently been updated, or has yet to fully propagate." ### Reason for observed behavior + As the output message mentions, this is likely the result of the non-deterministic behavior of DNS. -Without going into a deep dive of what DNS is or how it works, the issue encountered here is that the when QHub tries to lookup the IP address associated with the DNS record, `your_qhub_domain`, nothing is returned. Unfortunately, this "lookup" is not as straight-forward as it sounds. To lookup the correct IP associated with this domain, many intermediate servers (root, top level domain, and authoritative nameservers) are checked, each with their own cache which was updated an unknown time ago (usually on the order of minutes but not always). +Without going into a deep dive of what DNS is or how it works, the issue encountered here is that the when QHub tries to lookup the IP address associated with the DNS record, +`your_qhub_domain`, nothing is returned. Unfortunately, this "lookup" is not as straight-forward as it sounds. To lookup the correct IP associated with this domain, many +intermediate servers (root, top level domain, and authoritative nameservers) are checked, each with their own cache which was updated an unknown time ago (usually on the order of +minutes but not always). For those interested to learn more about DNS, [see this interesting comic](https://howdns.works/)). ### Troubleshooting -Again, as the output message mentions, it will ask if you want it to retry this DNS lookup again after another wait period; this wait period keeps increasing after each retry. However, it's still possible that after waiting 15 or more minutes that the DNS still won't resolve. -At this point, feel free to cancel the deployment and rerun the same deployment command again in an hour or two. Although not guaranteed, it's extremely likely that the DNS will resolve correctly after this prolonged wait period. +Again, as the output message mentions, it will ask if you want it to retry this DNS lookup again after another wait period; this wait period keeps increasing after each retry. +However, it's still possible that after waiting 15 or more minutes that the DNS still won't resolve. +At this point, feel free to cancel the deployment and rerun the same deployment command again in an hour or two. Although not guaranteed, it's extremely likely that the DNS will +resolve correctly after this prolonged wait period. ## A Conda-Store environment fails to build ### Issue -One of the two (`dashboard` or `dask`) [Conda-Store](https://github.com/Quansight/conda-store) environments created during the initial QHub deployment fails to appear as options when logged into JupyterHub. + +One of the two (`dashboard` or `dask`) [Conda-Store](https://github.com/Quansight/conda-store) environments created during the initial QHub deployment fails to appear as options +when logged into JupyterHub. If your user has access to Conda-Store, you can verify this by visiting `.com/conda-store` and having a look at the build status of the missing environment. ### Reason for observed behavior -The reason for this issue is due to how these environments are simultaneously built. Under the hood, Conda-Store relies on Mamba/Conda to resolve and download the specific packages listed in the environment YAML. If they both environment builds try to download the same package with different versions, the build that started first will have their package overwritten by the second build. This causes the first build to fail. + +The reason for this issue is due to how these environments are simultaneously built. Under the hood, Conda-Store relies on Mamba/Conda to resolve and download the specific packages +listed in the environment YAML. If they both environment builds try to download the same package with different versions, the build that started first will have their package +overwritten by the second build. This causes the first build to fail. ### Troubleshooting + To resolve this issue, navigate to `.com/conda-store`, find the environment build that failed and trigger it to re-build. diff --git a/environment-dev.yaml b/environment-dev.yaml index f31bdbf9b..55f12a597 100644 --- a/environment-dev.yaml +++ b/environment-dev.yaml @@ -11,7 +11,7 @@ dependencies: - python-kubernetes # dev dependencies - flake8 ==3.8.4 - - black ==20.8b1 + - black ==22.3.0 - twine - pytest - diagrams diff --git a/qhub/initialize.py b/qhub/initialize.py index 8db10d0fd..a376601dc 100644 --- a/qhub/initialize.py +++ b/qhub/initialize.py @@ -15,6 +15,7 @@ from qhub.utils import ( namestr_regex, qhub_image_tag, + qhub_dask_version, check_cloud_credentials, set_kubernetes_version, ) @@ -57,6 +58,9 @@ "monitoring": { "enabled": True, }, + "argo_workflows": { + "enabled": True, + }, "cdsdashboards": { "enabled": True, "cds_hide_user_named_servers": True, @@ -211,7 +215,7 @@ "python", "ipykernel", "ipywidgets", - "qhub-dask ==0.3.13", + f"qhub-dask =={qhub_dask_version}", "python-graphviz", "numpy", "numba", @@ -225,15 +229,15 @@ "python==3.9.7", "ipykernel==6.4.1", "ipywidgets==7.6.5", - "qhub-dask==0.3.13", + f"qhub-dask=={qhub_dask_version}", "param==1.11.1", "python-graphviz==0.17", "matplotlib==3.4.3", "panel==0.12.4", - "voila==0.2.16", + "voila==0.3.5", "streamlit==1.0.0", "dash==2.0.0", - "cdsdashboards-singleuser==0.6.0", + "cdsdashboards-singleuser==0.6.1", ], }, } diff --git a/qhub/provider/cicd/__init__.py b/qhub/provider/cicd/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/qhub/provider/terraform.py b/qhub/provider/terraform.py index 456f539c0..04a2e1f36 100644 --- a/qhub/provider/terraform.py +++ b/qhub/provider/terraform.py @@ -132,10 +132,13 @@ def version(): return re.search(r"(\d+)\.(\d+).(\d+)", version_output).group(0) -def init(directory=None): +def init(directory=None, upgrade=True): logger.info(f"terraform init directory={directory}") with timer(logger, "terraform init"): - run_terraform_subprocess(["init"], cwd=directory, prefix="terraform") + command = ["init"] + if upgrade: + command.append("-upgrade") + run_terraform_subprocess(command, cwd=directory, prefix="terraform") def apply(directory=None, targets=None, var_files=None): diff --git a/qhub/render.py b/qhub/render.py index 840300300..4c9b0054e 100644 --- a/qhub/render.py +++ b/qhub/render.py @@ -163,9 +163,32 @@ def render_contents(config: Dict): } ) + contents.update(gen_gitignore(config)) + return contents +def gen_gitignore(config): + """ + Generate `.gitignore` file. + Add files as needed. + """ + + from inspect import cleandoc + + filestoignore = """ + # ignore terraform state + .terraform + terraform.tfstate + terraform.tfstate.backup + .terraform.tfstate.lock.info + + # python + __pycache__ + """ + return {".gitignore": cleandoc(filestoignore)} + + def gen_cicd(config): """ Use cicd schema to generate workflow files based on the diff --git a/qhub/schema.py b/qhub/schema.py index 352a23d97..6c021c009 100644 --- a/qhub/schema.py +++ b/qhub/schema.py @@ -41,6 +41,12 @@ class AuthenticationEnum(str, enum.Enum): custom = "custom" +class AccessEnum(str, enum.Enum): + all = "all" + yaml = "yaml" + keycloak = "keycloak" + + class Base(pydantic.BaseModel): ... @@ -297,6 +303,7 @@ class Config: class JupyterLabProfile(Base): + access: AccessEnum = AccessEnum.all display_name: str description: str default: typing.Optional[bool] @@ -304,6 +311,18 @@ class JupyterLabProfile(Base): groups: typing.Optional[typing.List[str]] kubespawner_override: typing.Optional[KubeSpawner] + @root_validator + def only_yaml_can_have_groups_and_users(cls, values): + if values["access"] != AccessEnum.yaml: + if ( + values.get("users", None) is not None + or values.get("groups", None) is not None + ): + raise ValueError( + "Profile must not contain groups or users fields unless access = yaml" + ) + return values + class DaskWorkerProfile(Base): worker_cores_limit: int @@ -320,7 +339,7 @@ class Profiles(Base): jupyterlab: typing.List[JupyterLabProfile] dask_worker: typing.Dict[str, DaskWorkerProfile] - @validator("jupyterlab", pre=True) + @validator("jupyterlab") def check_default(cls, v, values): """Check if only one default value is present""" default = [attrs["default"] for attrs in v if "default" in attrs] @@ -370,6 +389,10 @@ class QHubExtension(Base): envs: typing.Optional[typing.List[QHubExtensionEnv]] +class Ingress(Base): + terraform_overrides: typing.Any + + # ======== External Container Registry ======== # This allows the user to set a private AWS ECR as a replacement for @@ -444,6 +467,7 @@ class Main(Base): prevent_deploy: bool = ( False # Optional, but will be given default value if not present ) + ingress: typing.Optional[Ingress] # If the qhub_version in the schema is old # we must tell the user to first run qhub upgrade diff --git a/qhub/stages/__init__.py b/qhub/stages/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/qhub/stages/input_vars.py b/qhub/stages/input_vars.py index 0a5556f74..01ca74e45 100644 --- a/qhub/stages/input_vars.py +++ b/qhub/stages/input_vars.py @@ -152,6 +152,7 @@ def stage_04_kubernetes_ingress(stage_outputs, config): "certificate-secret-name": config["certificate"]["secret_name"] if config["certificate"]["type"] == "existing" else None, + **config.get("ingress", {}).get("terraform_overrides", {}), } diff --git a/qhub/template/image/README.md b/qhub/template/image/README.md index 6eec783c5..81bf6ca8d 100644 --- a/qhub/template/image/README.md +++ b/qhub/template/image/README.md @@ -1,8 +1,9 @@ # Pinning It is extremely important to pin specific packages: - - dask - - dask-gateway + +- dask +- dask-gateway # Building Dockerfile diff --git a/qhub/template/image/jupyterhub/environment.yaml b/qhub/template/image/jupyterhub/environment.yaml index 25f7ad470..be8d3f409 100644 --- a/qhub/template/image/jupyterhub/environment.yaml +++ b/qhub/template/image/jupyterhub/environment.yaml @@ -7,7 +7,7 @@ dependencies: - jupyterhub-kubespawner==1.1.0 - oauthenticator==14.1.0 - escapism==1.0.1 - - cdsdashboards==0.6.0 + - cdsdashboards==0.6.1 - jupyterhub-idle-culler==1.0 - pip: - qhub-jupyterhub-theme==0.3.3 diff --git a/qhub/template/image/jupyterlab/environment.yaml b/qhub/template/image/jupyterlab/environment.yaml index 9ee039679..77a43b85d 100644 --- a/qhub/template/image/jupyterlab/environment.yaml +++ b/qhub/template/image/jupyterlab/environment.yaml @@ -29,7 +29,7 @@ dependencies: - nbgitpuller # cds dashboards - - cdsdashboards-singleuser >=0.6.0 + - cdsdashboards-singleuser >=0.6.1 - jhsingle-native-proxy >=0.7.6 # viz tools diff --git a/qhub/template/stages/04-kubernetes-ingress/main.tf b/qhub/template/stages/04-kubernetes-ingress/main.tf index 44c8387c5..ec2348f9e 100644 --- a/qhub/template/stages/04-kubernetes-ingress/main.tf +++ b/qhub/template/stages/04-kubernetes-ingress/main.tf @@ -5,8 +5,10 @@ module "kubernetes-ingress" { node-group = var.node_groups.general - enable-certificates = var.enable-certificates - acme-email = var.acme-email - acme-server = var.acme-server - certificate-secret-name = var.certificate-secret-name + enable-certificates = var.enable-certificates + acme-email = var.acme-email + acme-server = var.acme-server + certificate-secret-name = var.certificate-secret-name + load-balancer-annotations = var.load-balancer-annotations + load-balancer-ip = var.load-balancer-ip } diff --git a/qhub/template/stages/04-kubernetes-ingress/modules/kubernetes/ingress/main.tf b/qhub/template/stages/04-kubernetes-ingress/modules/kubernetes/ingress/main.tf index 99a2ff71e..32a284899 100644 --- a/qhub/template/stages/04-kubernetes-ingress/modules/kubernetes/ingress/main.tf +++ b/qhub/template/stages/04-kubernetes-ingress/modules/kubernetes/ingress/main.tf @@ -64,9 +64,9 @@ resource "kubernetes_service" "main" { } spec { - selector = { + selector = merge({ "app.kubernetes.io/component" = "traefik-ingress" - } + }, var.load-balancer-annotations) port { name = "http" @@ -111,6 +111,7 @@ resource "kubernetes_service" "main" { } type = "LoadBalancer" + load_balancer_ip = var.load-balancer-ip } } diff --git a/qhub/template/stages/04-kubernetes-ingress/modules/kubernetes/ingress/variables.tf b/qhub/template/stages/04-kubernetes-ingress/modules/kubernetes/ingress/variables.tf index 6d5eac16e..d30bb9334 100644 --- a/qhub/template/stages/04-kubernetes-ingress/modules/kubernetes/ingress/variables.tf +++ b/qhub/template/stages/04-kubernetes-ingress/modules/kubernetes/ingress/variables.tf @@ -58,3 +58,18 @@ variable "certificate-secret-name" { type = string default = null } + +variable "load-balancer-ip" { + description = "IP Address of the load balancer" + type = string + default = null +} + +variable "load-balancer-annotations" { + description = "Annotations for the load balancer" + type = map(object({ + key = string + value = string + })) + default = null +} diff --git a/qhub/template/stages/04-kubernetes-ingress/variables.tf b/qhub/template/stages/04-kubernetes-ingress/variables.tf index c3dc006ba..85929c4fb 100644 --- a/qhub/template/stages/04-kubernetes-ingress/variables.tf +++ b/qhub/template/stages/04-kubernetes-ingress/variables.tf @@ -38,3 +38,20 @@ variable "certificate-secret-name" { description = "Kubernetes secret used for certificate" default = "" } + + +variable "load-balancer-ip" { + description = "IP Address of the load balancer" + type = string + default = null +} + + +variable "load-balancer-annotations" { + description = "Annotations for the load balancer" + type = map(object({ + key = string + value = string + })) + default = null +} diff --git a/qhub/template/stages/06-kubernetes-keycloak-configuration/main.tf b/qhub/template/stages/06-kubernetes-keycloak-configuration/main.tf index dfb99011d..dfa8a99a9 100644 --- a/qhub/template/stages/06-kubernetes-keycloak-configuration/main.tf +++ b/qhub/template/stages/06-kubernetes-keycloak-configuration/main.tf @@ -31,6 +31,12 @@ resource "keycloak_group" "groups" { realm_id = keycloak_realm.main.id name = each.key attributes = {} + + lifecycle { + ignore_changes = [ + attributes, + ] + } } resource "keycloak_default_groups" "default" { diff --git a/qhub/template/stages/07-kubernetes-services/argo-workflows.tf b/qhub/template/stages/07-kubernetes-services/argo-workflows.tf index 2a8c8ec39..3ffda2e81 100644 --- a/qhub/template/stages/07-kubernetes-services/argo-workflows.tf +++ b/qhub/template/stages/07-kubernetes-services/argo-workflows.tf @@ -12,7 +12,7 @@ module "argo-workflows" { source = "./modules/kubernetes/services/argo-workflows" namespace = var.environment external-url = var.endpoint - # realm_id = var.realm_id + realm_id = var.realm_id # node-group = var.node_groups.general } diff --git a/qhub/template/stages/07-kubernetes-services/conda-store.tf b/qhub/template/stages/07-kubernetes-services/conda-store.tf index 90125d9ed..c8f47a246 100644 --- a/qhub/template/stages/07-kubernetes-services/conda-store.tf +++ b/qhub/template/stages/07-kubernetes-services/conda-store.tf @@ -23,7 +23,7 @@ variable "conda-store-image" { }) default = { name = "quansight/conda-store-server" - tag = "v0.3.13" + tag = "v0.3.15" } } diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/argo-workflows/main.tf b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/argo-workflows/main.tf index 5dba602cc..3fa731070 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/argo-workflows/main.tf +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/argo-workflows/main.tf @@ -28,10 +28,30 @@ resource "helm_release" "argo-workflows" { } server = { - enabled = true - - extraArgs = ["--auth-mode=server"] + # `sso` for OIDC/OAuth + extraArgs = ["--auth-mode=sso", "--insecure-skip-verify"] + # to enable TLS, `secure = true` + secure = false baseHref = "/${local.argo-workflows-prefix}/" + + sso = { + issuer = "https://${var.external-url}/auth/realms/${var.realm_id}" + clientId = { + name = "argo-server-sso" + key = "argo-oidc-client-id" + } + clientSecret = { + name = "argo-server-sso" + key = "argo-oidc-client-secret" + } + # The OIDC redirect URL. Should be in the form /oauth2/callback. + redirectUrl = "https://${var.external-url}/oauth2/callback" + rbac = { + enabled = false + # secretWhitelist = [] + } + # scopes = ["groups"] + } } containerRuntimeExecutor = "emissary" @@ -40,6 +60,33 @@ resource "helm_release" "argo-workflows" { ], var.overrides) } +resource "kubernetes_secret" "argo-oidc-secret" { + metadata { + name = "argo-server-sso" + namespace = var.namespace + } + data = { + "argo-oidc-client-id" = module.argo-workflow-openid-client.config.client_id + "argo-oidc-client-secret" = module.argo-workflow-openid-client.config.client_secret + } +} + +module "argo-workflow-openid-client" { + source = "../keycloak-client" + + realm_id = var.realm_id + client_id = "argo-server-sso" + external-url = var.external-url + # role_mapping = { + # "admin" = ["argo_admin"] + # "developer" = ["argo_developer"] + # "analyst" = ["argo_viewer"] + # } + + callback-url-paths = [ + "https://${var.external-url}/oauth2/callback" + ] +} resource "kubernetes_manifest" "argo-workflows-middleware-stripprefix" { manifest = { @@ -60,7 +107,6 @@ resource "kubernetes_manifest" "argo-workflows-middleware-stripprefix" { } } - resource "kubernetes_manifest" "argo-workflows-ingress-route" { manifest = { apiVersion = "traefik.containo.us/v1alpha1" diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/argo-workflows/variables.tf b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/argo-workflows/variables.tf index 79b594e94..3638f965e 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/argo-workflows/variables.tf +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/argo-workflows/variables.tf @@ -29,3 +29,8 @@ variable "overrides" { type = list(string) default = [] } + +variable "realm_id" { + description = "Keycloak realm to use for deploying openid client" + type = string +} diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/clearml/chart/README.md b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/clearml/chart/README.md index c2424e05f..76dd36241 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/clearml/chart/README.md +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/clearml/chart/README.md @@ -1,6 +1,8 @@ # ClearML Server for Kubernetes Clusters Using Helm + # Cloud Ready Version (Advanced) -## Auto-Magical Experiment Manager & Version Control for AI + +## Auto-Magical Experiment Manager & Version Control for AI [![GitHub license](https://img.shields.io/badge/license-SSPL-green.svg)](https://img.shields.io/badge/license-SSPL-green.svg) [![GitHub version](https://img.shields.io/github/release-pre/allegroai/clearml-server.svg)](https://img.shields.io/github/release-pre/allegroai/clearml-server.svg) @@ -8,96 +10,106 @@ ## Introduction -The **clearml-server** is the backend service infrastructure for [ClearML](https://github.com/allegroai/clearml). -It allows multiple users to collaborate and manage their experiments. -By default, *ClearML is set up to work with the ClearML Demo Server, which is open to anyone and resets periodically. -In order to host your own server, you will need to install **clearml-server** and point ClearML to it. +The **clearml-server** is the backend service infrastructure for [ClearML](https://github.com/allegroai/clearml). It allows multiple users to collaborate and manage their +experiments. By default, \*ClearML is set up to work with the ClearML Demo Server, which is open to anyone and resets periodically. In order to host your own server, you will need +to install **clearml-server** and point ClearML to it. **clearml-server** contains the following components: -* The ClearML Web-App, a single-page UI for experiment management and browsing -* RESTful API for: - * Documenting and logging experiment information, statistics and results - * Querying experiments history, logs and results -* Locally-hosted file server for storing images and models making them easily accessible using the Web-App +- The ClearML Web-App, a single-page UI for experiment management and browsing +- RESTful API for: + - Documenting and logging experiment information, statistics and results + - Querying experiments history, logs and results +- Locally-hosted file server for storing images and models making them easily accessible using the Web-App Use this repository to add **clearml-server** to your Helm and then deploy **clearml-server** on Kubernetes clusters using Helm. ## Deploying Your Own Elasticsearch, Redis and Mongodb -ClearML Server requires that you have elasticsearch, redis and mongodb services. -This chart default templates contains [bitnami](https://bitnami.com/) charts for [redis](https://github.com/bitnami/charts/tree/master/bitnami/redis) and [mongodb](https://github.com/bitnami/charts/tree/master/bitnami/mongodb), and the official chart for elasticsearch (which is currently still beta). -You can either use the default ones, or use your own deployments and set their name and ports in the appropriate sections of this chart. -In order to use your own deployment, make sure to disable the existing one in the `values.yaml` (for example, in order to disable elastic set `elasticsearch.enabled = false`) +ClearML Server requires that you have elasticsearch, redis and mongodb services. This chart default templates contains [bitnami](https://bitnami.com/) charts for +[redis](https://github.com/bitnami/charts/tree/master/bitnami/redis) and [mongodb](https://github.com/bitnami/charts/tree/master/bitnami/mongodb), and the official chart for +elasticsearch (which is currently still beta). You can either use the default ones, or use your own deployments and set their name and ports in the appropriate sections of this +chart. In order to use your own deployment, make sure to disable the existing one in the `values.yaml` (for example, in order to disable elastic set +`elasticsearch.enabled = false`) ## Prerequisites 1. a Kubernetes cluster -1. Persistent Volumes for `pvc-apiserver.yaml`, `pvc-fileserver.yaml`, and `pvc-agentservices.yaml`. -1. Persistent volumes for elasticsearch, mongodb and redis (redis is optional). - See relevant information for each chart: - * [elasticsearch](https://github.com/elastic/helm-charts/blob/7.6.2/elasticsearch/values.yaml) - * [mongodb](https://github.com/bitnami/charts/tree/master/bitnami/mongodb#parameters) - * [redis](https://github.com/bitnami/charts/tree/master/bitnami/redis#parameters) - Make sure to define the following values for each PV: - * elasticsearch - in the `values.yaml` set `elasticsearch.persistence.enabled=true` and set `elasticsearch.volumeClaimTemplate.storageClassName` to the storageClassName used in your elasticsearch PV. - * mongodb - in order to define a persistent volume for mongodb, in the `values.yaml` set `mongodb.persistence.enabled=true` and set `mongodb.persistence.storageClass` to the storageClassName used in your mongodb PV. - Read [here](https://github.com/bitnami/charts/tree/master/bitnami/mongodb#parameters) for more details. - * redis - in order to define a persistent volume for redis, in the `values.yaml` set `redis.master.persistence.enabled=true` and set `redis.master.persistence.storageClass` to the storageClassName used in your redis PV. - Read [here](https://github.com/bitnami/charts/tree/master/bitnami/redis#parameters) for more details. -1. `kubectl` is installed and configured (see [Install and Set Up kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) in the Kubernetes documentation) -1. `helm` installed (see [Installing Helm](https://helm.sh/docs/using_helm/#installing-helm) in the Helm documentation) +2. Persistent Volumes for `pvc-apiserver.yaml`, `pvc-fileserver.yaml`, and `pvc-agentservices.yaml`. +3. Persistent volumes for elasticsearch, mongodb and redis (redis is optional). See relevant information for each chart: + - [elasticsearch](https://github.com/elastic/helm-charts/blob/7.6.2/elasticsearch/values.yaml) + - [mongodb](https://github.com/bitnami/charts/tree/master/bitnami/mongodb#parameters) + - [redis](https://github.com/bitnami/charts/tree/master/bitnami/redis#parameters) Make sure to define the following values for each PV: + - elasticsearch - in the `values.yaml` set `elasticsearch.persistence.enabled=true` and set `elasticsearch.volumeClaimTemplate.storageClassName` to the storageClassName used in + your elasticsearch PV. + - mongodb - in order to define a persistent volume for mongodb, in the `values.yaml` set `mongodb.persistence.enabled=true` and set `mongodb.persistence.storageClass` to the + storageClassName used in your mongodb PV. Read [here](https://github.com/bitnami/charts/tree/master/bitnami/mongodb#parameters) for more details. + - redis - in order to define a persistent volume for redis, in the `values.yaml` set `redis.master.persistence.enabled=true` and set `redis.master.persistence.storageClass` to + the storageClassName used in your redis PV. Read [here](https://github.com/bitnami/charts/tree/master/bitnami/redis#parameters) for more details. +4. `kubectl` is installed and configured (see [Install and Set Up kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) in the Kubernetes documentation) +5. `helm` installed (see [Installing Helm](https://helm.sh/docs/using_helm/#installing-helm) in the Helm documentation) ## Deploying ClearML Server in Kubernetes Clusters Using Helm 1. Add the **clearml-server** repository to your Helm: - helm repo add allegroai https://allegroai.github.io/clearml-server-helm-cloud-ready/ + ``` + helm repo add allegroai https://allegroai.github.io/clearml-server-helm-cloud-ready/ + ``` -1. Confirm the **clearml-server** repository is now in Helm: +2. Confirm the **clearml-server** repository is now in Helm: - helm search repo clearml + ``` + helm search repo clearml + ``` - The helm search results must include `allegroai/clearml-server-cloud-ready`. + The helm search results must include `allegroai/clearml-server-cloud-ready`. -1. Install `clearml-server-cloud-ready` on your cluster: +3. Install `clearml-server-cloud-ready` on your cluster: - helm install clearml-server allegroai/clearml-server-cloud-ready --namespace=clearml --create-namespace - - A clearml `namespace` is created in your cluster and **clearml-server** is deployed in it. + ``` + helm install clearml-server allegroai/clearml-server-cloud-ready --namespace=clearml --create-namespace + ``` + A clearml `namespace` is created in your cluster and **clearml-server** is deployed in it. ## Updating ClearML Server application using Helm 1. If you are upgrading from the [single node version](https://github.com/allegroai/clearml-server-helm) of ClearML Server helm charts, follow these steps first: - 1. Log in to the node previously labeled as `app=trains` - 1. Copy each folder under /opt/clearml/data to it's persistent volume. - 1. Follow the [Deploying ClearML Server](##-Deploying-ClearML-Server-in-Kubernetes-Clusters-Using-Helm) instructions to deploy Clearml + 1. Log in to the node previously labeled as `app=trains` + 2. Copy each folder under /opt/clearml/data to it's persistent volume. + 3. Follow the [Deploying ClearML Server](##-Deploying-ClearML-Server-in-Kubernetes-Clusters-Using-Helm) instructions to deploy Clearml -1. Update using new or updated `values.yaml` +2. Update using new or updated `values.yaml` - helm upgrade clearml-server allegroai/clearml-server-cloud-ready -f new-values.yaml + ``` + helm upgrade clearml-server allegroai/clearml-server-cloud-ready -f new-values.yaml + ``` -1. If there are no breaking changes, you can update your deployment to match repository version: +3. If there are no breaking changes, you can update your deployment to match repository version: - helm upgrade clearml-server allegroai/clearml-server-cloud-ready + ``` + helm upgrade clearml-server allegroai/clearml-server-cloud-ready + ``` **Important**: - * If you previously deployed a **clearml-server**, you may encounter errors. If so, you must first delete old deployment using the following command: + - If you previously deployed a **clearml-server**, you may encounter errors. If so, you must first delete old deployment using the following command: - helm delete --purge clearml-server + ``` + helm delete --purge clearml-server + ``` - After running the `helm delete` command, you can run the `helm install` command. + After running the `helm delete` command, you can run the `helm install` command. ## Port Mapping After **clearml-server** is deployed, the services expose the following node ports: -* API server on `30008` -* Web server on `30080` -* File server on `30081` +- API server on `30008` +- Web server on `30080` +- File server on `30081` ## Accessing ClearML Server @@ -107,23 +119,28 @@ Once you have a load balancer and domain name set up, follow these steps to conf 1. Create domain records - * Create 3 records to be used for Web-App, File server and API access using the following rules: - * `app.` - * `files.` - * `api.` + - Create 3 records to be used for Web-App, File server and API access using the following rules: + + - `app.` + - `files.` + - `api.` (*for example, `app.clearml.mydomainname.com`, `files.clearml.mydomainname.com` and `api.clearml.mydomainname.com`*) + 2. Point the records you created to the load balancer + 3. Configure the load balancer to redirect traffic coming from the records you created: - * `app.` should be redirected to k8s cluster nodes on port `30080` - * `files.` should be redirected to k8s cluster nodes on port `30081` - * `api.` should be redirected to k8s cluster nodes on port `30008` + + - `app.` should be redirected to k8s cluster nodes on port `30080` + - `files.` should be redirected to k8s cluster nodes on port `30081` + - `api.` should be redirected to k8s cluster nodes on port `30008` ## Additional Configuration for ClearML Server You can also configure the **clearml-server** for: -* fixed users (users with credentials) -* non-responsive experiment watchdog settings +- fixed users (users with credentials) +- non-responsive experiment watchdog settings -For detailed instructions, see the [Optional Configuration](https://github.com/allegroai/clearml-server#optional-configuration) section in the **clearml-server** repository README file. +For detailed instructions, see the [Optional Configuration](https://github.com/allegroai/clearml-server#optional-configuration) section in the **clearml-server** repository README +file. diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/conda-store/config/conda_store_config.py b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/conda-store/config/conda_store_config.py index e47cee6e4..d49943f1d 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/conda-store/config/conda_store_config.py +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/conda-store/config/conda_store_config.py @@ -13,9 +13,7 @@ c.CondaStore.default_uid = 1000 c.CondaStore.default_gid = 100 c.CondaStore.default_permissions = "775" -c.CondaStore.conda_included_packages = [ - "ipykernel" -] +c.CondaStore.conda_included_packages = ["ipykernel"] c.S3Storage.internal_endpoint = "${minio-service}:9000" c.S3Storage.internal_secure = False diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/examples/dashboard_plotly.py b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/examples/dashboard_plotly.py index 49461a164..cd379cab6 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/examples/dashboard_plotly.py +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/examples/dashboard_plotly.py @@ -13,26 +13,27 @@ # assume you have a "long-form" data frame # see https://plotly.com/python/px-arguments/ for more options -df = pd.DataFrame({ - "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"], - "Amount": [4, 1, 2, 2, 4, 5], - "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"] -}) +df = pd.DataFrame( + { + "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"], + "Amount": [4, 1, 2, 2, 4, 5], + "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"], + } +) fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group") -app.layout = html.Div(children=[ - html.H1(children='Hello Dash'), - - html.Div(children=''' +app.layout = html.Div( + children=[ + html.H1(children="Hello Dash"), + html.Div( + children=""" Dash: A web application framework for your data. - '''), - - dcc.Graph( - id='example-graph', - figure=fig - ) -]) + """ + ), + dcc.Graph(id="example-graph", figure=fig), + ] +) -if __name__ == '__main__': +if __name__ == "__main__": app.run_server(debug=True) diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/examples/dashboard_streamlit.py b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/examples/dashboard_streamlit.py index cb07d8d56..b78affa76 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/examples/dashboard_streamlit.py +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/examples/dashboard_streamlit.py @@ -2,10 +2,9 @@ import numpy as np import pandas as pd -st.title('My first StreamLit QHub app') +st.title("My first StreamLit QHub app") st.write("Here's our first attempt at using data to create a table:") -st.write(pd.DataFrame({ - 'first column': [1, 2, 3, 4], - 'second column': [10, 20, 30, 40] -})) +st.write( + pd.DataFrame({"first column": [1, 2, 3, 4], "second column": [10, 20, 30, 40]}) +) diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/jupyterhub/02-spawner.py b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/jupyterhub/02-spawner.py index 5ab464c99..28d19ec56 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/jupyterhub/02-spawner.py +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/jupyterhub/02-spawner.py @@ -32,7 +32,7 @@ c.CDSDashboardsConfig.spawn_default_options = False c.CDSDashboardsConfig.conda_envs = [ - environment['name'] for _, environment in conda_store_environments.items() + environment["name"] for _, environment in conda_store_environments.items() ] else: c.JupyterHub.allow_named_servers = False diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/jupyterhub/03-profiles.py b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/jupyterhub/03-profiles.py index 344e11416..42c342872 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/jupyterhub/03-profiles.py +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/files/jupyterhub/03-profiles.py @@ -31,8 +31,8 @@ def base_profile_home_mounts(username): "name": "skel", "configMap": { "name": skel_mount["name"], - } - } + }, + }, ] } @@ -46,7 +46,9 @@ def base_profile_home_mounts(username): ] } - MKDIR_OWN_DIRECTORY = "mkdir -p /mnt/{path} && chmod 777 /mnt/{path} && cp -r /etc/skel/. /mnt/{path}" + MKDIR_OWN_DIRECTORY = ( + "mkdir -p /mnt/{path} && chmod 777 /mnt/{path} && cp -r /etc/skel/. /mnt/{path}" + ) command = MKDIR_OWN_DIRECTORY.format( path=pvc_home_mount_path.format(username=username) ) @@ -299,7 +301,7 @@ def configure_user(username, groups, uid=1000, gid=100): } -def render_profile(profile, username, groups): +def render_profile(profile, username, groups, keycloak_profilenames): """Render each profile for user If profile is not available for given username, groups returns @@ -315,11 +317,21 @@ def render_profile(profile, username, groups): } } """ - # check that username or groups in allowed groups for profile - user_not_in_users = username not in set(profile.get('users', [])) - user_not_in_groups = (set(groups) & set(profile.get('groups', []))) == set() - if ('users' in profile or 'groups' in profile) and user_not_in_users and user_not_in_groups: - return None + access = profile.get("access", "all") + + if access == "yaml": + # check that username or groups in allowed groups for profile + # profile.groups and profile.users can be None or empty lists, or may not be members of profile at all + user_not_in_users = username not in set(profile.get("users", []) or []) + user_not_in_groups = ( + set(groups) & set(profile.get("groups", []) or []) + ) == set() + if user_not_in_users and user_not_in_groups: + return None + elif access == "keycloak": + # Keycloak mapper should provide the 'jupyterlab_profiles' attribute from groups/user + if profile.get("display_name", None) not in keycloak_profilenames: + return None profile = copy.copy(profile) profile_kubespawner_override = profile.get("kubespawner_override") @@ -335,6 +347,19 @@ def render_profile(profile, username, groups): ], {}, ) + + # We need to merge any env vars from the spawner with any overrides from the profile + # This is mainly to ensure JUPYTERHUB_ANYONE/GROUP is passed through from the spawner + # to control dashboard access. + envvars_fixed = {**(profile["kubespawner_override"].get("environment", {}))} + + def preserve_envvars(spawner): + # This adds in JUPYTERHUB_ANYONE/GROUP rather than overwrite all env vars, + # if set in the spawner for a dashboard to control access. + return {**envvars_fixed, **spawner.environment} + + profile["kubespawner_override"]["environment"] = preserve_envvars + return profile @@ -354,10 +379,18 @@ def render_profiles(spawner): groups = [os.path.basename(_) for _ in auth_state["oauth_user"]["groups"]] spawner.log.error(f"user info: {username} {groups}") + keycloak_profilenames = auth_state["oauth_user"].get("jupyterlab_profiles", []) + # fetch available profiles and render additional attributes profile_list = z2jh.get_config("custom.profiles") return list( - filter(None, [render_profile(p, username, groups) for p in profile_list]) + filter( + None, + [ + render_profile(p, username, groups, keycloak_profilenames) + for p in profile_list + ], + ) ) diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/main.tf b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/main.tf index 074e6908b..ac922a050 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/main.tf +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/main.tf @@ -197,4 +197,5 @@ module "jupyterhub-openid-client" { "https://${var.external-url}/hub/oauth_callback", var.jupyterhub-logout-redirect-url ] + jupyterlab_profiles_mapper = true } diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/variables.tf b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/variables.tf index f88f67c07..8f6d27998 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/variables.tf +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/jupyterhub/variables.tf @@ -113,7 +113,7 @@ variable "cdsdashboards" { variable "conda-store-environments" { description = "conda environments from conda-store in filesystem namespace" - type = map(any) + type = any default = {} } diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/keycloak-client/main.tf b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/keycloak-client/main.tf index 00a39628a..6d8804088 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/keycloak-client/main.tf +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/keycloak-client/main.tf @@ -45,6 +45,22 @@ resource "keycloak_openid_group_membership_protocol_mapper" "main" { add_to_userinfo = true } +resource "keycloak_openid_user_attribute_protocol_mapper" "jupyterlab_profiles" { + count = var.jupyterlab_profiles_mapper ? 1 : 0 + + realm_id = var.realm_id + client_id = keycloak_openid_client.main.id + name = "jupyterlab_profiles_mapper" + claim_name = "jupyterlab_profiles" + + add_to_id_token = true + add_to_access_token = true + add_to_userinfo = true + + user_attribute = "jupyterlab_profiles" + multivalued = true + aggregate_attributes = true +} resource "keycloak_role" "main" { for_each = toset(flatten(values(var.role_mapping))) diff --git a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/keycloak-client/variables.tf b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/keycloak-client/variables.tf index 88fe3853d..d20ecca48 100644 --- a/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/keycloak-client/variables.tf +++ b/qhub/template/stages/07-kubernetes-services/modules/kubernetes/services/keycloak-client/variables.tf @@ -27,3 +27,9 @@ variable "callback-url-paths" { description = "URLs to use for openid callback" type = list(string) } + +variable "jupyterlab_profiles_mapper" { + description = "Create a mapper for jupyterlab_profiles group/user attributes" + type = bool + default = false +} diff --git a/qhub/upgrade.py b/qhub/upgrade.py index 7a6bc777d..836e76610 100644 --- a/qhub/upgrade.py +++ b/qhub/upgrade.py @@ -355,6 +355,32 @@ def _version_specific_upgrade( return config +class Upgrade_0_4_1(UpgradeStep): + version = "0.4.1" + + def _version_specific_upgrade( + self, config, start_version, config_filename: pathlib.Path, *args, **kwargs + ): + """ + Upgrade jupyterlab profiles. + """ + print("\nUpgrading jupyterlab profiles in order to specify access type:\n") + + profiles_jupyterlab = config.get("profiles", {}).get("jupyterlab", []) + for profile in profiles_jupyterlab: + name = profile.get("display_name", "") + + if "groups" in profile or "users" in profile: + profile["access"] = "yaml" + else: + profile["access"] = "all" + + print( + f"Setting access type of JupyterLab profile {name} to {profile['access']}" + ) + return config + + __rounded_version__ = ".".join([str(c) for c in rounded_ver_parse(__version__)]) # Manually-added upgrade steps must go above this line diff --git a/qhub/utils.py b/qhub/utils.py index 43f804969..da14d10e8 100644 --- a/qhub/utils.py +++ b/qhub/utils.py @@ -23,14 +23,17 @@ QHUB_K8S_VERSION = os.getenv("QHUB_K8S_VERSION", None) DO_ENV_DOCS = ( - "https://docs.qhub.dev/en/latest/source/02_get_started/02_setup.html#digital-ocean" + "https://docs.qhub.dev/en/stable/source/installation/setup.html#digital-ocean" +) +AWS_ENV_DOCS = "https://docs.qhub.dev/en/stable/source/installation/setup.html#amazon-web-services-aws" +GCP_ENV_DOCS = "https://docs.qhub.dev/en/stable/source/installation/setup.html#google-cloud-platform" +AZURE_ENV_DOCS = ( + "https://docs.qhub.dev/en/stable/source/installation/setup.html#microsoft-azure" ) -AWS_ENV_DOCS = "https://docs.qhub.dev/en/latest/source/02_get_started/02_setup.html#amazon-web-services-aws" -GCP_ENV_DOCS = "https://docs.qhub.dev/en/latest/source/02_get_started/02_setup.html#google-cloud-platform" -AZURE_ENV_DOCS = "https://docs.qhub.dev/en/latest/source/02_get_started/02_setup.html#microsoft-azure" qhub_image_tag = f"v{__version__}" pip_install_qhub = f"pip install qhub=={__version__}" +qhub_dask_version = "0.4.0" QHUB_GH_BRANCH = os.environ.get("QHUB_GH_BRANCH", "") if QHUB_GH_BRANCH: diff --git a/setup.cfg b/setup.cfg index 3217bf5aa..b98c9ea1f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,6 +22,7 @@ project_urls = [options] zip_safe = False include_package_data = True +packages = qhub install_requires = ruamel.yaml cloudflare @@ -36,13 +37,10 @@ install_requires = python-keycloak importlib_metadata;python_version<"3.8" -# we probably have to ignore some folders -packages=find: - [options.extras_require] dev = flake8==3.8.4 - black==20.8b1 + black==22.3.0 twine pytest pytest-timeout diff --git a/tests/scripts/minikube-loadbalancer-ip.py b/tests/scripts/minikube-loadbalancer-ip.py index e2e1a4ecb..d7a00e351 100755 --- a/tests/scripts/minikube-loadbalancer-ip.py +++ b/tests/scripts/minikube-loadbalancer-ip.py @@ -4,13 +4,13 @@ import sys import subprocess -minikube_cmd = ['minikube', 'ssh', '--', 'ip', '-j', 'a'] +minikube_cmd = ["minikube", "ssh", "--", "ip", "-j", "a"] minikube_output = subprocess.check_output(minikube_cmd, encoding="utf-8")[:-1] address = None for interface in json.loads(minikube_output): - if interface['ifname'] == 'eth0': - address = interface['addr_info'][0]['local'].split('.') + if interface["ifname"] == "eth0": + address = interface["addr_info"][0]["local"].split(".") break else: print("minikube interface eth0 not found") diff --git a/tests/test_links.py b/tests/test_links.py new file mode 100644 index 000000000..b624b588a --- /dev/null +++ b/tests/test_links.py @@ -0,0 +1,21 @@ +import pytest +import requests +from qhub.utils import DO_ENV_DOCS, AWS_ENV_DOCS, GCP_ENV_DOCS, AZURE_ENV_DOCS + +LINKS_TO_TEST = [ + DO_ENV_DOCS, + AWS_ENV_DOCS, + GCP_ENV_DOCS, + AZURE_ENV_DOCS, +] + + +@pytest.mark.parametrize( + "url,status_code", + [ + (url, 200) for url in LINKS_TO_TEST + ] +) +def test_links(url, status_code): + response = requests.get(url) + assert response.status_code == status_code diff --git a/tests/test_render.py b/tests/test_render.py index ed86f5e5d..f34efb005 100644 --- a/tests/test_render.py +++ b/tests/test_render.py @@ -1,9 +1,11 @@ +import os import pytest +from pathlib import Path from ruamel.yaml import YAML from qhub.render import render_template, set_env_vars_in_config -from .conftest import render_config_partial +from .conftest import render_config_partial, PRESERVED_DIR @pytest.fixture @@ -87,3 +89,31 @@ def test_render_template(write_qhub_config_to_file): assert qhub_config_json["namespace"] == namespace assert qhub_config_json["domain"] == domain assert qhub_config_json["provider"] == cloud_provider + + +def test_exists_after_render(write_qhub_config_to_file): + items_to_check = [ + ".gitignore", + "image", + "stages", + "qhub-config.yaml", + PRESERVED_DIR, + ] + + qhub_config_loc, _ = write_qhub_config_to_file + + yaml = YAML() + qhub_config_json = yaml.load(qhub_config_loc.read_text()) + + # list of files/dirs available after `qhub render` command + ls = os.listdir(Path(qhub_config_loc).parent.resolve()) + + cicd = qhub_config_json.get("ci_cd", {}).get("type", None) + + if cicd == "github-actions": + items_to_check.append(".github") + elif cicd == "gitlab-ci": + items_to_check.append(".gitlab-ci.yml") + + for i in items_to_check: + assert i in ls diff --git a/tests/test_upgrade.py b/tests/test_upgrade.py index 87f6b4ab0..1149f4828 100644 --- a/tests/test_upgrade.py +++ b/tests/test_upgrade.py @@ -34,7 +34,7 @@ def qhub_users_import_json(): ), ], ) -def test_upgrade( +def test_upgrade_4_0( old_qhub_config_path_str, attempt_fixes, expect_upgrade_error, diff --git a/tests/vale/styles/vocab.txt b/tests/vale/styles/vocab.txt index 947c929ce..3d7c5931e 100644 --- a/tests/vale/styles/vocab.txt +++ b/tests/vale/styles/vocab.txt @@ -17,6 +17,7 @@ cds ci clearml ClearML +ClearML cli conda config @@ -26,15 +27,16 @@ cpu cpus cuda cudatoolkit -dns -Lego +dashboarding dask Dask Daskgpus dev digital +dns Dockerfile Dockerfiles +Dockerfiles docstrings doctl ebs @@ -58,6 +60,7 @@ grafana gsutil gui Hadolint +Hadolint hostname http https @@ -67,11 +70,14 @@ ip ipywidget Jitsi jovyan +JSON jupyter jupyterhub jupyterlab K9s Kellndorfer +keycloak +Keycloak Keycloak kube kubectl @@ -79,6 +85,7 @@ Kubectl kubelet kubernetes kubespawner +Lego linux metallb metapackage @@ -86,17 +93,23 @@ minikube Minikube mongodb Mongodb +myclient nameserver nameservers +nameservers namespace namespaces nfs nodegroup nodegroups +nss +NSS nvidia occuring +omitted overridable pangeo +param passwordless performant Plotly @@ -126,6 +139,7 @@ tarballed tarballing tcp termina +tf tfstate tls tracebacks @@ -133,8 +147,11 @@ traefik Traefik traitlets untaring +URI +URIs url usecases +userinfo validator vcpu virtualenv @@ -145,10 +162,3 @@ vscode walkthrough webapp yaml -ClearML -Hadolint -Dockerfiles -nameservers -omitted -keycloak -Keycloak diff --git a/tests_deployment/test_jupyterhub_ssh.py b/tests_deployment/test_jupyterhub_ssh.py index ecfed3f2b..0f2e3113e 100644 --- a/tests_deployment/test_jupyterhub_ssh.py +++ b/tests_deployment/test_jupyterhub_ssh.py @@ -1,4 +1,3 @@ - import re import uuid diff --git a/tests_e2e/package-lock.json b/tests_e2e/package-lock.json index 1970c268a..19e26f7aa 100644 --- a/tests_e2e/package-lock.json +++ b/tests_e2e/package-lock.json @@ -1615,9 +1615,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "node_modules/mkdirp": { @@ -1633,9 +1633,9 @@ } }, "node_modules/moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", + "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==", "dev": true, "engines": { "node": "*" @@ -3578,9 +3578,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "mkdirp": { @@ -3593,9 +3593,9 @@ } }, "moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", + "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==", "dev": true }, "ms": {
  • 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 z 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ℜ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