diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 198c7c306385da123f4ebaff0b3914dd2442ab29..e4688ce940240259bb27bbfe53d926a0b1b62cf4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,15 +1,16 @@ variables: docker_registry_user: "robot$$gitlab" - docker_image_tag: "1.5" stages: - build -build_base: +build_image: stage: build script: - - docker build -f base/Dockerfile -t docker-registry.ebrains.eu/clb-jupyter-image/base:$docker_image_tag . + - docker build -f base/Dockerfile -t docker-registry.ebrains.eu/clb-jupyter-image/ebrains:$CI_COMMIT_TAG . - docker login -u $docker_registry_user -p $docker_registry_prod_token docker-registry.ebrains.eu - - docker push docker-registry.ebrains.eu/clb-jupyter-image/base:$docker_image_tag + - docker push docker-registry.ebrains.eu/clb-jupyter-image/ebrains:$CI_COMMIT_TAG + only: + - tags tags: - shell-runner diff --git a/base/Dockerfile b/base/Dockerfile index b718930f06053f6e17971cea46812496d5a652bc..00fbb5ec855a5834741a935a5853fc04dc369dd3 100644 --- a/base/Dockerfile +++ b/base/Dockerfile @@ -1,112 +1,120 @@ -FROM centos/python-36-centos7 +FROM ubuntu:focal -MAINTAINER Collaboratory Platform <platform@humanbrainproject.eu> +LABEL maintainer="Collaboratory Platform <platform@humanbrainproject.eu>" + +ARG NB_USER="jovyan" +ARG NB_UID=1000 +ARG NB_GID=100 ENV GIT_COMMITTER_NAME=platform@humanbrainproject.eu \ GIT_COMMITTER_EMAIL=platform@humanbrainproject.eu \ + USER="${NB_USER}" \ MPLBACKEND=Agg \ - SDAHOME=/opt/app-root/lib/sda_flex \ - MPICC=/usr/lib64/mpich/bin/mpicc \ + SHELL=/bin/bash \ XDG_CACHE_HOME=/tmp/cache/ \ - LAB_IMAGE_NAME=EBRAINS_EXPERIMENTAL + LAB_IMAGE_NAME=EBRAINS_OFFICIAL USER root -# the version of jupyter lab isn't compatible with newer node versions. Specify version of node (10) -RUN curl -SsL https://rpm.nodesource.com/setup_10.x | bash - -# Install all OS dependencies for notebook server that starts but lacks all -# features (e.g., download as all possible file formats) -# to use devtoolset 10 (e.g. gcc): scl enable devtoolset-10 bash -RUN yum install -y epel-release && \ - yum-config-manager --enable epel && \ - yum groupinstall -y 'Development Tools' && \ - yum install -y centos-release-scl && yum install -y devtoolset-10 && \ - yum install -y \ - bzip2-devel \ - cmake \ - cmake3 \ - csh \ - curl \ - Cython \ - fio \ - freetype-devel \ - gsl-devel \ - hdf5-devel \ - liberation-fonts \ - libtool-ltdl-devel \ - libXext-devel \ - libXrender \ - llvm \ - lsof \ - mpich \ - mpich-devel \ - ncurses-devel \ - nodejs \ - pandoc \ - python-devel \ - R \ - readline-devel \ - texlive-latex \ - unzip \ - vim \ - wget \ - && yum -y clean all - -# Set the Switzerland timezone +# Set the Switzerland timezone (necessary to make r-base install noninteractive) RUN ln -sf /usr/share/zoneinfo/Europe/Zurich /etc/localtime -RUN mkdir -p /opt/app-root/etc /opt/app-root/clb/ +# Set to noninteractive for install +ENV DEBIAN_FRONTEND noninteractive +RUN apt-get update --yes && \ + apt-get install --yes \ + ca-certificates \ + cmake \ + csh \ + curl \ + cython \ + gcc \ + gettext \ + git \ + libnss-wrapper \ + llvm \ + lsof \ + mpich \ + pandoc \ + python3-pip \ + r-base \ + unzip \ + vim && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# install nodejs +RUN curl -fsSL https://deb.nodesource.com/setup_17.x | bash +RUN apt-get install -y nodejs + +# install min texlive (necessary for nb exports) +RUN apt-get update --yes && \ + apt-get install --yes --no-install-recommends \ + texlive-xetex \ + texlive-fonts-recommended \ + texlive-plain-generic && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# jupyter install in /opt/app-root/ for legacy reasons (previously based on centos base image) +RUN mkdir -p /opt/app-root/etc /opt/app-root/clb/ /opt/app-root/src COPY base/jupyter_notebook_config.py /opt/app-root/etc/ + +# folders for drive integration +RUN mkdir -p /mnt/user/ RUN ln -s /mnt/user/drive /opt/app-root/src/drive RUN ln -s /mnt/user/shared /opt/app-root/src/shared +ENV HOME=/opt/app-root/src/ +# install pip packages COPY base/requirements.txt /tmp -# needs to be installed before rpy2 -RUN pip install cffi==1.14.5 -RUN pip install -r /tmp/requirements.txt -# requirements.tvb need to be installed in separate step -COPY base/requirements.tvb.txt /tmp -RUN pip install -r /tmp/requirements.tvb.txt - -RUN python -c "import matplotlib.pyplot" - -RUN jupyter nbextension enable --py widgetsnbextension --sys-prefix && \ - jupyter nbextension enable --py nglview --sys-prefix +RUN pip install --no-cache-dir -r /tmp/requirements.txt -RUN jupyter labextension disable @jupyterlab/filebrowser-extension:share-file +# fix missing template issue in nbgitpuller: https://github.com/jupyterhub/nbgitpuller/issues/235 +# remove this once it has been fixed in project +RUN ln -s /usr/local/lib/python3.8/dist-packages/nbgitpuller/templates/status.html /usr/local/lib/python3.8/dist-packages/notebook/templates/ -# todo: investigate issue why labextension install fails with an npm error -RUN jupyter labextension install --no-build @jupyter-widgets/jupyterlab-manager@1.1.0 \ - @bokeh/jupyter_bokeh@1.2.0 \ - @krassowski/jupyterlab_go_to_definition@0.7.1 \ - jupyterlab-topbar-extension@0.4.0 \ - jupyterlab-system-monitor@0.4.1 \ - jupyterlab-plotly@4.14.3 \ - nglview-js-widgets@2.7.1 \ - clb-jupyter-ext-copy-shareable-link@1.0.0 \ - clb-jupyter-ext-query-params@1.0.1 +# disable ipcluster extension +RUN jupyter labextension disable ipcluster \ + ipyparallel-labextension -RUN jupyter labextension install jupyter-matplotlib@0.7.4 +# install additional labextensions +RUN jupyter labextension install --no-build @jupyter-widgets/jupyterlab-manager@v3.0.1 \ + @krassowski/jupyterlab_go_to_definition@v1.0.0 \ + jupyterlab-topbar-extension@v0.6.0 \ + jupyterlab-system-monitor@v0.7.0 \ + jupyterlab-plotly@v5.5.0 \ + jupyter-matplotlib@v0.10.4 \ + clb-jupyter-ext-query-params@3.2.0 RUN jupyter lab build RUN jupyter notebook --generate-config -RUN mkdir -p /opt/app-root/src/.ipython/profile_default/startup/ -RUN mkdir -p /tmp/cache/ - -# @TODO Remove this when bug is fixed: https://github.com/ipython/ipython/issues/11546 -RUN echo 'c.Completer.use_jedi = False' >> /opt/app-root/src/.ipython/profile_default/ipython_config.py +RUN mkdir -p /opt/app-root/src/.ipython/profile_default/startup/ /opt/app-root/src/.local/lib/python3.8/site-packages/ /tmp/cache/ # Preload clb_oauth RUN echo 'from clb_nb_utils import oauth as clb_oauth' >> /opt/app-root/src/.ipython/profile_default/startup/50-clb-nb-utils.py -RUN fix-permissions /opt/app-root -RUN fix-permissions /tmp/cache +# fix permissions so NB_USER has permissions to run notebooks and install packages +COPY base/fix-permissions /usr/local/bin/fix-permissions +RUN chmod +x /usr/local/bin/fix-permissions + +RUN fix-permissions /opt/app-root/ && \ + fix-permissions /tmp/cache/ && \ + fix-permissions /usr/local/share/jupyter/ && \ + fix-permissions /usr/local/etc/jupyter && \ + fix-permissions /usr/etc/jupyter/ + +# to support OpenShift's arbitrary UIDs +# more info: https://docs.openshift.com/enterprise/3.1/creating_images/guidelines.html +COPY base/passwd.template /tmp/passwd.template +COPY base/group.template /tmp/group.template +COPY base/start-notebook.sh /opt/app-root/etc/ +RUN chmod +x /opt/app-root/etc/start-notebook.sh + +WORKDIR /opt/app-root/src/ EXPOSE 8080 -USER 1000 +USER ${NB_UID} -CMD jupyter labhub --NotebookApp.default_url=/lab --config=/opt/app-root/etc/jupyter_notebook_config.py $@ +CMD /opt/app-root/etc/start-notebook.sh diff --git a/base/fix-permissions b/base/fix-permissions new file mode 100644 index 0000000000000000000000000000000000000000..45354c0dccbadfef143fc32333a8b240430d3d89 --- /dev/null +++ b/base/fix-permissions @@ -0,0 +1,28 @@ +#!/bin/sh +# source: https://github.com/sclorg/s2i-base-container/blob/master/core/root/usr/bin/fix-permissions + +# Allow this script to fail without failing a build +set +e + +SYMLINK_OPT=${2:--L} + +# Fix permissions on the given directory or file to allow group read/write of +# regular files and execute of directories. + +[ $(id -u) -ne 0 ] && CHECK_OWNER=" -uid $(id -u)" + +# If argument does not exist, script will still exit with 0, +# but at least we'll see something went wrong in the log +if ! [ -e "$1" ] ; then + echo "ERROR: File or directory $1 does not exist." >&2 + # We still want to end successfully + exit 0 +fi + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} \! -gid 0 -exec chgrp 0 {} + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} \! -perm -g+rw -exec chmod g+rw {} + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} -perm /u+x -a \! -perm /g+x -exec chmod g+x {} + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} -type d \! -perm /g+x -exec chmod g+x {} + + +# Always end successfully +exit 0 \ No newline at end of file diff --git a/base/group.template b/base/group.template new file mode 100644 index 0000000000000000000000000000000000000000..a957d0695246d100aae8a5ed23b5922d2688f361 --- /dev/null +++ b/base/group.template @@ -0,0 +1,2 @@ +nb_group:x:${GROUP_ID}: +nb_group_user:x:${USER_ID}: \ No newline at end of file diff --git a/base/jupyter_notebook_config.py b/base/jupyter_notebook_config.py index d82e2241d473dd29b7cf8f656eea90e6629abf76..6b9fc72094b87c9749d64cced15572d7fb6a21ac 100644 --- a/base/jupyter_notebook_config.py +++ b/base/jupyter_notebook_config.py @@ -7,7 +7,6 @@ c.NotebookApp.port = port c.NotebookApp.open_browser = False c.NotebookApp.quit_button = False -c.PDFExporter.enabled = False c.WebPDFExporter.enabled = False if os.environ.get('JUPYTERHUB_SERVICE_PREFIX'): diff --git a/base/passwd.template b/base/passwd.template new file mode 100644 index 0000000000000000000000000000000000000000..bb42cf7afc363193bab1ddbab51a1d8b76341105 --- /dev/null +++ b/base/passwd.template @@ -0,0 +1,14 @@ +root:x:0:0:root:/root:/bin/bash +bin:x:1:1:bin:/bin:/sbin/nologin +daemon:x:2:2:daemon:/sbin:/sbin/nologin +adm:x:3:4:adm:/var/adm:/sbin/nologin +lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin +sync:x:5:0:sync:/sbin:/bin/sync +shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown +halt:x:7:0:halt:/sbin:/sbin/halt +mail:x:8:12:mail:/var/spool/mail:/sbin/nologin +operator:x:11:0:operator:/root:/sbin/nologin +games:x:12:100:games:/usr/games:/sbin/nologin +ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin +nobody:x:99:99:Nobody:/:/sbin/nologin +${USER}:x:${USER_ID}:${GROUP_ID}:${USER_DESCRIPTION}:${HOME}:/bin/bash \ No newline at end of file diff --git a/base/requirements.tvb.txt b/base/requirements.tvb.txt deleted file mode 100644 index 1e3a06834e52f63f7f592a1b519bf2c68cd8ba8e..0000000000000000000000000000000000000000 --- a/base/requirements.tvb.txt +++ /dev/null @@ -1,2 +0,0 @@ -gdist==1.0.3 -tvb-library==2.0 \ No newline at end of file diff --git a/base/requirements.txt b/base/requirements.txt index 3de215cdde9051b62abaa26b000d94c432a28bfe..f4e10a51dbfa23adc3ef44ba67e80222e4231c70 100644 --- a/base/requirements.txt +++ b/base/requirements.txt @@ -1,45 +1,49 @@ -beautifulsoup4==4.8.2 -bluepyopt==1.9.12 -bokeh==1.4.0 -Cython==0.29.15 -cryptography==3.3.2 -elephant==0.6.4 -h5py==2.10.0 -ipympl==0.5.8 -ipywidgets==7.5.1 -jupyterhub==1.1.0 -jupyterlab==1.2.6 -jupyterlab-git==0.9.0 -lazyarray==0.3.3 -lxml==4.5.0 -matplotlib==3.3.1 -mpi4py==3.0.3 -nbdime==1.1.0 -nbgitpuller==0.9.0 -nbresuse==0.3.3 -neo==0.8.0 -neurom==1.4.14 -nglview==2.7.1 -nibabel==3.0.1 -numba==0.48.0 -numexpr==2.7.1 -numpy==1.18.1 -pandas==1.0.1 -patsy==0.5.1 -plotly==4.5.1 -python-swiftclient==3.9.0 -PyJWT==1.7.1 -pyunicore==0.5.7 +beautifulsoup4==4.10.0 +bluepyopt==1.11.5 +bokeh==2.4.2 +Cython==0.29.26 +cffi==1.14.5 +cryptography==36.0.1 +elephant==0.10.0 +h5py==3.6.0 +ipympl==0.8.5 +ipywidgets==7.6.5 +jupyterhub==1.5.0 +jupyterlab==3.2.8 +jupyterlab-git==0.34.1 +lazyarray==0.5.1 +lxml==4.7.1 +matplotlib==3.5.1 +mpi4py==3.1.3 +nbdime==3.1.1 +nbgitpuller==1.0.2 +nbresuse==0.4.0 +neo==0.10.0 +neurom==3.1.0 +nglview==3.0.3 +nibabel==3.2.1 +numba==0.54.1 +numexpr==2.8.1 +numpy==1.20.3 +pandas==1.3.5 +patsy==0.5.2 +plotly==5.5.0 +Pygments==2.11.2 +python-swiftclient==3.13.0 +PyJWT==2.3.0 +pyunicore==0.9.13 requests-oauthlib==1.3.0 -rise==5.6.1 +rise==5.7.1 rpy2==3.4.5 -scikit-image==0.16.2 -scikit-learn==0.22.1 -scipy==1.4.1 -seaborn==0.10.0 -statsmodels==0.11.1 -sympy==1.5.1 +scikit-image==0.19.1 +scikit-learn==1.0.2 +scipy==1.7.3 +seaborn==0.11.2 +statsmodels==0.13.1 +sympy==1.9 vincent==0.4.4 -widgetsnbextension==3.5.1 -xlrd==1.2.0 +widgetsnbextension==3.5.2 +xlrd==2.0.1 git+https://github.com/HumanBrainProject/clb-nb-utils.git +# fix issue with nbconvert in jupyter_server version installed by jupyterlab dependency (remove once fixed in offical release) +git+https://github.com/jupyter-server/jupyter_server.git@d2015290b80bfdaa6ebb990cdccc0155921696f5 \ No newline at end of file diff --git a/base/start-notebook.sh b/base/start-notebook.sh new file mode 100644 index 0000000000000000000000000000000000000000..028dbe57c849c0fc3d51451c0e4b8e603c048d9a --- /dev/null +++ b/base/start-notebook.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -e +# to support OpenShift's arbitrary UIDs +# more info: https://docs.openshift.com/enterprise/3.1/creating_images/guidelines.html +export USER_ID=$(id -u) +export GROUP_ID=$(id -g) +export USER_DESCRIPTION="Notebook User" +envsubst < /tmp/passwd.template > /tmp/passwd +envsubst < /tmp/group.template > /tmp/group +export LD_PRELOAD=libnss_wrapper.so +export NSS_WRAPPER_PASSWD=/tmp/passwd +export NSS_WRAPPER_GROUP=/tmp/group +exec jupyter labhub --NotebookApp.default_url=/lab --config=/opt/app-root/etc/jupyter_notebook_config.py $@