Skip to content

Commit

Permalink
Add a 2i2c federation member on Hetzner
Browse files Browse the repository at this point in the history
https://2i2c.mybinder.org/ is up now!

https://github.com/2i2c-org/2i2c-org.github.io/pull/356/files#diff-7244b57e647732dd6a8f006bdf63943e1dcb813fa1a085073522ccf40e2cdfc6
has more context - that's also an announcement blog post. It came
together quickly.

This is a single node k3s cluster running on Hetzner. It's not as
large as we'd like it to be - which is CCX63 on https://www.hetzner.com/cloud.
That's 48 vCPUs and 192GB of RAM. And with k3s, we can override the
number of pods on a node. Given the current guarantee of 450M, we can
put approximately 400 pods on this one node! That runs out to less
than $1 / month per user capacity which is pretty good.

Still need to figure out:

1. Access for everyone else on the team
2. Resize the server to be big, and set up k3s again there from
   scratch + document (I simply followed the quickstart with traefik
   disabled)
3. Test prometheus and grafana
4. Add 2i2c to list of supporters

Am excited to try this out and see how it goes.

Thanks to @choldgraf, @colliand, @jmunroe and others at 2i2c
for supporting me through this.
  • Loading branch information
yuvipanda committed Jan 17, 2025
1 parent b9439b5 commit ff2a59b
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 10 deletions.
118 changes: 118 additions & 0 deletions config/hetzner-2i2c.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
projectName: hetzner-2i2c

cryptnono:
detectors:
monero:
enabled: false

binderhub:
config:
BinderHub:
hub_url: https://hub.2i2c.mybinder.org
badge_base_url: https://mybinder.org
sticky_builds: true
image_prefix: quay.io/mybinder-hetzner-2i2c/image-
# build_docker_host: /var/run/dind/docker.sock
# TODO: we should have CPU requests, too
# use this to limit the number of builds per node
# complicated: dind memory request + KubernetesBuildExecutor.memory_request * builds_per_node ~= node memory
KubernetesBuildExecutor:
memory_request: "2G"
docker_host: /var/run/dind/docker.sock

LaunchQuota:
total_quota: 300

# DockerRegistry:
# token_url: "https://2lmrrh8f.gra7.container-registry.ovh.net/service/token?service=harbor-registry"

replicas: 1

extraVolumes:
- name: secrets
secret:
secretName: events-archiver-secrets
extraVolumeMounts:
- name: secrets
mountPath: /secrets
readOnly: true
extraEnv:
GOOGLE_APPLICATION_CREDENTIALS: /secrets/service-account.json

dind: {}

ingress:
hosts:
- 2i2c.mybinder.org

jupyterhub:
# proxy:
# chp:
# resources:
# requests:
# cpu: "1"
# limits:
# cpu: "1"
ingress:
hosts:
- hub.2i2c.mybinder.org
tls:
- secretName: kubelego-tls-hub
hosts:
- hub.2i2c.mybinder.org

imageCleaner:
# Use 40GB as upper limit, size is given in bytes
imageGCThresholdHigh: 40e9
imageGCThresholdLow: 30e9
imageGCThresholdType: "absolute"

grafana:
ingress:
hosts:
- grafana.2i2c.mybinder.org
tls:
- hosts:
- grafana.2i2c.mybinder.org
secretName: kubelego-tls-grafana
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: prometheus
orgId: 1
type: prometheus
url: https://prometheus.2i2c.mybinder.org
access: direct
isDefault: true
editable: false
# persistence:
# storageClassName: csi-cinder-high-speed

prometheus:
server:
persistentVolume:
size: 50Gi
retention: 30d
ingress:
hosts:
- prometheus.2i2c.mybinder.org
tls:
- hosts:
- prometheus.2i2c.mybinder.org
secretName: kubelego-tls-prometheus

ingress-nginx:
controller:
replicas: 1
scope:
enabled: true
service:
loadBalancerIP: 138.199.149.127

static:
ingress:
hosts:
- static.2i2c.mybinder.org
tls:
secretName: kubelego-tls-static
22 changes: 12 additions & 10 deletions deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
"prod": "us-central1",
}

# Projects using raw KUBECONFIG files
KUBECONFIG_CLUSTERS = {"ovh2", "hetzner-2i2c"}

# Mapping of config name to cluster name for AWS EKS deployments
AWS_DEPLOYMENTS = {"curvenote": "binderhub"}

Expand Down Expand Up @@ -100,17 +103,15 @@ def setup_auth_azure(cluster, dry_run=False):
print(stdout)


def setup_auth_ovh(release, cluster, dry_run=False):
def setup_auth_kubeconfig(release, cluster, dry_run=False):
"""
Set up authentication with 'ovh' K8S from the ovh-kubeconfig.yml
Setup authentication with a pure kubeconfig file
"""
print(f"Setup the OVH authentication for namespace {release}")
print(f"Setup authentication for namespace {release} with kubeconfig")

ovh_kubeconfig = os.path.join(ABSOLUTE_HERE, "secrets", f"{release}-kubeconfig.yml")
os.environ["KUBECONFIG"] = ovh_kubeconfig
print(f"Current KUBECONFIG='{ovh_kubeconfig}'")
stdout = check_output(["kubectl", "config", "use-context", cluster], dry_run)
print(stdout)
kubeconfig = os.path.join(ABSOLUTE_HERE, "secrets", f"{release}-kubeconfig.yml")
os.environ["KUBECONFIG"] = kubeconfig
print(f"Current KUBECONFIG='{kubeconfig}'")


def setup_auth_gcloud(release, cluster=None, dry_run=False):
Expand Down Expand Up @@ -442,6 +443,7 @@ def main():
"ovh",
"ovh2",
"curvenote",
"hetzner-2i2c"
],
)
argparser.add_argument(
Expand Down Expand Up @@ -511,8 +513,8 @@ def main():
# script is running on CI, proceed with auth and helm setup

if args.stage in ("all", "auth"):
if cluster.startswith("ovh"):
setup_auth_ovh(args.release, cluster, args.dry_run)
if cluster in KUBECONFIG_CLUSTERS:
setup_auth_kubeconfig(args.release, cluster, args.dry_run)
patch_coredns(args.dry_run, args.diff)
elif cluster in AZURE_RGs:
setup_auth_azure(cluster, args.dry_run)
Expand Down
Binary file added secrets/config/hetzner-2i2c.yaml
Binary file not shown.
Binary file added secrets/hetzner-2i2c.yml
Binary file not shown.

0 comments on commit ff2a59b

Please sign in to comment.