diff --git a/config/localhost.yaml b/config/localhost.yaml new file mode 100644 index 000000000..3e9c74e1c --- /dev/null +++ b/config/localhost.yaml @@ -0,0 +1,53 @@ +# 127.0.0.1.nip.io will not work because when pods try to use it, +# the domain will resolve to the pod itself. +# The deploy.py overwrite the 127.0.0.1 to the user IP address. +binderhub: + config: + BinderHub: + # Use Kubernetes DNS + hub_url: http://jupyterhub.127.0.0.1.nip.io + use_registry: false + + extraConfig: + # Disable send events to StackDriver on Google Cloud + 01-eventlog: + + registry: + username: "your-username" + # This is unsafe! Only se for local development + password: "your-password" + + ingress: + https: + # This is unsafe! Only se for local development + enabled: false + hosts: + - 127.0.0.1.nip.io + + jupyterhub: + ingress: + hosts: + - jupyterhub.127.0.0.1.nip.io + +static: + ingress: + tls: + # This is unsafe! Only se for local development + enabled: false + hosts: + - static.127.0.0.1.nip.io + +analyticsPublisher: + enabled: false + +prometheus: + enabled: false + +grafana: + enabled: false + +cryptnono: + enabled: false + +cluster-autoscaler: + enabled: false diff --git a/deploy.py b/deploy.py index 889e68877..4c6fa2788 100755 --- a/deploy.py +++ b/deploy.py @@ -198,7 +198,7 @@ def get_config_files(release, config_dir="config"): return config_files -def deploy(release, name=None, dry_run=False, diff=False): +def deploy(release, name=None, dry_run=False, diff=False, ip_address=None): """Deploys a federation member to a k8s cluster. Waits for deployments and daemonsets to become Ready @@ -238,6 +238,20 @@ def deploy(release, name=None, dry_run=False, diff=False): for config_file in config_files: helm.extend(["-f", config_file]) + if release == "localhost": + helm.extend( + [ + "--set", + f"binderhub.config.BinderHub.hub_url=http://jupyterhub.{ip_address}.nip.io", + "--set", + f"binderhub.ingress.hosts={{{ip_address}.nip.io}}", + "--set", + f"binderhub.jupyterhub.ingress.hosts={{jupyterhub.{ip_address}.nip.io}}", + "--set", + f"static.ingress.hosts={{static.{ip_address}.nip.io}}", + ] + ) + check_call(helm, dry_run) print( BOLD + GREEN + f"SUCCESS: Helm {helm_commands[0]} for {release} completed" + NC, @@ -437,6 +451,7 @@ def main(): "release", help="Release to deploy", choices=[ + "localhost", "staging", "prod", "ovh", @@ -459,6 +474,10 @@ def main(): action="store_true", help="If the script is running locally, skip auth step", ) + argparser.add_argument( + "--local-ip", + help="IP address of the local machine", + ) argparser.add_argument( "--dry-run", action="store_true", @@ -479,6 +498,12 @@ def main(): args = argparser.parse_args() + if args.release == "localhost": + args.local = True + + if args.local_ip is None: + raise ValueError("Cluster localhost requires IP address.") + # if one argument given make cluster == release cluster = args.cluster or args.release @@ -520,6 +545,8 @@ def main(): setup_auth_gcloud(args.release, cluster, args.dry_run) elif cluster in AWS_DEPLOYMENTS: setup_auth_aws(cluster, args.dry_run) + elif cluster == "localhost": + pass else: raise Exception("Cloud cluster not recognised!") @@ -530,7 +557,7 @@ def main(): if args.stage in ("all", "certmanager"): setup_certmanager(args.dry_run, args.diff) if args.stage in ("all", "mybinder"): - deploy(args.release, args.name, args.dry_run, args.diff) + deploy(args.release, args.name, args.dry_run, args.diff, args.local_ip) if __name__ == "__main__": diff --git a/docs/source/getting_started/index.rst b/docs/source/getting_started/index.rst index f61b55744..10f32ec82 100644 --- a/docs/source/getting_started/index.rst +++ b/docs/source/getting_started/index.rst @@ -9,6 +9,7 @@ permissions, as well as contextual information about the mybinder.org deployment .. toctree:: :maxdepth: 3 + local_environment getting_started production_environment terminology diff --git a/docs/source/getting_started/local_environment.md b/docs/source/getting_started/local_environment.md new file mode 100644 index 000000000..cb9c7c369 --- /dev/null +++ b/docs/source/getting_started/local_environment.md @@ -0,0 +1,73 @@ +# Getting started with local development + +This page contains a starting point for people who want to know more about the BinderHub deployment by playing around with a local development instance. + +## Local Kubernetes + +You will need a local Kubernetes cluster. A few options are + +- [Kubernetes with Docker Desktop](https://docs.docker.com/desktop/features/kubernetes/) (recommended) +- [minikube](https://minikube.sigs.k8s.io/docs/) +- [k3d](https://k3d.io/stable/) +- [kind](https://kind.sigs.k8s.io/) + +### Install Docker Desktop + +Install Docker Desktop on [Mac](https://docs.docker.com/desktop/setup/install/mac-install/), [Windows](https://docs.docker.com/desktop/setup/install/windows-install/), or [Linux](https://docs.docker.com/desktop/setup/install/linux/). And [turn on Kubernetes](https://docs.docker.com/desktop/features/kubernetes/#install-and-turn-on-kubernetes). + +## Set up `kubectl` to connect to Kubernetes + +Once you have `kubectl` installed, you can connect it with your local Kubernetes. +To do so, run the following command: + +``` +kubectl config use-context k8s-context-name +``` + +If using Docker Desktop, `k8s-context-name` is `docker-desktop`. + +You can test this out by running: + +``` +kubectl get -A pods +``` + +and a list of all running pods should be printed. + +## Deploy Harbor to Kubernetes + +Run the following command: + +``` +helm repo add harbor https://helm.goharbor.io +``` + +``` +helm install harbor harbor/harbor +``` + +## Deploy mybinder.org to Kubernetes + +Run the following command: + +``` +source cert-manager.env +``` + +``` +for d in ./mybinder*/; do + helm dependency update "$d" +done +``` + +``` +chartpress --skip-build +``` + +``` +python deploy.py localhost +``` + +## Access your mybinder.org + +Open http://localhost with your favourite web browser. diff --git a/mybinder/templates/static/ingress.yaml b/mybinder/templates/static/ingress.yaml index fd6126fd8..b7dfba8c4 100644 --- a/mybinder/templates/static/ingress.yaml +++ b/mybinder/templates/static/ingress.yaml @@ -30,9 +30,11 @@ spec: port: number: 80 {{- end }} + {{- if .Values.static.ingress.tls.enabled }} tls: - secretName: {{ .Values.static.ingress.tls.secretName }} hosts: {{- range $host := .Values.static.ingress.hosts }} - {{ $host }} {{- end }} + {{- end }} diff --git a/mybinder/values.yaml b/mybinder/values.yaml index b5e14e1d7..2008b0a22 100644 --- a/mybinder/values.yaml +++ b/mybinder/values.yaml @@ -528,6 +528,7 @@ static: kubernetes.io/ingress.class: nginx kubernetes.io/tls-acme: "true" tls: + enabled: true secretName: kubelego-tls-static # values ref: https://github.com/grafana/helm-charts/blob/main/charts/grafana/values.yaml