Skip to content

Commit fc3fdb5

Browse files
committed
Add aws curvenote binderhub
Use manual build of jupyterhub/binderhub#1724
1 parent bea7996 commit fc3fdb5

File tree

7 files changed

+408
-24
lines changed

7 files changed

+408
-24
lines changed

config-kube-system/aws-curvenote.yaml

Lines changed: 0 additions & 19 deletions
This file was deleted.

config-kube-system/curvenote.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Install the more modern load-balancer controller:
2+
# https://docs.aws.amazon.com/eks/latest/userguide/aws-load-balancer-controller.html
3+
aws-load-balancer-controller:
4+
enabled: true
5+
clusterName: binderhub
6+
clusterSecretsPermissions:
7+
allowAllSecrets: true
8+
enableShield: false
9+
enableWaf: false
10+
enableWafv2: false
11+
logLevel: debug
12+
serviceAccount:
13+
# Must match the IRSA service account name
14+
name: aws-load-balancer-controller
15+
annotations:
16+
eks.amazonaws.com/role-arn: "arn:aws:iam::166088433508:role/binderhub-IRSA-aws-load-balancer-controller"
17+
18+
aws-ebs-csi-driver:
19+
enabled: true
20+
controller:
21+
serviceAccount:
22+
# Must match the IRSA service account name
23+
name: ebs-csi-controller-sa
24+
annotations:
25+
eks.amazonaws.com/role-arn: "arn:aws:iam::166088433508:role/binderhub-IRSA-ebs-csi-controller-sa"
26+
storageClasses:
27+
- name: ebs-sc
28+
# Note this results in EKS having two default StorageClasses, so to be sure
29+
# always specify the storage class in the PVC.
30+
annotations:
31+
storageclass.kubernetes.io/is-default-class: "true"

config/aws-curvenote.yaml

Whitespace-only changes.

