{"id":14069580,"url":"https://github.com/sgibson91/binderhub-deploy","last_synced_at":"2025-07-30T05:32:38.476Z","repository":{"id":37965801,"uuid":"168169215","full_name":"sgibson91/binderhub-deploy","owner":"sgibson91","description":"Deploy a BinderHub from scratch on Microsoft Azure","archived":true,"fork":false,"pushed_at":"2023-03-23T13:14:42.000Z","size":3570,"stargazers_count":27,"open_issues_count":0,"forks_count":11,"subscribers_count":11,"default_branch":"main","last_synced_at":"2024-12-04T10:39:51.194Z","etag":null,"topics":["azure","binder","binderhub","cloud","docker","hut23","reproducibility","reproducible-research"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sgibson91.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-29T14:34:02.000Z","updated_at":"2023-03-23T13:15:48.000Z","dependencies_parsed_at":"2024-08-13T07:15:28.845Z","dependency_job_id":"9e9df939-5e4e-4a83-ab00-4eb50d98af46","html_url":"https://github.com/sgibson91/binderhub-deploy","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/sgibson91/binderhub-deploy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgibson91%2Fbinderhub-deploy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgibson91%2Fbinderhub-deploy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgibson91%2Fbinderhub-deploy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgibson91%2Fbinderhub-deploy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sgibson91","download_url":"https://codeload.github.com/sgibson91/binderhub-deploy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgibson91%2Fbinderhub-deploy/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267815187,"owners_count":24148356,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure","binder","binderhub","cloud","docker","hut23","reproducibility","reproducible-research"],"created_at":"2024-08-13T07:07:03.839Z","updated_at":"2025-07-30T05:32:34.795Z","avatar_url":"https://github.com/sgibson91.png","language":"Shell","funding_links":[],"categories":["Shell"],"sub_categories":[],"readme":":warning: This project is no longer maintained, and hence archived :warning:\n\n# Automatically deploy a BinderHub to Microsoft Azure\n\n[![mit_license_badge](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Build and Push Docker image](https://github.com/alan-turing-institute/binderhub-deploy/actions/workflows/docker-build.yml/badge.svg)](https://github.com/alan-turing-institute/binderhub-deploy/actions/workflows/docker-build.yml) [![Lint Dockerfile](https://github.com/alan-turing-institute/binderhub-deploy/workflows/Lint%20Dockerfile/badge.svg)](https://github.com/alan-turing-institute/binderhub-deploy/actions?query=workflow%3A%22Lint+Dockerfile%22+branch%3Amain) [![Check Setup](https://github.com/alan-turing-institute/binderhub-deploy/workflows/Check%20Setup/badge.svg)](https://github.com/alan-turing-institute/binderhub-deploy/actions?query=workflow%3A%22Check+Setup%22+branch%3Amain) [![Run shellcheck and shfmt](https://github.com/alan-turing-institute/binderhub-deploy/workflows/Run%20shellcheck%20and%20shfmt/badge.svg)](https://github.com/alan-turing-institute/binderhub-deploy/actions?query=workflow%3A%22Run+shellcheck+and+shfmt%22+branch%3Amain) [![yamllint](https://github.com/alan-turing-institute/binderhub-deploy/workflows/yamllint/badge.svg)](https://github.com/alan-turing-institute/binderhub-deploy/actions?query=workflow%3Ayamllint+branch%3Amain) [![Code of Conduct](https://img.shields.io/static/v1?label=Code%20of\u0026message=Conduct\u0026color=blueviolet)](CODE_OF_CONDUCT.md) [![Contributing Guidelines](https://img.shields.io/static/v1?label=Contributing\u0026message=Guidelines\u0026color=blueviolet)](CONTRIBUTING.md) [![good first issue](https://img.shields.io/github/labels/alan-turing-institute/binderhub-deploy/good%20first%20issue)](https://github.com/alan-turing-institute/binderhub-deploy/labels/good%20first%20issue) [![GitHub labels](https://img.shields.io/github/labels/alan-turing-institute/binderhub-deploy/help%20wanted)](https://github.com/alan-turing-institute/binderhub-deploy/labels/help%20wanted)\u003c!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --\u003e\n[![All Contributors](https://img.shields.io/badge/all_contributors-8-orange.svg?style=flat-square)](#contributors-)\n\u003c!-- ALL-CONTRIBUTORS-BADGE:END --\u003e\n\n[BinderHub](https://binderhub.readthedocs.io/en/latest/index.html) is a cloud-based, multi-server technology used for hosting repoducible computing environments and interactive Jupyter Notebooks built from code repositories.\n\nThis repository contains a set of scripts to automatically deploy a BinderHub onto [Microsoft Azure](https://azure.microsoft.com/en-gb/), and connect either a [Docker Hub](https://hub.docker.com/) account/organisation or an [Azure Container Registry](https://azure.microsoft.com/en-gb/services/container-registry/), so that you can host your own [Binder](https://mybinder.readthedocs.io/en/latest/) service.\n\nYou will require a Microsoft Azure account and subscription.\nA Free Trial subscription can be obtained [here](https://azure.microsoft.com/en-gb/free/).\nYou will be asked to provide a credit card for verification purposes.\n**You will not be charged.**\nYour resources will be frozen once your subscription expires, then deleted if you do not reactivate your account within a given time period.\nIf you are building a BinderHub as a service for an organisation, your institution may already have an Azure account.\nYou should contact your IT Services for further information regarding permissions and access (see the [Service Principal Creation](#sparkles-service-principal-creation) section below).\n\nPlease read our :purple_heart: [Code of Conduct](CODE_OF_CONDUCT.md) :purple_heart: and :space_invader: [Contributing Guidelines](CONTRIBUTING.md) :space_invader:\n\n**Table of Contents:**\n\n- [:children_crossing: Usage](#children_crossing-usage)\n  - [:package: Choosing between Docker Hub and Azure Container Registry](#package-choosing-between-docker-hub-and-azure-container-registry)\n  - [:closed_lock_with_key: Enabling HTTPS for a Domain Name](#closed_lock_with_key-enabling-https-for-a-domain-name)\n  - [:vertical_traffic_light: `setup.sh`](#vertical_traffic_light-setupsh)\n  - [:rocket: `deploy.sh`](#rocket-deploysh)\n  - [:inbox_tray: `set-a-records.sh`](inbox_tray-set-a-recordssh)\n  - [:bar_chart: `logs.sh`](#bar_chart-logssh)\n  - [:information_source: `info.sh`](#information_source-infosh)\n  - [:arrow_up: `upgrade.sh`](#arrow_up-upgradesh)\n  - [:boom: `teardown.sh`](#boom-teardownsh)\n- [:rocket: \"Deploy to Azure\" Button](#rocket-deploy-to-azure-button)\n  - [:sparkles: Service Principal Creation](#sparkles-service-principal-creation)\n  - [:chart_with_upwards_trend: Monitoring Deployment Progress](#chart_with_upwards_trend-monitoring-deployment-progress)\n  - [:package: Retrieving Deployment Output from Azure](#package-retrieving-deployment-output-from-azure)\n  - [:unlock: Accessing your BinderHub after Deployment](#unlock-accessing-your-binderhub-after-deployment)\n- [:house_with_garden: Running the Container Locally](#house_with_garden-running-the-container-locally)\n- [:art: Customising your BinderHub Deployment](#art-customising-your-binderhub-deployment)\n- [:computer: Developers Guide](#computer-developers-guide)\n  - [:wrench: Building the Docker image for testing](#wrench-building-the-docker-image-for-testing)\n  - [:label: Tagging a Release](#label-tagging-a-release)\n- [:purple_heart: Contributors](#purple_heart-contributors)\n\n---\n\n## :children_crossing: Usage\n\nThis repo can either be run locally or as \"Platform as a Service\" through the \"Deploy to Azure\" button in the [\"Deploy to Azure\" Button](#rocket-deploy-to-azure-button) section.\n\nTo use these scripts locally, clone this repo and change into the directory.\n\n```bash\ngit clone https://github.com/alan-turing-institute/binderhub-deploy.git\ncd binderhub-deploy\n```\n\nTo make the scripts executable and then run them, do the following:\n\n```bash\ncd src\nchmod 700 \u003cscript-name\u003e.sh\n./\u003cscript-name\u003e.sh\n```\n\n[**NOTE:** The above command is UNIX specific. If you are running Windows 10, [this blog post](https://www.windowscentral.com/how-install-bash-shell-command-line-windows-10) discusses using a bash shell in Windows.]\n\nTo build the BinderHub, you should run `setup.sh` first (to install the required command line tools), then `deploy.sh` (which will build the BinderHub).\nOnce the BinderHub is deployed, you can run `logs.sh` and `info.sh` to get the JupyterHub logs and IP addresses respectively.\n`teardown.sh` should _only_ be used to delete your BinderHub deployment.\n\nYou need to create a file called `config.json` which has the format described in the code block below.\nFill the quotation marks with your desired namespaces, etc.\n`config.json` is git-ignored so sensitive information, such as passwords and Service Principals, cannot not be pushed to GitHub.\n\n- For a list of available data centre regions, [see here](https://azure.microsoft.com/en-gb/global-infrastructure/locations/).\n  This should be a _region_ and **not** a _location_, for example \"West Europe\" or \"Central US\".\n  These can be equivalently written as `westeurope` and `centralus`, respectively.\n- For a list of available Linux Virtual Machines, [see here](https://docs.microsoft.com/en-gb/azure/virtual-machines/linux/sizes-general).\n  This should be something like, for example `Standard_D2s_v3`.\n- The versions of the BinderHub Helm Chart can be found [here](https://jupyterhub.github.io/helm-chart/#development-releases-binderhub) and are of the form `0.2.0-\u003ccommit-hash\u003e`.\n  It is advised to select the most recent version unless you specifically require an older one.\n- If you are deploying an Azure Container Registry, find out more about the SKU tiers [here](https://docs.microsoft.com/en-gb/azure/container-registry/container-registry-skus).\n\n```json\n{\n  \"container_registry\": \"\",        // Choose Docker Hub or ACR with 'dockerhub' or 'azurecr' values, respectively.\n  \"enable_https\": \"false\",         // Choose whether to enable HTTPS with cert-manager. Boolean.\n  \"acr\": {\n    \"registry_name\": null,         // Name to give the ACR. This must be alpha-numerical and unique to Azure.\n    \"sku\": \"Basic\"                 // The SKU capacity and pricing tier for the ACR\n  },\n  \"azure\": {\n    \"subscription\": \"\",            // Azure subscription name or ID (a hex-string)\n    \"res_grp_name\": \"\",            // Azure Resource Group name\n    \"location\": \"\",                // Azure Data Centre region\n    \"node_count\": 1,               // Number of nodes to deploy. 3 is preferrable for a stable cluster, but may be liable to caps.\n    \"vm_size\": \"Standard_D2s_v3\",  // Azure virtual machine type to deploy\n    \"sp_app_id\": null,             // Azure service principal ID (optional)\n    \"sp_app_key\": null,            // Azure service principal password (optional)\n    \"sp_tenant_id\": null,          // Azure tenant ID (optional)\n    \"log_to_blob_storage\": false   // Store logs in blob storage when not running from a container\n  },\n  \"binderhub\": {\n    \"name\": \"\",                    // Name of your BinderHub\n    \"version\": \"\",                 // Helm chart version to deploy, should be 0.2.0-\u003ccommit-hash\u003e\n    \"image_prefix\": \"\"             // The prefix to preppend to Docker images (e.g. \"binder-prod\")\n  },\n  \"docker\": {\n    \"username\": null,              // Docker username (can be supplied at runtime)\n    \"password\": null,              // Docker password (can be supplied at runtime)\n    \"org\": null                    // A Docker Hub organisation to push images to (optional)\n  },\n  \"https:\": {\n    \"certmanager_version\": null,   // Version of cert-manager to install\n    \"contact_email\": null,        // Contact email for Let's Encrypt\n    \"domain_name\": null,          // Domain name to issue certificates for\n    \"nginx_version\": null         // Version on nginx-ingress to install\n  }\n}\n```\n\nYou can copy [`template-config.json`](./template-config.json) should you require.\n\n**Please note that all entries in `template-config.json` must be surrounded by double quotation marks (`\"`), with the exception of `node_count`.**\n\n#### Important for Free Trial subscriptions\n\nIf you have signed up to an Azure Free Trial subscription, you are not allowed to deploy more than 4 **cores**.\nHow many cores you deploy depends on your choice of `node_count` and `vm_size`.\n\nFor example, a `Standard_D2s_v3` machine has 2 cores.\nTherefore, setting `node_count` to 2 will deploy 4 cores and you will have reached your quota for cores on your Free Trial subscription.\n\n### :package: Choosing between Docker Hub and Azure Container Registry\n\nTo select either a Docker Hub account/organisation or an Azure Container Registry (ACR), you must set the top-level `container_registry` key in `config.json` to either `dockerhub` or `azurecr` respectively.\nThis will tell `deploy.sh` which variables and YAML templates to use.\nThen fill in the values under either the `dockerhub` or `acr` key as required.\n\nUsing a Docker Hub account/organisation has the benefit of being relatively simple to set up.\nHowever, all the BinderHub images pushed there will be publicly available.\nFor a few extra steps, deploying an ACR will allow the BinderHub images to be pushed to a private repository.\n\n#### Important Caveats when deploying an ACR\n\n**Service Principal:**\n\nIn the [Service Principal Creation](#sparkles-service-principal-creation) section, we cover how to create a Service Principal in order to deploy a BinderHub.\nWhen following these steps, the `--role` argument of `Contributor` should be replaced with `Owner`.\nThis is because the Service Principal will need the [`AcrPush`](https://docs.microsoft.com/en-gb/azure/role-based-access-control/built-in-roles#acrpush) role in order to push images to the ACR and the `Contributor` role does not have permission to create new role assignments.\n\n### :vertical_traffic_light: `setup.sh`\n\nThis script checks whether the required command line tools are already installed.\nIf any are missing, the script uses the system package manager or [`curl`](https://curl.haxx.se/docs/) to install the command line interfaces (CLIs).\nThe CLIs to be installed are:\n\n- [Microsoft Azure (`azure-cli`)](https://docs.microsoft.com/en-gb/cli/azure/install-azure-cli-linux?view=azure-cli-latest#install-or-update)\n- [Kubernetes (`kubectl`)](https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-binary-using-curl)\n- [Helm (`helm`)](https://helm.sh/docs/using_helm/#from-script)\n\nAny dependencies that are not automatically installed by these packages will also be installed.\n\n### :closed_lock_with_key: Enabling HTTPS for a Domain Name\n\nIf you have a domain name that you would like your BinderHub to be hosted at, the package can configure a [DNS Zone](https://docs.microsoft.com/en-gb/azure/dns/dns-zones-records#dns-zones) to host the records for your domain name and configure the BinderHub to use these addresses rather than raw IP addresses.\nHTTPS certificates will also be requested for the [DNS records](https://docs.microsoft.com/en-us/azure/dns/dns-zones-records#dns-records) using [`cert-manager`](https://cert-manager.io/docs/) and [Let's Encrypt](https://letsencrypt.org/).\n\n#### :hammer: Manual steps required\n\nWhile the package tries to automate as much as possible, when enabling HTTPS there are still a few steps that the user will have to do manually.\n\n1) **Delegate the domain to the name servers**\n\n   The script will return four name servers that are hosting the DNS Zone, the will be saved to the log file `name-servers.log`.\n   Your parent domain NS records need to be updated to delegate to these name servers (see the [Azure documentation](https://docs.microsoft.com/en-us/azure/dns/dns-delegate-domain-azure-dns#delegate-the-domain)).\n   How this is achieved will be different depending on your domain registrar.\n\n2) **Point the A records to the Load Balancer IP Address**\n\n   Two A records are created for the Binder page and the JupyterHub and these records need to be set to the public IP address of the cluster's load balancer.\n   The package tries to complete this step automatically but often fails, due to the long-running nature of Azure's process to update the CLI.\n   It is recommended to wait some time (overnight is best) and then run `set-a-records.sh`.\n   Alternatively, there are [manual instructions](docs/manually-setting-a-records.md) for setting the A records in the Azure Portal.\n\n3) **Switching from Let's Encrypt staging to production**\n\n   Let's Encrypt provides a [staging platform](https://letsencrypt.org/docs/staging-environment/) to test against and this is the environment the package will request certificates from.\n   Once you have [verified the staging certificates](https://www.cyberciti.biz/faq/test-ssl-certificates-diagnosis-ssl-certificate/) have been issued correctly, the user must switch to requesting certificates from Let's Encrypt's production environment to receive trusted certificates.\n   [Instructions for switching environments](docs/lets_encrypt_prod_switch.md).\n\n### :rocket: `deploy.sh`\n\nThis script reads in values from `config.json` and deploys a Kubernetes cluster.\nIt then creates `config.yaml` and `secret.yaml` files which are used to install the BinderHub using the templates in the [`templates` folder](./templates/).\n\nIf you have chosen a Docker Hub account/organisation, the script will ask for your Docker ID and password if you haven't supplied them in the config file.\nThe ID is your Docker username, **NOT** the associated email.\nIf you have provided a Docker organisation in `config.json`, then Docker ID **MUST** be a member of this organisation.\n\nIf you have chosen an ACR, the script will create one and assign the `AcrPush` role to your Service Principal.\nThe registry server and Service Principal credentials will then be parsed into `config.yaml` and `secret.yaml` so that the BinderHub can connect to the ACR.\n\nIf you have requested HTTPS to be enabled, the script will create a DNS Zone and A records for the Binder and JupyterHub endpoints.\nThe [`nginx-ingress`](https://github.com/helm/charts/tree/master/stable/nginx-ingress) and [`cert-manager`](https://github.com/jetstack/cert-manager) helm charts will also be installed to provide a load balancer and automated requests for certificates from Let's Encrypt, respectively.\n\nBoth a JupyterHub and BinderHub are installed via a Helm Chart onto the deployed Kubernetes cluster and the `config.yaml` file is updated with the JupyterHub IP address.\n\n`config.yaml` and `secret.yaml` are both git-ignored so that secrets cannot be pushed back to GitHub.\n\nThe script also outputs log files (`\u003cfile-name\u003e.log`) for each stage of the deployment.\nThese files are also git-ignored.\n\nIf the `azure.log_to_blob_storage` value in `config.json` is set to `true` the script is running from the command line, then the log files will be stored in blob storage.\n\n### :inbox_tray: `set-a-records.sh`\n\n:rotating_light: This script is only relevant if deploying a BinderHub with a domain name and HTTPS certificates :rotating_light:\n\nThis script reads in values from `config.json` and try to set the Kubernetes public IP address to the `binder` and `hub` A records in the DNS Zone.\n\n### :bar_chart: `logs.sh`\n\nThis script will print the JupyterHub logs to the terminal to assist with debugging issues with the BinderHub.\nIt reads from `config.json` in order to get the BinderHub name.\n\n### :information_source: `info.sh`\n\nThis script will print the pod status of the Kubernetes cluster and the IP addresses of both the JupyterHub and BinderHub to the terminal.\nIt reads the BinderHub name from `config.json`.\n\n### :arrow_up: `upgrade.sh`\n\nThis script will automatically upgrade the Helm Chart deployment configuring the BinderHub and then prints the Kubernetes pods.\nIt reads the BinderHub name and Helm Chart version from `config.json`.\n\n### :boom: `teardown.sh`\n\nThis script will purge the Helm Chart release, delete the Kubernetes namespace and then delete the Azure Resource Group containing the computational resources.\nIt will read the namespaces from `config.json`.\nThe user should check the [Azure Portal](https://portal.azure.com/) to verify the resources have been deleted.\nIt will also purge the cluster information from your `kubectl` configuration file.\n\n## :rocket: \"Deploy to Azure\" Button\n\nTo deploy [BinderHub](https://binderhub.readthedocs.io/) to Azure in a single click (and some form-filling), use the deploy button below.\n\n[![Deploy to Azure](https://azuredeploy.net/deploybutton.svg)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Falan-turing-institute%2Fbinderhub-deploy%2Fmain%2Fazure.deploy.json)\n\n### :sparkles: Service Principal Creation\n\nYou will be asked to provide a [Service Principal](https://docs.microsoft.com/en-gb/azure/active-directory/develop/app-objects-and-service-principals) in the form launched when you click the \"Deploy to Azure\" button above.\n\n[**NOTE:** The following instructions can also be run in a local terminal session.\nThey will require the Azure command line to be installed, so make sure to run [`setup.sh`](src/setup.sh) first.]\n\nTo create a Service Principal, go to the [Azure Portal](https://portal.azure.com/) (and login!) and open the Cloud Shell:\n\n![Open Shell in Azure](assets/open_shell_in_azure.png)\n\nYou may be asked to create storage when you open the shell.\nThis is expected, click \"Create\".\n\nMake sure the shell is set to Bash, not PowerShell.\n\n![Bash Shell](assets/bash_shell.png)\n\nSet the subscription you'd like to deploy your BinderHub on.\n\n```bash\naz account set --subscription \u003csubscription\u003e\n```\n\nThis image shows the command being executed for an \"Azure Pass - Sponsorship\" subscription.\n\n![Set Subscription](assets/set_subscription.png)\n\nYou will need the subscription ID, which you can retrieve by running:\n\n```bash\naz account list --refresh --output table\n```\n\n![List Subscriptions](assets/az_account_list.png)\n\nNext, create the Service Principal with the following command.\nMake sure to give it a sensible name!\n\n```bash\naz ad sp create-for-rbac \\\n    --name binderhub-sp \\\n    --role Contributor \\\n    --scope /subscriptions/\u003csubscription ID from above\u003e\n```\n\n**NOTE:** If you are deploying an ACR rather than connecting to Docker Hub, then this command should be:\n\n```bash\naz ad sp create-for-rbac \\\n    --name binder\\\n    --scope /subscriptions/\u003csubscription ID from above\u003e\n```\n\n![Create Service Principal](assets/create-for-rbac.png)\n\nThe fields `appId`, `password` and `tenant` are the required pieces of information.\nThese should be copied into the \"Service Principal App ID\", \"Service Principal App Key\" and \"Service Principal Tenant ID\" fields in the form, respectively.\n\n**Keep this information safe as the password cannot be recovered after this step!**\n\n### :chart_with_upwards_trend: Monitoring Deployment Progress\n\nTo monitor the progress of the blue-button deployment, go to the [Azure portal](https://portal.azure.com/) and select \"Resource Groups\" from the left hand pane.\nThen in the central pane select the resource group you chose to deploy into.\n\n![Select Resource Group](assets/select_resource_group.png)\n\nThis will give you a right hand pane containing the resources within the group.\nYou may need to \"refresh\" until you see a new container instance.\n\n![Select Container Instance](assets/select_container_instance.png)\n\nWhen it appears, select it and then in the new pane go to \"Settings-\u003eContainers\".\nYou should see your new container listed.\n\n![Container Events](assets/container_events.png)\n\nSelect it, then in the lower right hand pane select \"Logs\".\nYou may need to \"refresh\" this to display the logs until the container starts up.\nThe logs are also not auto-updating, so keep refreshing them to see progress.\n\n![Container Logs](assets/container_logs.png)\n\n### :package: Retrieving Deployment Output from Azure\n\nWhen BinderHub is deployed using the \"Deploy to Azure\" button (or with a local container), output logs, YAML files, and ssh keys are pushed to an Azure storage account to preserve them once the container exits.\nThe storage account is created in the same resource group as the Kubernetes cluster, and files are pushed into a storage blob within the account.\n\nBoth the storage blob name and the storage account name are derived from the name you gave to your BinderHub instance, but may be modified and/or have a random seed appended.\nTo find the storage account name, navigate to your resource group by selecting \"Resource Groups\" in the left-most panel of the [Azure Portal](https://portal.azure.com/), then clicking on the resource group containing your BinderHub instance.\nAlong with any pre-existing resources (for example, if you re-used an existing resource group), you should see three new resources: a container instance, a Kubernetes service, and a storage account.\nMake a note of the name of the storage account (referred to in the following commands as `ACCOUNT_NAME`) then select this storage account.\n\n![Storage Account](assets/storage_account.png)\n\nIn the new pane that opens, select \"Blobs\" from the \"Services\" section.\nYou should see a single blob listed.\nMake a note of the name of this blob, which will be `BLOB_NAME` in the following commands.\n\n![Blob Storage](assets/blob_storage.png)\n\n![Select Blob Storage](assets/select_blob_storage.png)\n\nThe Azure CLI can be used to fetch files from the blob (either in the cloud shell in the [Azure Portal](https://portal.azure.com), or in a local terminal session if you've run [`setup.sh`](.setup.sh) first).\nFiles are fetched into a local directory, **which must already exist**, referred to as `OUTPUT_DIRECTORY` in the following commands.\n\nYou can run [`setup.sh`](src/setup.sh) to install the Azure CLI or use the cloud shell on the [Azure Portal](https://portal.azure.com).\n\nTo fetch all files:\n\n```bash\naz storage blob download-batch \\\n    --account-name \u003cACCOUNT_NAME\u003e \\\n    --source \u003cBLOB_NAME\u003e \\\n    --pattern \"*\" \\\n    --destination \"\u003cOUTPUT_DIRECTORY\u003e\"\n```\n\nThe `--pattern` argument can be used to fetch particular files, for example all log files:\n\n```bash\naz storage blob download-batch \\\n    --account-name \u003cACCOUNT_NAME\u003e \\\n    --source \u003cBLOB_NAME\u003e \\\n    --pattern \"*.log\" \\\n    --destination \"\u003cOUTPUT_DIRECTORY\u003e\"\n```\n\nTo fetch a single file, specify `REMOTE_FILENAME` for the name of the file in blob storage, and `LOCAL_FILENAME` for the filename it will be fetched into:\n\n```bash\naz storage blob download \\\n    --account-name \u003cACCOUNT_NAME\u003e \\\n    --container-name \u003cBLOB_NAME\u003e \\\n    --name \u003cREMOTE_FILENAME\u003e \\\n    --file \u003cLOCAL_FILENAME\u003e\n```\n\nFor full documentation, see the [`az storage blob` documentation](https://docs.microsoft.com/en-gb/cli/azure/storage/blob?view=azure-cli-latest).\n\n### :unlock: Accessing your BinderHub after Deployment\n\nOnce the deployment has succeeded and you've downloaded the log files, visit the IP address of your Binder page to test it's working.\n\nThe Binder IP address can be found by running the following:\n\n```bash\ncat \u003cOUTPUT_DIRECTORY\u003e/binder-ip.log\n```\n\nA good repository to test your BinderHub with is [binder-examples/requirements](https://github.com/binder-examples/requirements)\n\n## :house_with_garden: Running the Container Locally\n\nThe third way to deploy BinderHub to Azure would be to pull the Docker image and run it directly, parsing the values you would have entered in `config.json` as environment variables.\n\nYou will need the Docker CLI installed.\nInstallation instructions can be found [here](https://docs.docker.com/v17.12/install/).\n\nFirst, pull the `binderhub-setup` image.\n\n```bash\ndocker pull sgibson91/binderhub-setup:\u003cTAG\u003e\n```\n\nwhere `\u003cTAG\u003e` is your chosen image tag.\n\nA list of availabe tags can be found [here](https://cloud.docker.com/repository/docker/sgibson91/binderhub-setup/tags).\nIt is recommended to use the most recent version number.\nThe `latest` tag is the most recent build from the default branch and may be subject fluctuations.\n\nThen, run the container with the following arguments, replacing the `\u003c\u003e` fields as necessary:\n\n```bash\ndocker run \\\n-e \"AKS_NODE_COUNT=1\" \\  # Required\n-e \"AKS_NODE_VM_SIZE=Standard_D2s_v3\" \\  # Required\n-e \"AZURE_SUBSCRIPTION=\u003cAzure Subscription ID\u003e\" \\  # Required\n-e \"BINDERHUB_CONTAINER_MODE=true\" \\  # Required\n-e \"BINDERHUB_NAME=\u003cChosen BinderHub name\u003e\" \\  # Required\n-e \"BINDERHUB_VERSION=\u003cChosen BinderHub version\u003e\" \\  # Required\n-e \"CONTAINER_REGISTRY=\u003cdockerhub or azurecr\u003e\" \\  # Required\n-e \"DOCKER_IMAGE_PREFIX=binder-dev\" \\  # Required\n-e \"DOCKERHUB_ORGANISATION=\u003cDocker organisation\u003e\" \\\n-e \"DOCKERHUB_PASSWORD=\u003cDocker password\u003e\" \\\n-e \"DOCKERHUB_USERNAME=\u003cDocker ID\u003e\" \\\n-e \"REGISTRY_NAME=\u003cRegistry Name\u003e\" \\\n-e \"REGISTRY_SKU=Basic\" \\\n-e \"RESOURCE_GROUP_LOCATION=westeurope\" \\  # Required\n-e \"RESOURCE_GROUP_NAME=\u003cChosen Resource Group name\u003e\" \\  # Required\n-e \"SP_APP_ID=\u003cService Principal ID\u003e\" \\  # Required\n-e \"SP_APP_KEY=\u003cService Principal Key\u003e\" \\  # Required\n-e \"SP_TENANT_ID=\u003cService Principal Tenant ID\u003e\" \\  # Required\n-it sgibson91/binderhub-setup:\u003cTAG\u003e\n```\n\nThe output will be printed to your terminal and the files will be pushed to blob storage, as in the button deployment.\nSee the [Retrieving Deployment Output from Azure](#package-retrieving-deployment-output-from-azure) section for how to return these files.\n\n## :art: Customising your BinderHub Deployment\n\nCustomising your BinderHub deployment is as simple as editing `config.yaml` and/or `secret.yaml` and then upgrading the BinderHub Helm Chart.\nThe Helm Chart can be upgraded by running [`upgrade.sh`](src/upgrade.sh) (make sure you have the CLIs installed by running [`setup.sh`](src/setup.sh) first).\n\nThe Jupyter guide to customising the underlying JupyterHub can be found [here](https://zero-to-jupyterhub.readthedocs.io/en/latest/extending-jupyterhub.html).\n\nThe BinderHub guide for changing the landing page logo can be found [here](https://binderhub.readthedocs.io/en/latest/customizing.html#template-customization).\n\n## :computer: Developers Guide\n\n### :wrench: Building the Docker image for testing\n\nThe Docker image will automatically be built by Docker Hub when new pushes are made to `main`.\nHowever, a developer may wish to build the image to test deployments before merging code.\n\nFirstly, make sure `config.json` has been removed from the repository.\nOtherwise, secrets within the file may be built into the image.\n\nThe command to build a Docker image from the root of the repo is as follows.\n\n```bash\ndocker build -t \u003cDOCKER_USERNAME\u003e/binderhub-setup:\u003cTAG\u003e .\n```\n\nIt is not necessary to push this image to a container registry.\nBut if you choose to do so, the command is as follows.\n\n```bash\ndocker push \u003cREGISTRY-HOST\u003e/\u003cDOCKER-USERNAME\u003e/binderhub-setup:\u003cTAG\u003e\n```\n\n### :label: Tagging a Release\n\nDocker Hub will automatically build the image from the repo with every push to `main` and tag this as `latest`.\n\nTo release a specific version, update the [Azure ARM template](https://github.com/alan-turing-institute/binderhub-deploy/blob/main/azure.deploy.json) with the new/desired version on line [166](https://github.com/alan-turing-institute/binderhub-deploy/blob/main/azure.deploy.json#L166) and the block starting at line [170](https://github.com/alan-turing-institute/binderhub-deploy/blob/main/azure.deploy.json#L170).\nWe follow [SemVer](https://semver.org/) versioning format.\n\nOnce the Pull Request containing the new code/version/release has been merged, run the following commands, where `vX.Y.Z` is the new/desired version release.\n\n```bash\ngit checkout main\ngit pull\ngit tag -a vX.Y.Z  # For an annotated tag\ngit tag -m vX.Y.Z  # For a lightweight tag\ngit tag vX.Y.Z     # For a tag with no extra data\ngit push --tags\n```\n\nThis will trigger Docker Hub to build an image with the SemVer version as a tag.\n\nSee the following documentation for information on tagging:\n\n- \u003chttps://git-scm.com/book/en/v2/Git-Basics-Tagging\u003e\n- \u003chttps://dev.to/neshaz/a-tutorial-for-tagging-releases-in-git-147e\u003e\n\n## :purple_heart: Contributors\n\nPlease read our :purple_heart: [Code of Conduct](CODE_OF_CONDUCT.md) :purple_heart: and :space_invader: [Contributing Guidelines](CONTRIBUTING.md) :space_invader: to get you started!\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://www.imperial.ac.uk/admin-services/ict/self-service/research-support/rcs/research-software-engineering/\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/6095790?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDiego\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/issues?q=author%3Adalonsoa\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"#ideas-dalonsoa\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/pulls?q=is%3Apr+reviewed-by%3Adalonsoa\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://uk.linkedin.com/in/gerardgorman\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/5394691?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eGerard Gorman\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#ideas-ggorman\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/pulls?q=is%3Apr+reviewed-by%3Aggorman\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/jemrobinson\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/3502751?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJames Robinson\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/commits?author=jemrobinson\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://oneframelink.com\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/561862?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eNicholas Paldino\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/commits?author=casperOne\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://sgibson91.github.io/\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/44771837?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSarah Gibson\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/issues?q=author%3Asgibson91\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/commits?author=sgibson91\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/commits?author=sgibson91\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#ideas-sgibson91\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#infra-sgibson91\" title=\"Infrastructure (Hosting, Build-Tools, etc)\"\u003e🚇\u003c/a\u003e \u003ca href=\"#maintenance-sgibson91\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"#platform-sgibson91\" title=\"Packaging/porting to new platform\"\u003e📦\u003c/a\u003e \u003ca href=\"#projectManagement-sgibson91\" title=\"Project Management\"\u003e📆\u003c/a\u003e \u003ca href=\"#question-sgibson91\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e \u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/pulls?q=is%3Apr+reviewed-by%3Asgibson91\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e \u003ca href=\"#tool-sgibson91\" title=\"Tools\"\u003e🔧\u003c/a\u003e \u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/commits?author=sgibson91\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://www.flickr.com/photos/manicstreetpreacher/\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/1644105?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSimon Li\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/issues?q=author%3Amanics\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://trallard.dev\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/23552331?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eTania Allard\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/issues?q=author%3Atrallard\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/commits?author=trallard\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#ideas-trallard\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#tutorial-trallard\" title=\"Tutorials\"\u003e✅\u003c/a\u003e \u003ca href=\"#question-trallard\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://www.imperial.ac.uk/people/tim.greaves\"\u003e\u003cimg src=\"https://avatars2.githubusercontent.com/u/7603619?v=4\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eTim Greaves\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/issues?q=author%3Atmbgreaves\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/alan-turing-institute/binderhub-deploy/commits?author=tmbgreaves\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#ideas-tmbgreaves\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#infra-tmbgreaves\" title=\"Infrastructure (Hosting, Build-Tools, etc)\"\u003e🚇\u003c/a\u003e \u003ca href=\"#platform-tmbgreaves\" title=\"Packaging/porting to new platform\"\u003e📦\u003c/a\u003e \u003ca href=\"#tool-tmbgreaves\" title=\"Tools\"\u003e🔧\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-enable --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgibson91%2Fbinderhub-deploy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsgibson91%2Fbinderhub-deploy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgibson91%2Fbinderhub-deploy/lists"}