Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New Hub prototype] Binderhub UI demo #4119

Merged
merged 24 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
999a69a
Add initial support for a binderhub UI hub
GeorgianaElena May 22, 2024
81bd511
Add the config files to the new cluster
GeorgianaElena May 22, 2024
34891e0
Use the hub's url
GeorgianaElena May 22, 2024
57dd87e
Make use of binderhub-service new extraEnv
consideRatio May 22, 2024
9d873eb
Use latest binderhub
GeorgianaElena May 24, 2024
8c03dc9
Export more relevant env vars
GeorgianaElena May 24, 2024
c7389a9
Temp use the old chart until latest is fixed
GeorgianaElena May 24, 2024
ecdd191
Fix ingress config and add binderhub's public ip for oauth callback
GeorgianaElena May 24, 2024
492f701
Switch to cilogon, load roles
GeorgianaElena May 25, 2024
f1f04f1
Reset base url otherwise we're stuck with /binder/services
GeorgianaElena May 25, 2024
f17c600
Export JUPYTERHUB_BASE_URL instead of JUPYTHUB_API_URL to fix redirect
GeorgianaElena May 25, 2024
6aa4d03
JUPYTERHUB_API_URL needs to be set as well otherwise a weird concaten…
GeorgianaElena May 25, 2024
e0bbb13
Update the binderhub-service chart
GeorgianaElena May 27, 2024
fe284c1
Temp declare extra config from chart in hub's values file
GeorgianaElena May 27, 2024
55b819e
Temp use old's registry creds
GeorgianaElena May 27, 2024
2f125c1
Add scopes for the binder service to use relevant hub REST API
consideRatio May 28, 2024
c2d5f91
Unset initContainers referencing home folders not mounted
consideRatio May 28, 2024
3523ccb
Unset other volume mounts not used
consideRatio May 28, 2024
e72c1e8
Cleanup not needed parts
consideRatio May 28, 2024
6637088
Cleanup re-setting of default jupyterhub-singleuser
consideRatio May 28, 2024
617292c
Tweak permissions for binder service to be minimal
consideRatio May 28, 2024
7d17a3f
Additional tweaking of required config for binderhub-ui
consideRatio May 28, 2024
41818be
Move the ingress class nama and annotations to basehub
GeorgianaElena May 28, 2024
488641f
Update the registry password with the one in terraform output
GeorgianaElena May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions config/clusters/2i2c/binderhub-ui-demo.values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
jupyterhub:
ingress:
hosts:
- hub.binderhub-ui-demo.2i2c.cloud
tls:
- secretName: https-auto-tls
hosts:
- hub.binderhub-ui-demo.2i2c.cloud
custom:
2i2c:
add_staff_user_ids_to_admin_users: true
add_staff_user_ids_of_type: "google"
jupyterhubConfigurator:
enabled: false
binderhubUI:
enabled: true
homepage:
templateVars:
org:
name: Demo binderhub UI with binderhub-service
url: https://2i2c.org
logo_url: https://2i2c.org/media/logo.png
designed_by:
name: 2i2c
url: https://2i2c.org
operated_by:
name: 2i2c
url: https://2i2c.org
funded_by:
name: ""
url: ""
singleuserAdmin:
extraVolumeMounts: []
singleuser:
storage:
type: none
extraVolumeMounts: []
initContainers: []
hub:
redirectToServer: false
services:
binder:
oauth_no_confirm: true
oauth_redirect_uri: https://binderhub-ui-demo.2i2c.cloud/oauth_callback
loadRoles:
binder:
services:
- binder
scopes:
- servers
- read:users # admin:users is required if authentication isn't enabled
user:
scopes:
- self
# Admin users will by default have access:services, so this is only
# observed to be required for non-admin users.
- access:services!service=binder
config:
BinderSpawnerMixin:
auth_enabled: true
JupyterHub:
authenticator_class: cilogon
CILogonOAuthenticator:
oauth_callback_url: "https://hub.binderhub-ui-demo.2i2c.cloud/hub/oauth_callback"
allowed_idps:
http://google.com/accounts/o8/id:
username_derivation:
username_claim: "email"
binderhub-service:
enabled: true
ingress:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 256m
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- binderhub-ui-demo.2i2c.cloud
tls:
- secretName: binder-https-auto-tls
hosts:
- binderhub-ui-demo.2i2c.cloud
config:
BinderHub:
base_url: /
hub_url: https://hub.binderhub-ui-demo.2i2c.cloud
badge_base_url: https://binderhub-ui-demo.2i2c.cloud
auth_enabled: true
enable_api_only_mode: false
image_prefix: us-central1-docker.pkg.dev/two-eye-two-see/binderhub-ui-demo-registry/binderhub-service-
extraConfig:
# FIXME: set KubernetesBuildExecutor.push_secret again
# without this for some reason the build pods
# search after the wrong secret name (i.e. the default name)
# set by binderhub in KubernetesBuildExecutor.push_secret
01-binderhub-service-set-push-secret: |
import os
c.KubernetesBuildExecutor.push_secret = os.environ["PUSH_SECRET_NAME"]
Comment on lines +87 to +94
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I have no idea what happened here. I tried investigated and started by removing this hack and checked again and this time it worked. Maybe there's something relevant that didn't get properly cleared during the redeploy?

