Update allowed images without restarting JupyterHub

Hello,

Is there a way to update allowed_images in jupyterhub_config.py without restarting Docker container running JupyterHub?

I had two ideas:

  • I can make this work maybe with setting remove=False and not removing user servers, but this answer says that it is not a good practice.
  • to add allowed_images=”*”, but the problem is that service tries to pull jupyterhub/singleuser image into my air-gapped machine without internet access

Is there a better way ?

Thanks!

allowed_images can be a callable

Which means you can make it a function that dynamically returns the list of images in any way you want.

1 Like

Thank you @manics !

Here is function that works for my case if anyone needs it:

def dynamic_allowed_images(spawner):
    """Return a list of available Docker image tags.

    Optionally filter by prefix via env var `ALLOWED_IMAGE_PREFIX`.
    Raises RuntimeError if no images match or discovery fails.
    """
    try:
        client = docker.from_env()
        prefix = os.environ.get("ALLOWED_IMAGE_PREFIX", "")

        tags = []
        for img in client.images.list():
            for tag in img.tags or []:
                if not prefix or tag.startswith(prefix):
                    tags.append(tag)
        unique_sorted = sorted(set(tags))
        if not unique_sorted:
            raise RuntimeError(
                "No Docker images found that match the configured prefix."
            )
        return unique_sorted
    except Exception as e:  # noqa: BLE001
        print(f"[JupyterHub] Error discovering Docker images: {e}", file=sys.stderr)
        raise
4 Likes

@manics Do I need to restart jupyterhub instance in order for my docker image list to get updated?

You shouldn’t. If it’s not working can you share your full configuration?

I can’t share full configuration at the moment but I have c.DockerSpawner.pull_policy = "Skip"set. Not sure if it is causing the issue?

Another thing I observed it that list gets refreshed only when I start and stop some random image/user server. It doesn’t refresh when I click to create new user server and when the page to choose an image pops up.

Was causing the issue

I can reproduce the behavior with the following minimal JupyterHub configuration using the latest versions.

c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'

c.JupyterHub.log_level = "DEBUG"

c.JupyterHub.authenticator_class = "shared-password"
c.SharedPasswordAuthenticator.user_password = "test1234"
c.Authenticator.allow_all = True

import sys
import docker
import os

def dynamic_allowed_images(spawner):
    """Return a list of available Docker image tags.

    Optionally filter by prefix via env var `ALLOWED_IMAGE_PREFIX`.
    Raises RuntimeError if no images match or discovery fails.
    """
    print("\n=== Called allowed_images ===\n")

    try:
        client = docker.from_env()
        prefix = os.environ.get("ALLOWED_IMAGE_PREFIX", "")

        tags = []
        for img in client.images.list():
            for tag in img.tags or []:
                if not prefix or tag.startswith(prefix):
                    tags.append(tag)
        unique_sorted = sorted(set(tags))
        if not unique_sorted:
            raise RuntimeError(
                "No Docker images found that match the configured prefix."
            )
        return unique_sorted
    except Exception as e:  # noqa: BLE001
        print(f"[JupyterHub] Error discovering Docker images: {e}", file=sys.stderr)
        raise

c.DockerSpawner.allowed_images = dynamic_allowed_images

Reloading the spawn page does not call the method dynamic_allowed_images again. Thus, the options do not change.

I tried to find the cause but couldn’t get the connection between dockerspawner/dockerspawner/dockerspawner.py at 87e4358630af8c1fc5f9edcf070ad95e137a98cf · jupyterhub/dockerspawner · GitHub and jupyterhub/jupyterhub/spawner.py at ab91bdd4732e3840ca6aaf6b8ff713fbd972d436 · jupyterhub/jupyterhub · GitHub.