How to run jupyterhub with docker swarm?

How to run jupyterhub with docker swarm? I init the docker swarm and add my nodes, and try to run docker service on the manager node but fail? How to set the config ?

Have you seen the DockerSpawner documentation? DockerSpawner

If you need more help please have a look at Getting good answers to your questions first. Thanks!

Thanks for the advice,I set the config below:

c = get_config()
# from jupyterhub.spawner import Spawner
# from dockerspawner import SystemUserSpawner
from dockerspawner import SwarmSpawner
# from pwd import getpwnam
import re
from jupyterhub.auth import Authenticator
import os, pwd,grp
import shlex

from jupyterhub.spawner import LocalProcessSpawner
import subprocess
### Custom UI

def get_gids_from_id(username):
    id_out = subprocess.check_output(['id', username]).decode('ascii')
    uid, gid, groups = id_out.strip().split(' ')
    _, groups = groups.split('=')
    gids = [int(g.split('(')[0]) for g in groups.split(',')]
    return gids,uid
class DemoFormSpawner(SwarmSpawner):
    def _options_form_default(self):
        default_stack = "qycai/base-notebook"
        default_env = "YOURNAME=%s\n" % self.user.name
        return """
        <label for="stack">Select your image</label>
        <select name="stack" size="1">
        <option value="qycai/base-notebook">base notebook </option>
        <option value="qycai/minimal-notebook">minimal notebook </option>
        <option value="qycai/datascience-notebook">single-cell Datascience notebook </option>
        </select>
        <div class="form-group">
            <label for="args">Extra notebook CLI arguments</label>
            <input name="args" class="form-control"
                placeholder="e.g. --debug"></input>
        </div>
        <div class="form-group">
            <label for="env">Environment variables <span style=\"font-size: 12px; font-weight: 400;\">(one per line)</span></label>
            <textarea class="form-control" name="env">{env}</textarea>
        </div>
        <div style="margin-bottom: 16px">
            <label style="width: 25%" for="cpu_limit" >CPU Limit <span style=\"font-size: 12px; font-weight: 400;\">(optional)</span></label>
            <input style="width: 75%" name="cpu_limit" placeholder="e.g. 8"></input>
        </div>
        <div style="margin-bottom: 16px">
            <label style="width: 25%" for="mem_limit" >Memory Limit in GB <span style=\"font-size: 12px; font-weight: 400;\">(optional)</span></label>
            <input style="width: 75%" name="mem_limit" id="mem-limit" placeholder="e.g. 16"></input>
        </div>
        """.format(stack=default_stack,env=default_env)
    def options_from_form(self, formdata):
        options = {}
        options['stack'] = formdata['stack']
        container_image = ''.join(formdata['stack'])
        print("SPAWN: " + container_image + " IMAGE" )
        self.container_image = container_image
        options['env'] = env = {}

        env_lines = formdata.get('env', [''])
        for line in env_lines[0].splitlines():
            if line:
                key, value = line.split('=', 1)
                env[key.strip()] = value.strip()

        arg_s = formdata.get('args', [''])[0].strip()
        if arg_s:
            options['argv'] = shlex.split(arg_s)
        options['cpu_limit'] = formdata['cpu_limit']
        options['mem_limit'] = formdata['mem_limit']
        return options
    def get_args(self):
        """Return arguments to pass to the notebook server"""
        argv = super().get_args()
        if self.user_options.get('argv'):
            argv.extend(self.user_options['argv'])
        return argv

    def get_env(self):
        env = super().get_env()
        if self.user_options.get('env'):
            env.update(self.user_options['env'])
        env.pop('USER',  None)
        # set notebook UID
        env['NB_UID'] = get_gids_from_id(self.user.name)[1]
        env.update(NB_GID=get_gids_from_id(self.user.name)[0])
        return env
c.JupyterHub.template_paths=['.']
c.JupyterHub.spawner_class = DemoFormSpawner
c.JupyterHub.shutdown_on_logout = True
c.SwarmSpawner.extra_create_kwargs = {'user': 'root'}
c.SwarmSpawner.environment = {
  'CHOWN_HOME':'yes',
  'CHOWN_HOME_OPTS':'-R',
}
c.SwarmSpawner.extra_create_kwargs.update({ 'command': "start-singleuser.sh --SingleUserNotebookApp.default_url=/lab" })

network_name = 'jupyterhub_network'
c.SwarmSpawner.use_internal_ip = True
c.SwarmSpawner.network_name = network_name
c.SwarmSpawner.extra_host_config = { 'network_mode': network_name }
notebook_dir = '/home'
c.SwarmSpawner.volumes = {'jupyterhub-user-{username}': notebook_dir,'/data1/home': {"bind": '/home/sc_user', "mode": "rw"}}
c.SwarmSpawner.remove_containers = True
c.SwarmSpawner.debug = True
c.PAMAuthenticator.open_sessions = False
c.JupyterHub.ip = '0.0.0.0'
c.JupyterHub.port = 8000
c.Authenticator.whitelist = whitelist = set()
c.Authenticator.admin_users = admin = set()
c.LocalAuthenticator.create_system_users=True
here = os.path.dirname(__file__)
with open(os.path.join(os.path.dirname(__file__), 'userlist')) as f:
    for line in f:
        if not line:
            continue
        parts = line.split()
        name = parts[0]
        whitelist.add(name)
        if len(parts) > 1 and parts[1] == 'admin':
            admin.add(name)

and i get the error when I spawn :

[E 2021-11-04 03:10:52.651 JupyterHub pages:209] Failed to spawn single-user server with form
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |     Traceback (most recent call last):
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/site-packages/jupyterhub/handlers/pages.py", line 206, in post
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         await self.spawn_single_user(user, server_name=server_name, options=options)
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/site-packages/jupyterhub/handlers/base.py", line 889, in spawn_single_user
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         timedelta(seconds=self.slow_spawn_timeout), finish_spawn_future
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/site-packages/jupyterhub/handlers/base.py", line 807, in finish_user_spawn
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         await spawn_future
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/site-packages/jupyterhub/user.py", line 642, in spawn
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         raise e
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/site-packages/jupyterhub/user.py", line 546, in spawn
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         url = await gen.with_timeout(timedelta(seconds=spawner.start_timeout), f)
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/site-packages/dockerspawner/dockerspawner.py", line 1270, in start
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         obj = await self.create_object()
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/site-packages/dockerspawner/swarmspawner.py", line 239, in create_object
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         service = await self.docker("create_service", **create_kwargs)
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/concurrent/futures/thread.py", line 56, in run
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         result = self.fn(*self.args, **self.kwargs)
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/site-packages/dockerspawner/dockerspawner.py", line 948, in _docker
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         return m(*args, **kwargs)
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |       File "/opt/conda/lib/python3.6/site-packages/docker/utils/decorators.py", line 34, in wrapper
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |         return f(self, *args, **kwargs)
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |     TypeError: create_service() got an unexpected keyword argument 'user'
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    |
swarmhub_jupyter_notebook.1.tis8j8tdq3g2@c5    | [I 2021-11-04 03:10:52.653 JupyterHub log:174] 200 POST /hub/spawn (qycai@127.0.0.1) 134.23ms

I suspect the above error is related your your config:

Have you tried getting SwarmSpawner to work with a minimal configuration, then gradually adding in more customisations?

I think you should be careful with this setup, because you use user supplied values through the HTML form directly without any validation.