Repository: jupyterhub/zero-to-jupyterhub-k8s

Issue:
Bind proxy on IPv4 and IPv6 for dual stack support
The `configurable-http-proxy` relies on the `http` module which in turn relies on the `server` module:

https://nodejs.org/api/net.html#net_server_listen

We dont make use of the `ipv6Only` option. Therefore we can safely listen on `::` for dual stack support.


Discussion:

Resolving patch:
diff --git a/jupyterhub/files/hub/jupyterhub_config.py b/jupyterhub/files/hub/jupyterhub_config.py
--- a/jupyterhub/files/hub/jupyterhub_config.py
+++ b/jupyterhub/files/hub/jupyterhub_config.py
@@ -14,6 +14,14 @@
 
 from z2jh import get_config, set_config_if_not_none
 
+def camelCaseify(s):
+    """convert snake_case to camelCase
+
+    For the common case where some_value is set from someValue
+    so we don't have to specify the name twice.
+    """
+    return re.sub(r"_([a-z])", lambda m: m.group(1).upper(), s)
+
 # Configure JupyterHub to use the curl backend for making HTTP requests,
 # rather than the pure-python implementations. The default one starts
 # being too slow to make a large number of requests to the proxy API
@@ -22,8 +30,9 @@
 
 c.JupyterHub.spawner_class = 'kubespawner.KubeSpawner'
 
-# Connect to a proxy running in a different pod
-c.ConfigurableHTTPProxy.api_url = 'http://{}:{}'.format(os.environ['PROXY_API_SERVICE_HOST'], int(os.environ['PROXY_API_SERVICE_PORT']))
+# Connect to a proxy running in a different pod. Note that *_SERVICE_*
+# environment variables are set by Kubernetes for Services
+c.ConfigurableHTTPProxy.api_url = f"http://proxy-api:{os.environ['PROXY_API_SERVICE_PORT']}"
 c.ConfigurableHTTPProxy.should_start = False
 
 # Do not shut down user pods when hub is restarted
@@ -38,15 +47,6 @@
 }
 
 
-def camelCaseify(s):
-    """convert snake_case to camelCase
-
-    For the common case where some_value is set from someValue
-    so we don't have to specify the name twice.
-    """
-    return re.sub(r"_([a-z])", lambda m: m.group(1).upper(), s)
-
-
 # configure the hub db connection
 db_type = get_config('hub.db.type')
 if db_type == 'sqlite-pvc':
@@ -80,12 +80,15 @@ def camelCaseify(s):
 if cookie_secret_hex:
     c.JupyterHub.cookie_secret = a2b_hex(cookie_secret_hex)
 
+# hub_bind_url configures what the JupyterHub process within the hub pod's
+# container should listen to.
+hub_container_port = 8081
+c.JupyterHub.hub_bind_url = f'http://:{hub_container_port}'
 
-c.JupyterHub.ip = os.environ['PROXY_PUBLIC_SERVICE_HOST']
-c.JupyterHub.port = int(os.environ['PROXY_PUBLIC_SERVICE_PORT'])
-
-# the hub should listen on all interfaces, so the proxy can access it
-c.JupyterHub.hub_ip = '0.0.0.0'
+# hub_connect_url is the URL for connecting to the hub for use by external
+# JupyterHub services such as the proxy. Note that *_SERVICE_* environment
+# variables are set by Kubernetes for Services.
+c.JupyterHub.hub_connect_url = f"http://hub:{os.environ['HUB_SERVICE_PORT']}"
 
 # implement common labels
 # this duplicates the jupyterhub.commonLabels helper
@@ -255,12 +258,6 @@ def camelCaseify(s):
 c.KubeSpawner.volumes.extend(get_config('singleuser.storage.extraVolumes', []))
 c.KubeSpawner.volume_mounts.extend(get_config('singleuser.storage.extraVolumeMounts', []))
 
-# Gives spawned containers access to the API of the hub.
-# Note that the HUB_SERVICE_* values come from kubernetes:
-# https://kubernetes.io/docs/concepts/services-networking/service/#environment-variables
-c.JupyterHub.hub_connect_ip = os.environ['HUB_SERVICE_HOST']
-c.JupyterHub.hub_connect_port = int(os.environ['HUB_SERVICE_PORT'])
-
 # Allow switching authenticators easily
 auth_type = get_config('auth.type')
 email_domain = 'local'


Test patch: