Skip to content

Commit

Permalink
1
Browse files Browse the repository at this point in the history
  • Loading branch information
yiyinglovecoding committed Mar 26, 2024
1 parent 9d7a427 commit d2e2a8a
Show file tree
Hide file tree
Showing 86 changed files with 1,313 additions and 670 deletions.
28 changes: 13 additions & 15 deletions applications/jupyter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ This code can also perform auto brand creation. Please check the details [below]
* Terraform
* Gcloud CLI

Jupyterhub server can use either local storage or GCS to store notebooks and other artifcts.
JupyterHub server can use either local storage or GCS to store notebooks and other artifcts.
To use GCS, create a bucket with your username. For example, when authenticating with IAP as [email protected], ensure your bucket name is `gcsfuse-<username>`

## Installation
Expand All @@ -43,7 +43,7 @@ To use GCS, create a bucket with your username. For example, when authenticating
cd ai-on-gke/applications/jupyter
```

2. Edit `workloads.tfvars` with your GCP settings. The `namespace` that you specify will become a K8s namespace for your Jupyterhub services. For more information about what the variables do visit [here](https://github.com/GoogleCloudPlatform/ai-on-gke/blob/main/applications/jupyter/variable_definitions.md)
2. Edit `workloads.tfvars` with your GCP settings. The `namespace` that you specify will become a K8s namespace for your JupyterHub services. For more information about what the variables do visit [here](https://github.com/GoogleCloudPlatform/ai-on-gke/blob/main/applications/jupyter/variable_definitions.md)

**Important Note:**
If using this with the Ray module (`applications/ray/`), it is recommended to use the same k8s namespace
Expand All @@ -55,12 +55,12 @@ for both i.e. set this to the same namespace as `applications/ray/workloads.tfva
| cluster_name | GKE Cluster Name | Yes |
| cluster_location | GCP Region | Yes |
| cluster_membership_id | Fleet membership name for GKE cluster. <br /> Required when using private clusters with Anthos Connect Gateway | |
| namespace | The namespace that Jupyterhub and rest of the other resources will be installed in. | Yes |
| namespace | The namespace that JupyterHub and rest of the other resources will be installed in. | Yes |
| gcs_bucket | GCS bucket to be used for Jupyter storage | |
| create_service_account | Create service accounts used for Workload Identity mapping | Yes |
| gcp_and_k8s_service_account | GCP service account used for Workload Identity mapping and k8s sa attached with workload | Yes |

For variables under `Jupyterhub with IAP`, please see the section below
For variables under `JupyterHub with IAP`, please see the section below

### Secure endpoint with IAP

Expand All @@ -78,7 +78,7 @@ See the example `.tfvars` files under `/applications/jupyter` for different bran

