{"id":43800157,"url":"https://github.com/mxab/jupyterhub-nomad-spawner","last_synced_at":"2026-02-05T21:33:55.261Z","repository":{"id":47374561,"uuid":"491283619","full_name":"mxab/jupyterhub-nomad-spawner","owner":"mxab","description":null,"archived":false,"fork":false,"pushed_at":"2025-02-14T11:12:53.000Z","size":244,"stargazers_count":21,"open_issues_count":1,"forks_count":8,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-02-14T12:23:55.025Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mxab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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":"2022-05-11T21:57:52.000Z","updated_at":"2025-02-14T11:10:27.000Z","dependencies_parsed_at":"2024-02-29T19:49:39.270Z","dependency_job_id":"3ea0e9d4-dc5d-4d33-90c7-67cb742991cb","html_url":"https://github.com/mxab/jupyterhub-nomad-spawner","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/mxab/jupyterhub-nomad-spawner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxab%2Fjupyterhub-nomad-spawner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxab%2Fjupyterhub-nomad-spawner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxab%2Fjupyterhub-nomad-spawner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxab%2Fjupyterhub-nomad-spawner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mxab","download_url":"https://codeload.github.com/mxab/jupyterhub-nomad-spawner/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mxab%2Fjupyterhub-nomad-spawner/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29135047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T20:50:26.975Z","status":"ssl_error","status_checked_at":"2026-02-05T20:49:26.082Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2026-02-05T21:33:55.155Z","updated_at":"2026-02-05T21:33:55.233Z","avatar_url":"https://github.com/mxab.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Nomad Jupyter Spawner\n\n\u003e [!WARNING]\n\u003e This project is currently in beta\n\nA Jupyterhub plugin to spawn single-user notebook servers via [Nomad](https://www.nomadproject.io/). The project provides templates to allow users to influence how their servers are spawned (see the [showcase](#-show-case) and [recipes](#-recipes) for more details.).\n\nAfter login users can select an image, resources and connect it with volumes (csi / host)\n\n```sh\npip install jupyterhub-nomad-spawner\n```\n\n## Show Case\n\nhttps://user-images.githubusercontent.com/1607547/182332760-b0f96ba2-faa8-47b6-9bd7-db93b8d31356.mp4\n\nTODOs:\n\n- Document setup\n- Namespace support\n\n## Usage\n\n### Jupyterhub Configuration\n\n```python\n\nimport os\n\nfrom jupyterhub.auth import DummyAuthenticator\n\nc.JupyterHub.spawner_class = \"nomad-spawner\"\nc.JupyterHub.bind_url = \"http://0.0.0.0:8000\"\nc.JupyterHub.hub_bind_url = \"http://0.0.0.0:8081\"\n\nc.JupyterHub.hub_connect_url = (\n    f\"http://{os.environ.get('NOMAD_IP_api')}:{os.environ.get('NOMAD_HOST_PORT_api')}\"\n)\nc.JupyterHub.log_level = \"DEBUG\"\nc.ConfigurableHTTPProxy.debug = True\n\n\nc.JupyterHub.allow_named_servers = True\nc.JupyterHub.named_server_limit_per_user = 5\n\nc.JupyterHub.authenticator_class = DummyAuthenticator\n\nc.NomadSpawner.datacenters = [\"dc1\", \"dc2\", \"dc3\"]\nc.NomadSpawner.csi_plugin_ids = [\"nfs\", \"hostpath-plugin0\"]\nc.NomadSpawner.mem_limit = \"2G\"\n\nc.NomadSpawner.common_images = [\"jupyter/minimal-notebook:2023-06-26\"]\n\n\ndef csi_volume_parameters(spawner):\n    if spawner.user_options[\"volume_csi_plugin_id\"] == \"nfs\":\n        return {\"gid\": \"1000\", \"uid\": \"1000\"}\n    else:\n        return None\n\n\nc.NomadSpawner.csi_volume_parameters = csi_volume_parameters\n\n```\n\n### Nomad Job\n\n```hcl\n\njob \"jupyterhub\" {\n    type = \"service\"\n\n    datacenters = [\"dc1\"]\n\n    group \"jupyterhub\" {\n\n        network {\n            mode = \"host\"\n            port \"hub\" {\n                to = 8000\n                static = 8000\n            }\n            port \"api\" {\n                to = 8081\n            }\n        }\n        task \"jupyterhub\" {\n            driver = \"docker\"\n\n            config {\n                image = \"mxab/jupyterhub:1\"\n                auth_soft_fail = false\n\n                args = [\n                        \"jupyterhub\",\n                        \"-f\",\n                        \"/local/jupyterhub_config.py\",\n                    ]\n                ports = [\"hub\", \"api\"]\n\n            }\n            template {\n                destination = \"/local/nomad.env\"\n                env = true\n                data = \u003c\u003cEOF\n\nNOMAD_ADDR=http://host.docker.internal:4646\nCONSUL_HTTP_ADDR=http://host.docker.internal:8500\n    EOF\n            }\n            template {\n                destination = \"/local/jupyterhub_config.py\"\n\n                data = \u003c\u003cEOF\nimport os\n\nfrom jupyterhub.auth import DummyAuthenticator\n\nc.JupyterHub.spawner_class = \"nomad-spawner\"\nc.JupyterHub.bind_url = \"http://0.0.0.0:8000\"\nc.JupyterHub.hub_bind_url = \"http://0.0.0.0:8081\"\n\nc.JupyterHub.hub_connect_url = (\n    f\"http://{os.environ.get('NOMAD_IP_api')}:{os.environ.get('NOMAD_HOST_PORT_api')}\"\n)\nc.JupyterHub.log_level = \"DEBUG\"\nc.ConfigurableHTTPProxy.debug = True\n\n\nc.JupyterHub.allow_named_servers = True\nc.JupyterHub.named_server_limit_per_user = 5\n\nc.JupyterHub.authenticator_class = DummyAuthenticator\n\nc.NomadSpawner.datacenters = [\"dc1\", \"dc2\", \"dc3\"]\nc.NomadSpawner.csi_plugin_ids = [\"nfs\", \"hostpath-plugin0\"]\nc.NomadSpawner.mem_limit = \"2G\"\n\nc.NomadSpawner.common_images = [\"jupyter/minimal-notebook:2023-06-26\"]\n\n\ndef csi_volume_parameters(spawner):\n    if spawner.user_options[\"volume_csi_plugin_id\"] == \"nfs\":\n        return {\"gid\": \"1000\", \"uid\": \"1000\"}\n    else:\n        return None\n\n\nc.NomadSpawner.csi_volume_parameters = csi_volume_parameters\n\n                EOF\n\n\n            }\n\n            resources {\n                memory = \"512\"\n            }\n\n        }\n\n        service {\n            name = \"jupyter-hub\"\n            port = \"hub\"\n\n            check {\n                type     = \"tcp\"\n                interval = \"10s\"\n                timeout  = \"2s\"\n            }\n\n        }\n        service {\n            name = \"jupyter-hub-api\"\n            port = \"api\"\n            check {\n                type     = \"tcp\"\n                interval = \"10s\"\n                timeout  = \"2s\"\n            }\n\n        }\n    }\n}\n\n\n```\n\n## Recipes\n\nBy default the `jupyterhub-nomad-spawner` allows users to customize the notebook servers image, the datacenters to spawn in, as well as the memory and volume type for the allocation. While these options are sufficient in most cases, `jupyterhub` operators may wish to customize the spawner's behavior and/or restrict the notebook users customization.\n\n- using a custom job spec\n\n  ```python\n  # must be available to your hub server\n  c.NomadSpawner.job_template_path = \"/etc/jupyterhub/custom-job-template.hcl.j2\"\n\n  ```\n\n- disabling user options\n\n  ```python\n  # skips the options dialogue, which is used to populate `NomadSpawner.user_options`\n  # therefore you would also have to overwrite the default `job_factory``\n  c.NomadSpawner.options_form = \"\"\n  ```\n\n- using a custom job factory\n\n  ```python\n  from jupyterhub_nomad_spawner.spawner import NomadSpawner\n  from jupyterhub_nomad_spawner.job_factory import (\n    JobData,\n    create_job,\n    )\n\n\n  class CustomNomadSpawner(NomadSpawner):\n    async def job_factory(self, _) -\u003e str:\n        return create_job(\n            job_data=JobData(\n                job_name=self.job_name,\n                username=self.user.name,\n                notebook_name=self.name,\n                service_provider=self.service_provider,\n                service_name=self.service_name,\n                env=self.get_env(),\n                args=self.get_args(),\n                image=\"jupyter/minimal-notebook\",\n                datacenters=[\"dc1\", \"dc2\"],\n                cpu=500,\n                memory=512,\n            ),\n            job_template_path=self.job_template_path,\n        )\n\n    c.JupyterHub.spawner_class = CustomNomadSpawner\n  ```\n\n- customizing server naming\n\n  ```python\n  c.NomadSpawner.base_job_name = \"jupyter\"   # used as prefix\n  c.NomadSpawner.name_template = \"{{prefix}}-{{username}}\"\n  ```\n\n\u003e [!NOTE]\n\u003e Please be aware that if you have enabled named servers, the template should contain the {{notebookid}}.\n\n###\n\n## Development\n\n### Setup\n\nGet poetry: https://python-poetry.org/docs/#installation\n\n```sh\npoetry install\n```\n\n### Release\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmxab%2Fjupyterhub-nomad-spawner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmxab%2Fjupyterhub-nomad-spawner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmxab%2Fjupyterhub-nomad-spawner/lists"}