Anyway, I will drop the commit that added this, but leaving this here for posterity in case there is indeed something going on:

This is what the build pod showed before this hack, yesterday

Warning  FailedMount  6m4s (x114 over 3h41m)  kubelet  MountVolume.SetUp failed for volume "docker-config" : secret "binder-build-docker-config" not found
Volumes:
  docker-socket:
    Type:          HostPath (bare host directory volume)
    Path:          /var/run/docker.sock
    HostPathType:  Socket
  docker-config:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  binder-build-docker-config
    Optional:    false
  kube-api-access-687gt:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true

Copy link
Member

@consideRatio consideRatio May 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every time I work with binderhub, the push_secret config is a big confusion =/

TL;DR - I was confused, and remain confused why you observed that.

Here are reasons for why its confusing observed in the last ~5 minutes looking:

  1. push_secret should be configured to a k8s secret name having a config.json key providing a docker configuration including credentials to work against a registry (its not the typical k8s imagePullSecret or similar, its a docker client config)
  2. binder-build-docker-config is a default value for push_secret, but its also hardcoded i the official BinderHub helm chart deployment, but in binderhub-service deployment it isn't hardcoded - instead push_secret is set by a extraConfig entry based on an env variable etc - we shouldn't touch push_secret config as users of binderhub-service I think.
  3. In binderhub-service chart, we configure credentials that goes into the k8s Secret via chart config buildPodsRegistryCredentials, but in the official chart its under config.BinderHub.buildDockerConfig which is confusing because it isn't a traitlet for the Python class BinderHub as expected if listed there.
  4. The binderhub-service deployment resource isn't automatically restarting if the credentials set via buildPodsRegistryCredentials is updated - it only gets restarted if there is something in the pod spec that changes, such as an annotation providing a hash of the secret. I'll fix this. EDIT: nevermind what I wrote doesn't make sense I realize.

extraEnv:
- name: JUPYTERHUB_API_TOKEN
valueFrom:
secretKeyRef:
name: '{{ include "jupyterhub.hub.fullname" . }}'
key: hub.services.binder.apiToken
- name: JUPYTERHUB_CLIENT_ID
value: "service-binder"
- name: JUPYTERHUB_API_URL
value: "https://hub.binderhub-ui-demo.2i2c.cloud/hub/api"
# Without this, the redirect URL to /hub/api/... gets
# appended to binderhub's URL instead of the hub's
- name: JUPYTERHUB_BASE_URL
value: "https://hub.binderhub-ui-demo.2i2c.cloud/"
- name: JUPYTERHUB_OAUTH_CALLBACK_URL
value: "https://binderhub-ui-demo.2i2c.cloud/oauth_callback"
# The password to the registry is stored encrypted in the hub's encrypted config file
buildPodsRegistryCredentials:
server: "https://us-central1-docker.pkg.dev"
username: "_json_key"
8 changes: 8 additions & 0 deletions config/clusters/2i2c/cluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ hubs:
- basehub-common.values.yaml
- imagebuilding-demo.values.yaml
- enc-imagebuilding-demo.secret.values.yaml
- name: binderhub-ui-demo
display_name: "2i2c Binderhub UI demo"
domain: hub.binderhub-ui-demo-demo.2i2c.cloud
helm_chart: basehub
helm_chart_values_files:
- basehub-common.values.yaml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just enables nfs things we won't use, should be removed I think.

