jupyterhub / dockerspawner

Spawns JupyterHub single user servers in Docker containers
https://jupyterhub-dockerspawner.readthedocs.io
BSD 3-Clause "New" or "Revised" License
490 stars 308 forks source link

Jupyterhub server starts, but fails to spawner jupyter notebook #308

Closed alvinhuff closed 5 years ago

alvinhuff commented 5 years ago

Hello I am running jupyterhub 1.0.0 behind a nginx/letsencrypt reverse proxy on jetstream both are docker containers on Ubuntu 18.04. I started this project initially following this guide (https://zonca.github.io/2017/10/scalable-jupyterhub-docker-swarm-mode.html ). The juypterhub container is being created by a service called jupyterhub server. The nginx proxy is a container setup to restart unless stopped using this guide (https://blog.linuxserver.io/2019/04/25/letsencrypt-nginx-starter-guide/ ).

I created a docker network called jupyterhub using the overlay and attachable switches.

I can manage to reach the server and login with a local account, but then I get the url: https://www.sgsup-jupyterhub.duckdns.org/hub/spawn-pending/alvin and the error Spawn failed.

When I run "juptyerhub --debug" from the jupyterhub container I get

oot@jupyterhubserver:/srv/jupyterhub# jupyterhub --debug
[D 2019-05-15 02:02:10.155 JupyterHub application:555] Looking for jupyterhub_config in /srv/jupyterhub
[D 2019-05-15 02:02:10.156 JupyterHub application:577] Loaded config file: /srv/jupyterhub/jupyterhub_config.py
[I 2019-05-15 02:02:10.169 JupyterHub app:2120] Using Authenticator: jupyterhub.auth.PAMAuthenticator-1.0.0
[I 2019-05-15 02:02:10.169 JupyterHub app:2120] Using Spawner: dockerspawner.swarmspawner.SwarmSpawner-0.11.1
[I 2019-05-15 02:02:10.174 JupyterHub app:1257] Loading cookie_secret from /srv/jupyterhub/jupyterhub_cookie_secret
[D 2019-05-15 02:02:10.175 JupyterHub app:1424] Connecting to db: sqlite:///jupyterhub.sqlite
[D 2019-05-15 02:02:10.194 JupyterHub orm:749] database schema version found: 4dc2d5a8c53c
[I 2019-05-15 02:02:10.199 JupyterHub proxy:460] Generating new CONFIGPROXY_AUTH_TOKEN
[W 2019-05-15 02:02:10.202 JupyterHub configurable:168] Config option `delete_invalid_users` not recognized by `PAMAuthenticator`.
[D 2019-05-15 02:02:10.248 JupyterHub app:1910] Loading state for alvin from db
[D 2019-05-15 02:02:10.248 JupyterHub app:1926] Loaded users:
       alvin admin
[E 2019-05-15 02:02:10.258 JupyterHub app:2341] Failed to bind hub to http://0.0.0.0:8000/hub/
[E 2019-05-15 02:02:10.258 JupyterHub app:2482]
    Traceback (most recent call last):
      File "/opt/conda/lib/python3.6/site-packages/jupyterhub/app.py", line 2480, in launch_instance_async
        await self.start()
      File "/opt/conda/lib/python3.6/site-packages/jupyterhub/app.py", line 2336, in start
        self.http_server.listen(port, address=ip)
      File "/opt/conda/lib/python3.6/site-packages/tornado/tcpserver.py", line 151, in listen
        sockets = bind_sockets(port, address=address)
      File "/opt/conda/lib/python3.6/site-packages/tornado/netutil.py", line 174, in bind_sockets
        sock.bind(sockaddr)
    OSError: [Errno 98] Address already in use

[D 2019-05-15 02:02:10.260 JupyterHub application:647] Exiting application: jupyterhub
ERROR:asyncio:Task exception was never retrieved
future: <Task finished coro=<JupyterHub.launch_instance_async() done, defined at /opt/conda/lib/python3.6/site-packages/jupyterhub/app.py:2477> exception=SystemExit(1,)>
Traceback (most recent call last):
  File "/opt/conda/lib/python3.6/site-packages/jupyterhub/app.py", line 2480, in launch_instance_async
    await self.start()
  File "/opt/conda/lib/python3.6/site-packages/jupyterhub/app.py", line 2336, in start
    self.http_server.listen(port, address=ip)
  File "/opt/conda/lib/python3.6/site-packages/tornado/tcpserver.py", line 151, in listen
    sockets = bind_sockets(port, address=address)
  File "/opt/conda/lib/python3.6/site-packages/tornado/netutil.py", line 174, in bind_sockets
    sock.bind(sockaddr)
OSError: [Errno 98] Address already in use

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/conda/lib/python3.6/site-packages/jupyterhub/app.py", line 2492, in launch_instance
    loop.start()
  File "/opt/conda/lib/python3.6/site-packages/tornado/platform/asyncio.py", line 148, in start
    self.asyncio_loop.run_forever()
  File "/opt/conda/lib/python3.6/asyncio/base_events.py", line 427, in run_forever
    self._run_once()
  File "/opt/conda/lib/python3.6/asyncio/base_events.py", line 1440, in _run_once
    handle._run()
  File "/opt/conda/lib/python3.6/asyncio/events.py", line 145, in _run
    self._callback(*self._args)
  File "/opt/conda/lib/python3.6/site-packages/jupyterhub/app.py", line 2483, in launch_instance_async
    self.exit(1)
  File "/opt/conda/lib/python3.6/site-packages/traitlets/config/application.py", line 648, in exit
    sys.exit(exit_status)
SystemExit: 1

when I run ps aux from the jupyterhub container I get:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.4 264808 70888 ?        Ssl  May14   0:07 /opt/conda/bin/python /opt/conda/bin/jupyterhub -f /srv/jupyterhub/jupyterhub_config.py
root        11  0.0  0.2 559844 37272 ?        Ssl  May14   0:01 node /opt/conda/bin/configurable-http-proxy --ip  --port 8000 --api-ip 127.0.0.1 --api-port 8001 --error-target http://jupyterhubserver:8000/hub/error
root        20  0.0  0.0  20256  3940 pts/0    Ss+  00:58   0:00 /bin/bash
root       293  0.0  0.0  20256  3776 pts/1    Ss+  01:08   0:00 /bin/bash
root       367  0.0  0.0  20256  3868 pts/2    Ss+  01:42   0:00 /bin/bash
root       631  0.0  0.0  20256  3876 pts/3    Ss   02:01   0:00 /bin/bash
root       651  0.0  0.0  36148  3280 pts/3    R+   02:03   0:00 ps aux

This is my pip list results

root@jupyterhubserver:/srv/jupyterhub# pip list
Package           Version
----------------- --------
alembic           1.0.10
asn1crypto        0.24.0
async-generator   1.10
attrs             19.1.0
backcall          0.1.0
bleach            3.1.0
certifi           2019.3.9
certipy           0.1.3
cffi              1.12.3
chardet           3.0.4
conda             4.6.14
cryptography      2.6.1
decorator         4.4.0
defusedxml        0.6.0
docker            3.7.2
docker-pycreds    0.4.0
dockerspawner     0.11.1
entrypoints       0.3
escapism          1.0.0
globus-sdk        1.7.1
idna              2.8
ipykernel         5.1.0
ipython           7.5.0
ipython-genutils  0.2.0
jedi              0.13.3
Jinja2            2.10.1
jsonschema        3.0.1
jupyter-client    5.2.4
jupyter-core      4.4.0
jupyterhub        1.0.0
jupyterlab        0.35.5
jupyterlab-server 0.2.0
Mako              1.0.9
MarkupSafe        1.1.1
mistune           0.8.4
nbconvert         5.5.0
nbformat          4.4.0
notebook          5.7.8
oauthenticator    0.8.2
oauthlib          3.0.1
pamela            1.0.0
pandocfilters     1.4.2
parso             0.4.0
pexpect           4.7.0
pickleshare       0.7.5
pip               19.1
prometheus-client 0.6.0
prompt-toolkit    2.0.9
ptyprocess        0.6.0
pycosat           0.6.3
pycparser         2.19
pycurl            7.43.0.2
Pygments          2.4.0
PyJWT             1.7.1
pyOpenSSL         19.0.0
pyrsistent        0.14.11
PySocks           1.6.8
python-dateutil   2.8.0
python-editor     1.0.4
pyzmq             18.0.0
requests          2.21.0
ruamel-yaml       0.15.71
Send2Trash        1.5.0
setuptools        41.0.1
six               1.12.0
SQLAlchemy        1.3.3
style             1.1.0
terminado         0.8.2
testpath          0.4.2
tornado           6.0.2
traitlets         4.3.2
update            0.0.1
urllib3           1.24.2
wcwidth           0.1.7
webencodings      0.5.1
websocket-client  0.56.0
wheel             0.33.1

This is the docker file I use to build the image that the jupyterhubserver service uses

FROM jupyterhub/jupyterhub-onbuild:latest

EXPOSE 8000

RUN /opt/conda/bin/conda install notebook jupyterlab

RUN python3 -m pip install --upgrade notebook

RUN /opt/conda/bin/pip install oauthenticator dockerspawner globus-sdk

RUN useradd -rm -d /home/alvin -s /bin/bash -g root -G sudo -u 1000 alvin -p "$(openssl passwd -1 reallystronger)"

WORKDIR /srv/jupyterhub/

This is my jupyterhub_config.py file

import os

c = get_config()

## and enable admin access within jupyterhub with the two lines below
c.PAMAuthenticator.open_sessions = False
c.Authenticator.whitelist = {"alvin"}
c.Authenticator.admin_users = {"alvin"}
c.PAMAuthenticator.admin_groups = {"alvin"}
## grants administrators access to all  notebooks
c.JupyterHub.admin_access = True
## the LocalAuthenticator has the privileges to add users to the system.
#c.LocalAuthenticator.create_system_users = True

##    automatically delete users from the Hub database that no longer pass
##    Authenticator validation,
##    such as when user accounts are deleted from the external system
##    without notifying JupyterHub (one day this will work 05/08/19
c.Authenticator.delete_invalid_users = True

##this or something like it will implemented at a later date
# Globus OAthentication
#from oauthenticator.globus import LocalGlobusOAuthenticator
#c.JupyterHub.authenticator_class = LocalGlobusOAuthenticator
#c.LocalGlobusOAuthenticator.enable_auth_state = True
#c.LocalGlobusOAuthenticator.oauth_callback_url = 'https://www.sgsup-jupyterhub.duckdns.org/hub/oauth_callback'
#c.LocalGlobusOAuthenticator.client_id = 'redacted.clients.auth.globus.org'
#c.LocalGlobusOAuthenticator.client_secret = 'redacted'

## The public facing port of the proxy
c.JupyterHub.hub_port = 8000
## The public facing ip of the whole application (the proxy)
c.JupyterHub.hub_ip = '0.0.0.0'
## The ip for this process
c.JupyterHub.hub_connect_ip = 'jupyterhubserver'
## revers proxy setting for nginx
#c.JupyterHub.base_url = '/hub/'
#  Defaults to an empty set, in which case no user has admin access.
#c.LocalGlobusOAuthenticator.admin_users = {"sirace@asu.edu"}

c.JupyterHub.spawner_class = 'dockerspawner.SwarmSpawner'
##possibly delete
#c.SwarmSpawner.jupyterhub_service_name = "jupyterhubserver"

c.SwarmSpawner.network_name = 'jupyterhub'

notebook_dir = os.environ.get('NOTEBOOK_DIR') or '/home/jovyan/work'
c.SwarmSpawner.notebook_dir = notebook_dir

mounts = [{'type': 'volume',
           'source': 'jupyterhub-user-{username}',
           'target': notebook_dir,
        'no_copy' : True,
        'driver_config' : {
          'name' : 'local',
          'options' : {
             'type' : 'nfs4',
             'o' : 'addr=jupterhubserver,rw',
             'device' : ':/var/nfs/{username}/'
           }
        },
}]

c.SwarmSpawner.extra_container_spec = {
    # The command to run inside the service
    'args': ['/usr/local/bin/start-singleuser.sh'],  # (string or list)
    'Image': 'jupyter/datascience-notebook:latest',
    # Replace mounts with [] to disable permanent storage otherwise leave as mounts
    'mounts': ['SwarmSpawner']
}

c.SwarmSpawner.extra_resource_spec = {
    # (int)  CPU limit in units of 10^9 CPU shares.
    'cpu_limit': int(1 * 1e9),
    # (int)  Memory limit in Bytes.
    'mem_limit': int(512 * 1e6),
    # (int)  CPU reservation in units of 10^9 CPU shares.
    'cpu_reservation': int(1 * 1e9),
    # (int)  Memory reservation in bytes
    'mem_reservation': int(512 * 1e6),
}
alvinhuff commented 5 years ago

So on a side note this is my first serious attempt at building something within the jupyterverse. Any recommendations on good starting point would be appreciated. This project will be for an online course teaching programing principles. I am not the instructor, but the tech support.

mohirio commented 5 years ago

The problem is with this line: c.JupyterHub.hub_ip = '0.0.0.0' You need to bind JupyterHub to a reachable IP address from outside your computer.

Also, it's better to check this out if you haven't: https://jupyterhub.readthedocs.io/en/stable/getting-started/networking-basics.html

c.JupyterHub.hub_connect_ip should be set to an IP visible to the docker containers.

alvinhuff commented 5 years ago

@mohirio According to the link you provided " Added in 0.8: The c.JupyterHub.hub_connect_ip setting is the ip address or hostname that other services should use to connect to the Hub" is this feature buggy? below is from the "docker inspect" command for the juptyerhubserver container.

"Config": {
            "Hostname": "jupyterhubserver",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "8000/tcp": {}

I am running jupyterhub as a docker container on a jetstream-cloud.org Ubuntu 18.04 VM. I use the hostname because the ip keeps changing.

My understanding from the link you provided '0.0.0.0' is jupyterhub standard notation to listen on all ip addresses is this just buggy?

mohirio commented 5 years ago

@alvinhuff Hey, sorry for the reply. I'm not really experienced with running JupyterHub itself in a docker container. But the error shows that JupyterHub can't bind to 0.0.0.0 since it's already in use, try changing it to a different IP address,

alvinhuff commented 5 years ago

@mohirio Hi I completed docker-compose.yml file to speed up my development now two service come up jupyterhubserver and nginx both successfully creating containers. Then I tried modifying the ip address in the jupyterhub_config.py and then exec jupyterhub and got the same result "service jupyter-alvin" failed to launch. I can then login and upon logging in a third service starts, which I am guessing is the result of the swarmspawner

docker service ls
ID                  NAME                   MODE                REPLICAS            IMAGE                                     PORTS
alqmll5y4r3q        Hub_jupyterhubserver   replicated          1/1                 sgsupdocker/jupyterhub-onbuild:052119.2   *:8000->8000/tcp
tcfxmfoibpil        Hub_nginx              replicated          1/1                 linuxserver/letsencrypt:latest            *:80->80/tcp, *:443->443/tcp
vfwzedtv6fy6        jupyter-alvin          replicated          0/1                 jupyter/datascience-notebook:latest

But the service jupyter-alvin fails to start a container, but the service task return this error: "invalid mount target, must be an absolute path: SwarmSpawner"

Does the notebook_dir and 'device' : ':/var/nfs/{username}/' need to be the same?

Thanks in advance for your help

alvinhuff commented 5 years ago

Hello, I have resolved the binding issue, but now I get I am getting this error : Unhandled error starting alvin's server: Incompatible options have been provided for the bind type mount. The browser throws and error: API request failed (500): error

from my jupyterhub_config.py file:

c.JupyterHub.spawner_class = 'dockerspawner.SwarmSpawner'
network_name = os.environ['DOCKER_NETWORK_NAME']
c.SwarmSpawner.network_name = network_name
c.SwarmSpawner.use_internal_ip = True

## Pass the network name as argument to spawned containers
c.SwarmSpawner.extra_host_config = {'network_mode': network_name}
c.SwarmSpawner.host_ip = '0.0.0.0'
notebook_dir = os.environ.get('NOTEBOOK_DIR') or '/home/joyvan/work'
c.SwarmSpawner.notebook_dir = notebook_dir

## Mount the user's notebook directory in the container
c.SwarmSpawner.volumes = { 'jupyterhub-user-{username}': notebook_dir }

## Remove containers once they are stopped
c.SwarmSpawner.remove_containers = True

## For debugging arguments passed to spawned containers
c.SwarmSpawner.debug = True

from my docker.yml file

services:
  jupyterhubserver:
    image: sgsupdocker/jupyterhub-onbuild:060319.2
    hostname: jupyterhubserver
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /vol_b/exchange:/home/joyvan/work
    networks:
      jupyterhub:
        aliases:
          - jupyterhubserver
    environment:
      DOCKER_NETWORK_NAME: jupyterhub
      NOTEBOOK_DIR: /home/joyvan/work
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager

from the container logs:

Traceback (most recent call last):
      File "/opt/conda/lib/python3.6/site-packages/tornado/web.py", line 1699, in _execute
        result = await result
      File "/opt/conda/lib/python3.6/site-packages/jupyterhub/apihandlers/users.py", line 414, in post
        await self.spawn_single_user(user, server_name, options=options)
      File "/opt/conda/lib/python3.6/site-packages/jupyterhub/handlers/base.py", line 889, in spawn_single_user
        timedelta(seconds=self.slow_spawn_timeout), finish_spawn_future
      File "/opt/conda/lib/python3.6/site-packages/jupyterhub/handlers/base.py", line 807, in finish_user_spawn
        await spawn_future
      File "/opt/conda/lib/python3.6/site-packages/jupyterhub/user.py", line 642, in spawn
        raise e
      File "/opt/conda/lib/python3.6/site-packages/jupyterhub/user.py", line 546, in spawn
        url = await gen.with_timeout(timedelta(seconds=spawner.start_timeout), f)
      File "/opt/conda/lib/python3.6/site-packages/dockerspawner/dockerspawner.py", line 983, in start
        obj = yield self.create_object()
      File "/opt/conda/lib/python3.6/site-packages/dockerspawner/swarmspawner.py", line 180, in create_object
        mounts=self.mounts,
      File "/opt/conda/lib/python3.6/site-packages/dockerspawner/swarmspawner.py", line 117, in mounts
        for host_loc, vol in self.volume_binds.items()
      File "/opt/conda/lib/python3.6/site-packages/dockerspawner/swarmspawner.py", line 117, in <listcomp>
        for host_loc, vol in self.volume_binds.items()
      File "/opt/conda/lib/python3.6/site-packages/docker/types/services.py", line 242, in __init__
        'Incompatible options have been provided for the bind '
docker.errors.InvalidArgument: Incompatible options have been provided for the bind type mount.

I think I have included all the relevant information. Am I getting this error because I am NOT using a named docker volume? The reason I am not using a named docker volume is becuase I keep getting a permissions denied when the permissions for both the destination and the source are set to ugo+rw. Any insights would be greatly appreciated.

alvinhuff commented 5 years ago

I have decided to go with TLJH. I might try dockerswarm at a later date