| Variable | Description | Default Value | Required |
| ------------------------ |--------------------------- |:-------------:|:--------:|
| add_auth | Enable IAP on Jupyterhub | true | Yes |
| add_auth | Enable IAP on JupyterHub | true | Yes |
| brand | Name of the brand used for creating IAP OAuth clients. Only one is allowed per project. View existing brands: `gcloud iap oauth-brands list`. Leave it empty to create a new brand. Uses [support_email](#support_email) | | |
| support_email | Support email assocated with the [brand](#brand). Used as a point of contact for consent for the ["OAuth Consent" in Cloud Console](https://console.cloud.google.com/apis/credentials/consent). Optional field if `brand` is empty. | | |
| default_backend_service | default_backend_service | | |
Expand Down Expand Up @@ -109,19 +109,17 @@ gcloud auth application-default login
- Should have `jupyter-proxy-public` in the name eg.: `k8s1-63da503a-jupyter-proxy-public-80-74043627`.
* Run `terraform apply --var-file=./workloads.tfvars`

## Using Jupyterhub
## Using JupyterHub

### If Auth with IAP is disabled

1. Extract the randomly generated password for Jupyterhub login
1. Extract the randomly generated password for JupyterHub login

```
terraform output password
```

2. Visit [Services](https://console.cloud.google.com/kubernetes/discovery) section on the GKE console & open the external IP for the `proxy-public` service in the browser.

> **_NOTE:_** If there isn't an external IP for `proxy-public`, is it most likely due to authentication being enabled.
2. Setup port forwarding for the frontend: `kubectl port-forward service/proxy-public -n <namespace> 8081:80 &`, and open `localhost:8081` in a browser.

### If Auth with IAP is enabled

Expand All @@ -139,17 +137,17 @@ Please note there may be some propagation delay after adding IAP principals (5-1
### Setup Access

In order for users to login to Jupyterhub via IAP, their access needs to be configured. To allow access for users/groups:
In order for users to login to JupyterHub via IAP, their access needs to be configured. To allow access for users/groups:

1. Navigate to the [GCP IAP Cloud Console](https://console.cloud.google.com/security/iap) and select your backend-service for `<namespace>/proxy-public`.

2. Click on `Add Principal`, insert the username / group name and select under `Cloud IAP` with role `IAP-secured Web App User`. Once presmission is granted, these users / groups can login to Jupyterhub with IAP. Please note there may be some propagation delay after adding IAP principals (5-10 mins).
2. Click on `Add Principal`, insert the username / group name and select under `Cloud IAP` with role `IAP-secured Web App User`. Once presmission is granted, these users / groups can login to JupyterHub with IAP. Please note there may be some propagation delay after adding IAP principals (5-10 mins).

## Persistent Storage

Jupyterhub is configured to provide 2 choices for storage:
JupyterHub is configured to provide 2 choices for storage:

1. Default Jupyterhub Storage - `pd.csi.storage.gke.io` with reclaim policy `Delete`
1. Default JupyterHub Storage - `pd.csi.storage.gke.io` with reclaim policy `Delete`

2. GCSFuse - `gcsfuse.csi.storage.gke.io` uses GCS Buckets and require users to pre-create buckets with name format `gcsfuse-{username}`

Expand Down Expand Up @@ -194,4 +192,4 @@ This module uses `<ip>.nip.io` as the domain name with a global static ipv4 addr
## Additional Information
For more information about Jupyterhub profiles and the preset profiles visit [here](https://github.com/GoogleCloudPlatform/ai-on-gke/blob/main/applications/jupyter/profiles.md)
For more information about JupyterHub profiles and the preset profiles visit [here](https://github.com/GoogleCloudPlatform/ai-on-gke/blob/main/applications/jupyter/profiles.md)
40 changes: 30 additions & 10 deletions applications/jupyter/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,36 @@ data "google_project" "project" {
project_id = var.project_id
}

## Enable Required GCP Project Services APIs
module "project-services" {
source = "terraform-google-modules/project-factory/google//modules/project_services"
version = "~> 14.5"

project_id = var.project_id
disable_services_on_destroy = false
disable_dependent_services = false
activate_apis = flatten([
"autoscaling.googleapis.com",
"cloudbuild.googleapis.com",
"cloudresourcemanager.googleapis.com",
"compute.googleapis.com",
"config.googleapis.com",
"connectgateway.googleapis.com",
"container.googleapis.com",
"containerfilesystem.googleapis.com",
"dns.googleapis.com",
"gkehub.googleapis.com",
"iamcredentials.googleapis.com",
"logging.googleapis.com",
"monitoring.googleapis.com",
"pubsub.googleapis.com",
"servicenetworking.googleapis.com",
"serviceusage.googleapis.com",
"sourcerepo.googleapis.com",
(var.add_auth ? ["iap.googleapis.com"] : [])
])
}

module "infra" {
source = "../../infrastructure"
count = var.create_cluster ? 1 : 0
Expand Down Expand Up @@ -106,16 +136,6 @@ module "namespace" {
create_namespace = true
}

# IAP Section: Enabled the IAP service
resource "google_project_service" "project_service" {
count = var.add_auth ? 1 : 0
project = var.project_id
service = "iap.googleapis.com"

disable_dependent_services = false
disable_on_destroy = false
}

# Creates jupyterhub
module "jupyterhub" {
source = "../../modules/jupyter"
Expand Down
12 changes: 6 additions & 6 deletions applications/jupyter/metadata.display.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,18 @@ spec:
title: Other Configuration
- name: iap_auth
title: Configure Authenticated Access for JupyterHub
subtext: Make sure the <a href="https://developers.google.com/workspace/guides/configure-oauth-consent#configure_oauth_consent"><i>OAuth Consent Screen</i></a> is configured for your project. Ensure <b>User type</b> is set to Internal.
subtext: Make sure the <a href="https://developers.google.com/workspace/guides/configure-oauth-consent#configure_oauth_consent"><i>OAuth Consent Screen</i></a> is configured for your project. Ensure <b>User type</b> is set to <i>Internal</i>. Note that by default, only users within your organization can be allowlisted. To add external users, change the <b>User type</b> to <i>External</i> after the application is deployed.
runtime:
outputMessage: Deployment can take several minutes to complete.
suggestedActions:
- heading: "Step 1: Create DNS A Records for Jupyterhub"
- heading: "Step 1: Create DNS A Records for JupyterHub"
description: |-
If using custom domains for Jupyterhub, create DNS A record set (<a href="https://cloud.google.com/dns/docs/records#add_a_record">Google DNS Record Set</a>). Propagation takes 10-15 minutes and logging in won’t succeed until it’s done.
If using custom domains for JupyterHub, create DNS A record set (<a href="https://cloud.google.com/dns/docs/records#add_a_record">Google DNS Record Set</a>). Propagation takes 10-15 minutes and logging in won’t succeed until it’s done.
- heading: "Step 2: Go to JupyterHub Application"
description: |-
<li>If IAP is enabled, log in with your organization's credentials.</li>
<li>If IAP is disabled, scroll to <i>Ports</i> section and initiate <b>PORT FORWARDING</b> (Run in Cloud Shell) to the front end application. Launch JupyterHub app via <b>OPEN IN WEB PREVIEW</b> button. Log in with <i>Jupyterhub User</i> and <i>Jupyterhub Password</i> (from the Outputs section).</li>
<li> Once logged in, choose the appropriate preset and execute notebooks.</li>
<li>If IAP is enabled, log in with your organization's credentials. SSL or cert errors indicate the cert is provisioning which takes up to 20 minutes.</li>
<li>If IAP is disabled, scroll to <b>Ports</b> section and initiate <b>PORT FORWARDING</b> (Run in Cloud Shell) to the front end application. Launch JupyterHub app via <b>OPEN IN WEB PREVIEW</b> button. Log in with <i>Jupyterhub User</i> and <i>Jupyterhub Password</i> (from the Outputs section).</li>
<li>Once logged in, choose the appropriate preset and execute notebooks. Sample notebooks are provided <a href="https://github.com/GoogleCloudPlatform/ai-on-gke/tree/main/ray-on-gke/examples/notebooks">here</a></li>
outputs:
jupyterhub_password: {}
jupyterhub_uri:
Expand Down
8 changes: 4 additions & 4 deletions applications/jupyter/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ spec:
defaultValue: false
- name: autopilot_cluster
varType: string
defaultValue: "false"
defaultValue: "true"
- name: client_id
description: Client ID used for enabling IAP
varType: string
Expand Down Expand Up @@ -71,7 +71,7 @@ spec:
- name: domain
description: Domain used for SSL certificate. If it's empty, *.nip.io DNS is used.
varType: string
defaultValue: ""
defaultValue: "jupyter.example.com"
- name: gcs_bucket
description: Bucket name to store the dataset. The bucket name must be globally unique across google cloud projects
varType: string
Expand Down Expand Up @@ -109,7 +109,7 @@ spec:
- name: additional_labels
description: Additional labels to apply to Kubenetes resources
varType: list(string)
defaultValue: ["created-by=jupyter-on-gke-qss"]
defaultValue: ["created-by=gke-ai-quick-start-solutions", "ai.gke.io=jupyter"]
- name: members_allowlist
description: "For example - user:[email protected],serviceAccount:[email protected],group:[email protected],domain:google.com"
varType: string
Expand All @@ -131,7 +131,7 @@ spec:
defaultValue: jupyter-service-account
outputs:
- name: jupyterhub_ip_address
description: JupyterHub gloabl IP address
description: JupyterHub global IP address
- name: jupyterhub_password
description: JupyterHub password is only required for standard authentication. Ignore, in case of IAP authentication
- name: jupyterhub_uri
Expand Down
2 changes: 1 addition & 1 deletion applications/jupyter/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ output "jupyterhub_uri" {
}

output "jupyterhub_ip_address" {
description = "JupyterHub gloabl IP address"
description = "JupyterHub global IP address"
value = module.jupyterhub.jupyterhub_ip_address
}

Expand Down
8 changes: 4 additions & 4 deletions applications/jupyter/profiles.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Jupyterhub Profiles
# JupyterHub Profiles

## Default Profiles

By default, there are 3 pre-set profiles for Jupyterhub:
By default, there are 3 pre-set profiles for JupyterHub:

![Profiles Page](images/image.png)

Expand Down Expand Up @@ -85,7 +85,7 @@ Similar to overriding images, the resources can also be overwritten by using `ku

### Node/GPU

Jupyterhub config allows the use of [nodeSelector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector). This is the way the profiles specify which node/GPU it wants
JupyterHub config allows the use of [nodeSelector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector). This is the way the profiles specify which node/GPU it wants

``` yaml
nodeSelector:
Expand Down Expand Up @@ -114,7 +114,7 @@ The possible GPUs are:

### TPUs

Jupyterhub profiles has a TPU option. It utilizes the [nodeSelector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector), and the annotations `cloud.google.com/gke-tpu-accelerator` and `cloud.google.com/gke-tpu-topology` to select the TPU nodes.
JupyterHub profiles has a TPU option. It utilizes the [nodeSelector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector), and the annotations `cloud.google.com/gke-tpu-accelerator` and `cloud.google.com/gke-tpu-topology` to select the TPU nodes.

We add the following annotations to `kupespawner_override`

Expand Down
8 changes: 4 additions & 4 deletions applications/jupyter/variable_definitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ This README contains all the variables used by Terraform for installing Juypterh

### namespace

The namespace that Jupyterhub and rest of the other resources will be installed/allocated in. If using Jupyterhub with the Ray module (`ai-on-gke/ray-on-gke/`), it is recommanded to have this namespace the same as the one with Ray.
The namespace that JupyterHub and rest of the other resources will be installed/allocated in. If using JupyterHub with the Ray module (`ai-on-gke/ray-on-gke/`), it is recommanded to have this namespace the same as the one with Ray.

### create_service_account

Create k8s and GCP service accounts for Jupyterhub workloads & configures workload identity.
Create k8s and GCP service accounts for JupyterHub workloads & configures workload identity.

### add_auth

Flag that will enable IAP on Jupyterhub. Resources that will be created along with enable IAP:
Flag that will enable IAP on JupyterHub. Resources that will be created along with enable IAP:
1. Global IP Address (If none is provided)
2. Backend Config. Deployment that triggers enabling IAP.
3. Managed Certificate. Deployment that creates a Google Managed object for SSL certificates
4. Ingress. Deployment that creates an Ingress object that will connect to the Jupyterhub Proxy
4. Ingress. Deployment that creates an Ingress object that will connect to the JupyterHub Proxy

### project_id

Expand Down
2 changes: 1 addition & 1 deletion applications/jupyter/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ variable "additional_labels" {
// list(string) is used instead of map(string) since blueprint metadata does not support maps.
type = list(string)
description = "Additional labels to add to Kubernetes resources."
default = ["created-by=jupyter-on-gke"]
default = ["created-by=ai-on-gke", "ai.gke.io=jupyter"]
}

variable "gcs_bucket" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ create_gcs_bucket = true
gcs_bucket = "<gcs-bucket>"
workload_identity_service_account = "jupyter-service-account"

# Jupyterhub with IAP
# JupyterHub with IAP
add_auth = true
brand = "" # Leave it empty to auto create
support_email = "<email>"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace = "jupyter"
gcs_bucket = "<gcs-bucket>"
workload_identity_service_account = "jupyter-service-account"

# Jupyterhub with IAP
# JupyterHub with IAP
add_auth = true
brand = "projects/<prj-number>/brands/<prj-number>" # ensure brand is Internal
support_email = "<email>"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ create_gcs_bucket = true
gcs_bucket = "<gcs-bucket>"
workload_identity_service_account = "jupyter-service-account"

# Jupyterhub with IAP
# JupyterHub with IAP
add_auth = true
brand = "projects/<prj-number>/brands/<prj-number>"
support_email = "<email>"
Expand Down
2 changes: 1 addition & 1 deletion applications/jupyter/workloads-without-iap.example.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ gcs_bucket = "<gcs-bucket>"
create_gcs_bucket = true
workload_identity_service_account = "jupyter-service-account"

# Jupyterhub without IAP
# JupyterHub without IAP
add_auth = false
4 changes: 2 additions & 2 deletions applications/jupyter/workloads.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ cluster_membership_id = "" # required for private cluster, defaults to `cluster_
#######################################################

## JupyterHub variables
namespace = "ml"
kubernetes_namespace = "ml"
create_gcs_bucket = true
gcs_bucket = "gcs-bucket-<unique-suffix>" # Choose a globally unique bucket name.
workload_identity_service_account = "jupyter-sa"
Expand All @@ -36,7 +36,7 @@ workload_identity_service_account = "jupyter-sa"
create_brand = false
support_email = "<email>" ## specify if create_brand=true

# Jupyterhub with IAP
# JupyterHub with IAP
add_auth = false
k8s_ingress_name = "jupyter-ingress"
k8s_managed_cert_name = "jupyter-managed-cert"
Expand Down
Loading

0 comments on commit d2e2a8a

Please sign in to comment.