- binderhub-ui-demo.values.yaml
- enc-binderhub-ui-demo.secret.values.yaml
- name: demo
display_name: "2i2c demo"
domain: demo.2i2c.cloud
Expand Down
23 changes: 23 additions & 0 deletions config/clusters/2i2c/enc-binderhub-ui-demo.secret.values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
binderhub-service:
buildPodsRegistryCredentials:
password: ENC[AES256_GCM,data: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,iv:Fr6VUfSfac5BrF/WGSTz0NUEsYAtQJmTFTLQUAgr7vg=,tag:5ch5EIGE0bz06GMBEywQwg==,type:str]
jupyterhub:
hub:
config:
CILogonOAuthenticator:
client_id: ENC[AES256_GCM,data:tEZMVs9TkdzJaAqsbF+uNX2uwhTCnsuJnxcwJD3rSB0FXt481yze4Rs8t/5Ef/npccE=,iv:bJzGDmlZArcO3yfUO9mCQDDZI7jMDjeC66U7zvBWSKI=,tag:Xt8OKd/iFHik6a6QesR7wg==,type:str]
client_secret: ENC[AES256_GCM,data:AwgZagRLArMGhZji3jon4YVjfblBmp3wyTmqvOFg7mZs5LMiFNrlnAtTQ8oqv5O4QQfyeMGZhustlnmmWMW9Vqtxkax3zljiPfAA0zfy/Ie4t0085Nw=,iv:vwPzC67oR7vzOHEyDMs2PDc19mRRPMkIjSDScT6M0Cc=,tag:imEiXTjo7KGB9Wl2G8eyMQ==,type:str]
sops:
kms: []
gcp_kms:
- resource_id: projects/two-eye-two-see/locations/global/keyRings/sops-keys/cryptoKeys/similar-hubs
created_at: "2023-09-18T19:00:41Z"
enc: CiUA4OM7eFioG9yDgVwKtc0cYrU65GNcqMSDuUgnuXuq3KW9dRI6EkkAq2nhVV2TFrZOq5jktjMd4TQF1lwH/08tAyGd3vMfBmdd3Xdy3bAUUHhrPXcK6QabMRYdXPzQzgB+oBGaqOsJO7D7jT9NpeCn
azure_kv: []
hc_vault: []
age: []
lastmodified: "2024-05-27T20:18:26Z"
mac: ENC[AES256_GCM,data:FWM3YCH5DXlFQPmPXlyNzyxadbMCuUdvR45+dgOP+wieErZILIU6Qc3oA65lmHsAZXNeFyO5Iak97x8+MnnLlmx4THDYdfntpMiAIxohpAYBaA5rDK575xFOQUeDwVZkvljD00Zjq5sUfummN4h85lQsNkHB0kp1BGtz7BsoseY=,iv:IRw83ZG/yVpEeJJ3hqwcKSf8r/Lvho8/Cj4L4qgBhLw=,tag:mLCTv+PJ0atXvLBT7nXLlQ==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.8.1
2 changes: 1 addition & 1 deletion helm-charts/basehub/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ dependencies:
version: 3.3.7
repository: https://jupyterhub.github.io/helm-chart/
- name: binderhub-service
version: 0.1.0-0.dev.git.110.hd833d08
version: 0.1.0-0.dev.git.240.hdaf17cc
repository: https://2i2c.org/binderhub-service/
condition: binderhub-service.enabled
8 changes: 8 additions & 0 deletions helm-charts/basehub/values.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -516,3 +516,11 @@ properties:
properties:
enabled:
type: boolean
binderhubUI:
type: object
additionalProperties: false
required:
- enabled
properties:
enabled:
type: boolean
122 changes: 122 additions & 0 deletions helm-charts/basehub/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,125 @@ jupyterhub:
limits:
memory: 2Gi
extraConfig:
# This is copy-pasted exactly from https://github.com/jupyterhub/binderhub/blob/c6c5dc8fe73f81ca538c47b420b33f317c3aa8ae/helm-chart/binderhub/values.yaml#L87
# Should be updated every time the upstream code changes
0-binderspawnermixin: |
"""
Helpers for creating BinderSpawners

FIXME:
This file is defined in binderhub/binderspawner_mixin.py
and is copied to helm-chart/binderhub/values.yaml
by ci/check_embedded_chart_code.py

The BinderHub repo is just used as the distribution mechanism for this spawner,
BinderHub itself doesn't require this code.

Longer term options include:
- Move BinderSpawnerMixin to a separate Python package and include it in the Z2JH Hub
image
- Override the Z2JH hub with a custom image built in this repository
- Duplicate the code here and in binderhub/binderspawner_mixin.py
"""

from tornado import web
from traitlets import Bool, Unicode
from traitlets.config import Configurable


class BinderSpawnerMixin(Configurable):
"""
Mixin to convert a JupyterHub container spawner to a BinderHub spawner

Container spawner must support the following properties that will be set
via spawn options:
- image: Container image to launch
- token: JupyterHub API token
"""

def __init__(self, *args, **kwargs):
# Is this right? Is it possible to having multiple inheritance with both
# classes using traitlets?
# https://stackoverflow.com/questions/9575409/calling-parent-class-init-with-multiple-inheritance-whats-the-right-way
# https://github.com/ipython/traitlets/pull/175
super().__init__(*args, **kwargs)

auth_enabled = Bool(
False,
help="""
Enable authenticated binderhub setup.

Requires `jupyterhub-singleuser` to be available inside the repositories
being built.
""",
config=True,
)

cors_allow_origin = Unicode(
"",
help="""
Origins that can access the spawned notebooks.

Sets the Access-Control-Allow-Origin header in the spawned
notebooks. Set to '*' to allow any origin to access spawned
notebook servers.

See also BinderHub.cors_allow_origin in binderhub config
for controlling CORS policy for the BinderHub API endpoint.
""",
config=True,
)

def get_args(self):
if self.auth_enabled:
args = super().get_args()
else:
args = [
"--ip=0.0.0.0",
f"--port={self.port}",
f"--NotebookApp.base_url={self.server.base_url}",
f"--NotebookApp.token={self.user_options['token']}",
"--NotebookApp.trust_xheaders=True",
]
if self.default_url:
args.append(f"--NotebookApp.default_url={self.default_url}")

if self.cors_allow_origin:
args.append("--NotebookApp.allow_origin=" + self.cors_allow_origin)
# allow_origin=* doesn't properly allow cross-origin requests to single files
# see https://github.com/jupyter/notebook/pull/5898
if self.cors_allow_origin == "*":
args.append("--NotebookApp.allow_origin_pat=.*")
args += self.args
# ServerApp compatibility: duplicate NotebookApp args
for arg in list(args):
if arg.startswith("--NotebookApp."):
args.append(arg.replace("--NotebookApp.", "--ServerApp."))
return args

def start(self):
if not self.auth_enabled:
if "token" not in self.user_options:
raise web.HTTPError(400, "token required")
if "image" not in self.user_options:
raise web.HTTPError(400, "image required")
if "image" in self.user_options:
self.image = self.user_options["image"]
return super().start()

def get_env(self):
env = super().get_env()
if "repo_url" in self.user_options:
env["BINDER_REPO_URL"] = self.user_options["repo_url"]
for key in (
"binder_ref_url",
"binder_launch_host",
"binder_persistent_request",
"binder_request",
):
if key in self.user_options:
env[key.upper()] = self.user_options[key]
return env
01-custom-theme: |
# adds a JupyterHub template path and updates template variables

Expand Down Expand Up @@ -861,6 +980,8 @@ jupyterhub:
}
c.JupyterHub.services.append(jhc_service)

if get_config("custom.binderhubUI.enabled"):
spawner_base_classes = [BinderSpawnerMixin, KubeSpawner]

class BaseHubSpawner(*spawner_base_classes):
def start(self, *args, **kwargs):
Expand All @@ -883,6 +1004,7 @@ jupyterhub:
self.service_account = admin_service_account

return super().start(*args, **kwargs)

c.JupyterHub.spawner_class = BaseHubSpawner


Expand Down
1 change: 1 addition & 0 deletions terraform/gcp/projects/pilot-hubs.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ hub_cloud_permissions = {

container_repos = [
"binder-staging",
"binderhub-ui-demo"
]