config/curvenote.yaml

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
projectName: curvenote
2+
3+
# userNodeSelector: &userNodeSelector
4+
# mybinder.org/pool-type: users
5+
# coreNodeSelector: &coreNodeSelector
6+
# mybinder.org/pool-type: core
7+
8+
binderhub:
9+
# Manual build with https://github.com/jupyterhub/binderhub/pull/1637
10+
image:
11+
name: docker.io/manics/binderhub
12+
tag: pr1724-2023-06-27-21-50-amd64
13+
14+
config:
15+
BinderHub:
16+
# hub_url: https://hub.curvenote.mybinder.org
17+
hub_url: https://hub.3.13.147.101.nip.io
18+
hub_url_local: http://proxy-public
19+
badge_base_url: https://mybinder.org
20+
# build_node_selector:
21+
# mybinder.org/pool-type: builds
22+
sticky_builds: true
23+
image_prefix: 166088433508.dkr.ecr.us-east-2.amazonaws.com/binderhub/
24+
# log_level: DEBUG
25+
# TODO: we should have CPU requests, too
26+
# use this to limit the number of builds per node
27+
# complicated: dind memory request + KubernetesBuildExecutor.memory_request * builds_per_node ~= node memory
28+
KubernetesBuildExecutor:
29+
memory_request: "2G"
30+
31+
LaunchQuota:
32+
total_quota: 10
33+
34+
registry:
35+
url: 166088433508.dkr.ecr.us-east-2.amazonaws.com
36+
username: ""
37+
password: ""
38+
39+
replicas: 1
40+
# nodeSelector: *coreNodeSelector
41+
42+
# extraVolumes:
43+
# - name: secrets
44+
# secret:
45+
# secretName: events-archiver-secrets
46+
# extraVolumeMounts:
47+
# - name: secrets
48+
# mountPath: /secrets
49+
# readOnly: true
50+
# extraEnv:
51+
# GOOGLE_APPLICATION_CREDENTIALS: /secrets/service-account.json
52+
53+
extraConfig:
54+
01-eventlog: |
55+
# Disabled until GOOGLE_APPLICATION_CREDENTIALS secret is available
56+
57+
10-external-registry-helper: |
58+
# from binderhub.registry import ExternalRegistryHelper
59+
import json
60+
from tornado import httpclient
61+
from traitlets import Unicode
62+
from binderhub.registry import DockerRegistry
63+
64+
65+
class ExternalRegistryHelper(DockerRegistry):
66+
67+
service_url = Unicode(
68+
"http://binderhub-container-registry-helper:8080",
69+
allow_none=False,
70+
help="The URL of the registry helper micro-service.",
71+
config=True,
72+
)
73+
74+
auth_token = Unicode(
75+
"secret-token",
76+
help="The auth token to use when accessing the registry helper micro-service.",
77+
config=True,
78+
)
79+
80+
async def _request(self, endpoint, **kwargs):
81+
client = httpclient.AsyncHTTPClient()
82+
repo_url = f"{self.service_url}{endpoint}"
83+
headers = {"Authorization": f"Bearer {self.auth_token}"}
84+
repo = await client.fetch(repo_url, headers=headers, **kwargs)
85+
return json.loads(repo.body.decode("utf-8"))
86+
87+
async def _get_image(self, image, tag):
88+
repo_url = f"/image/{image}:{tag}"
89+
self.log.debug(f"Checking whether image exists: {repo_url}")
90+
try:
91+
image_json = await self._request(repo_url)
92+
return image_json
93+
except httpclient.HTTPError as e:
94+
if e.code == 404:
95+
return None
96+
else:
97+
raise
98+
99+
async def get_image_manifest(self, image, tag):
100+
"""
101+
Checks whether the image exists in the registry.
102+
103+
If the container repository doesn't exist create the repository.
104+
105+
The container repository name may not be the same as the BinderHub image name.
106+
107+
E.g. Oracle Container Registry (OCIR) has the form:
108+
OCIR_NAMESPACE/OCIR_REPOSITORY_NAME:TAG
109+
110+
These extra components are handled automatically by the registry helper
111+
so BinderHub repository names such as OCIR_NAMESPACE/OCIR_REPOSITORY_NAME
112+
can be used directly, it is not necessary to remove the extra components.
113+
114+
Returns the image manifest if the image exists, otherwise None
115+
"""
116+
117+
repo_url = f"/repo/{image}"
118+
self.log.debug(f"Checking whether repository exists: {repo_url}")
119+
try:
120+
repo_json = await self._request(repo_url)
121+
except httpclient.HTTPError as e:
122+
if e.code == 404:
123+
repo_json = None
124+
else:
125+
raise
126+
127+
if repo_json:
128+
return await self._get_image(image, tag)
129+
else:
130+
self.log.debug(f"Creating repository: {repo_url}")
131+
await self._request(repo_url, method="POST", body="")
132+
return None
133+
134+
async def get_credentials(self, image, tag):
135+
token_url = f"/token/{image}:{tag}"
136+
self.log.debug(f"Getting registry token: {token_url}")
137+
token_json = None
138+
try:
139+
token_json = await self._request(token_url, method="POST", body="")
140+
except httpclient.HTTPError as e:
141+
if e.code != 404:
142+
raise
143+
token = dict((k, v) for (k, v) in token_json.items() if k in ["username", "password", "registry"])
144+
self.log.debug(f"Returning registry token: {token}")
145+
return token
146+
147+
c.BinderHub.registry_class = ExternalRegistryHelper
148+
c.ExternalRegistryHelper.service_url = "http://curvenote-binderhub-container-registry-helper:8080"
149+
c.ExternalRegistryHelper.auth_token = "secret-token-use-existing-secret-instead"
150+
151+
dind:
152+
resources:
153+
requests:
154+
cpu: "4"
155+
memory: 16Gi
156+
limits:
157+
cpu: "7"
158+
memory: 24Gi
159+
160+
ingress:
161+
hosts:
162+
# - curvenote.mybinder.org
163+
- 3.13.147.101.nip.io
164+
165+
jupyterhub:
166+
# singleuser:
167+
# nodeSelector: *userNodeSelector
168+
# hub:
169+
# nodeSelector: *coreNodeSelector
170+
hub:
171+
db:
172+
pvc:
173+
storageClassName: ebs-sc
174+
175+
singleuser:
176+
initContainers:
177+
- name: tc-init
178+
image: jupyterhub/mybinder.org-tc-init:2020.12.4-0.dev.git.4289.h140cef52
179+
imagePullPolicy: IfNotPresent
180+
env:
181+
- name: WHITELIST_CIDR
182+
value: 10.0.0.0/8
183+
- name: EGRESS_BANDWIDTH
184+
value: 1mbit
185+
securityContext:
186+
# capabilities.add seems to be disabled
187+
# by the `runAsUser: 1000` in the pod-level securityContext
188+
# unless we explicitly run as root
189+
runAsUser: 0
190+
capabilities:
191+
add:
192+
- NET_ADMIN
193+
194+
proxy:
195+
chp:
196+
# nodeSelector: *coreNodeSelector
197+
resources:
198+
requests:
199+
cpu: "1"
200+
limits:
201+
cpu: "1"
202+
ingress:
203+
hosts:
204+
# - hub.curvenote.mybinder.org
205+
- hub.3.13.147.101.nip.io
206+
tls:
207+
- secretName: kubelego-tls-hub
208+
hosts:
209+
# - hub.curvenote.mybinder.org
210+
- hub.3.13.147.101.nip.io
211+
scheduling:
212+
userPlaceholder:
213+
enabled: false
214+
replicas: 50
215+
userScheduler:
216+
enabled: false
217+
# nodeSelector: *coreNodeSelector
218+
cull:
219+
# maxAge: 15 min since we're just testing
220+
maxAge: 900
221+
222+
imageCleaner:
223+
# Use 40GB as upper limit, size is given in bytes
224+
imageGCThresholdHigh: 40e9
225+
imageGCThresholdLow: 30e9
226+
imageGCThresholdType: "absolute"
227+
228+
cryptnono:
229+
enabled: false
230+
231+
grafana:
232+
enabled: false
233+
# nodeSelector: *coreNodeSelector
234+
ingress:
235+
hosts:
236+
# - grafana.curvenote.mybinder.org
237+
tls:
238+
- hosts:
239+
# - grafana.curvenote.mybinder.org
240+
secretName: kubelego-tls-grafana
241+
datasources:
242+
datasources.yaml:
243+
apiVersion: 1
244+
datasources:
245+
- name: prometheus
246+
orgId: 1
247+
type: prometheus
248+
url: https://prometheus.curvenote.mybinder.org
249+
access: direct
250+
isDefault: true
251+
editable: false
252+
persistence:
253+
storageClassName: csi-cinder-high-speed
254+
255+
prometheus:
256+
enabled: false
257+
server:
258+
# nodeSelector: *coreNodeSelector
259+
persistentVolume:
260+
size: 50Gi
261+
retention: 30d
262+
ingress:
263+
hosts:
264+
# - prometheus.curvenote.mybinder.org
265+
tls:
266+
- hosts:
267+
# - prometheus.curvenote.mybinder.org
268+
secretName: kubelego-tls-prometheus
269+
270+
ingress-nginx:
271+
controller:
272+
service:
273+
# loadBalancerIP: 162.19.17.37
274+
annotations:
275+
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
276+
277+
static:
278+
ingress:
279+
hosts:
280+
# - static.curvenote.mybinder.org
281+
- static.3.13.147.101.nip.io
282+
283+
minesweeper:
284+
# Requires secrets
285+
enabled: false
286+
image: jupyterhub/mybinder.org-minesweeper:2020.12.4-0.dev.git.5080.hf35cc80d
287+
288+
289+
binderhub-container-registry-helper:
290+
enabled: true
291+
auth_token: secret-token-use-existing-secret-instead
292+
# auth_existing_secret_name:
293+
replicaCount: 2
294+
serviceAccount:
295+
name: binderhub-container-registry-helper
296+
annotations:
297+
eks.amazonaws.com/role-arn: "arn:aws:iam::166088433508:role/binderhub-IRSA-aws-binderhub-ecr"

0 commit comments

Comments
 (0)