diff --git a/docker/jupyterlab/README.md b/docker/jupyterlab/README.md new file mode 100644 index 0000000..b31e878 --- /dev/null +++ b/docker/jupyterlab/README.md @@ -0,0 +1,4 @@ +# Content + +Container recipes derived from the Jupyter Docker Stacks at https://jupyter-docker-stacks.readthedocs.io + diff --git a/docker/jupyterlab/jupyterlab-SurfaceTopography/Dockerfile b/docker/jupyterlab/jupyterlab-SurfaceTopography/Dockerfile new file mode 100644 index 0000000..50ecdfd --- /dev/null +++ b/docker/jupyterlab/jupyterlab-SurfaceTopography/Dockerfile @@ -0,0 +1,63 @@ +# Build from within repository root +# +# Modify conda enviornment running jupyter notebooks +FROM jupyter/minimal-notebook:latest + +USER root + +COPY --chown=${NB_UID}:${NB_GID} jupyterlab-SurfaceTopography/conda-requirements.in "/home/${NB_USER}/" +RUN pip install pip-tools +RUN pip-compile "/home/${NB_USER}/conda-requirements.in" > "/home/${NB_USER}/conda-requirements.txt" +RUN pip install --quiet --no-cache-dir --requirement "/home/${NB_USER}/conda-requirements.txt" && \ + fix-permissions "${CONDA_DIR}" && \ + fix-permissions "/home/${NB_USER}" + +# FROM imkteksim/dtool-jupyter:latest +# Install from requirements.txt file +RUN apt-get --yes update && \ + apt-get --yes install \ + clang cmake curl g++ gdb git m4 wget \ + libboost-test-dev \ + libcurl4-openssl-dev \ + libeigen3-dev \ + libfftw3-dev \ + libgmp-dev \ + libnetcdf-dev \ + libopenblas-base \ + libopenblas-dev \ + python3-pip \ + python3-dev \ + python3-netcdf4 && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Workaround for building packages and introducing an ipykernel outside of the jupyterlab conda environment +RUN PATH=$(echo "$PATH" | sed -e 's|/opt/conda[^:]*:||g') && ( \ + pip install --no-binary numpy SurfaceTopography && \ + pip install ipykernel && \ + python3 -m ipykernel install --name SurfaceTopography --display-name "Python (SurfaceTopography)") && \ + fix-permissions "${CONDA_DIR}" && \ + fix-permissions "/home/${NB_USER}" + +# Workaround for modifying system python outside of the jupyterlab conda environment +COPY --chown=${NB_UID}:${NB_GID} jupyterlab-SurfaceTopography/requirements.txt "/home/${NB_USER}/" +RUN PATH="$(echo "$PATH" | sed -e 's|/opt/conda[^:]*:||g')" && ( \ + pip install --quiet --no-cache-dir --requirement "/home/${NB_USER}/requirements.txt" ) + +COPY jupyterlab-SurfaceTopography/start-wrapper.sh /usr/local/bin/ + +# Custom fonts config +COPY jupyterlab-SurfaceTopography/etc/fonts.conf /etc/fonts/conf.avail/99-injected.conf +RUN ln -s /etc/fonts/conf.avail/99-injected.conf /etc/fonts/conf.d/99-injected.conf +RUN mkdir -p /fonts + +# Install from requirements.txt file +RUN apt-get --yes update && \ + apt-get --yes install fontconfig && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +WORKDIR /home/${NB_USER}/work +USER ${NB_UID} + +CMD ["start-wrapper.sh", "start-notebook.sh"] diff --git a/docker/jupyterlab/jupyterlab-SurfaceTopography/README.md b/docker/jupyterlab/jupyterlab-SurfaceTopography/README.md new file mode 100644 index 0000000..7af3aff --- /dev/null +++ b/docker/jupyterlab/jupyterlab-SurfaceTopography/README.md @@ -0,0 +1,161 @@ +# Sample setup jupyterlab-SurfaceTopography + +## Changes to the container + +This docker image bases on the [Jupyter Docker Stacks](https://jupyter-docker-stacks.readthedocs.io/en/latest/). +These base images use condato run a JupyterLab instance. Extensions to the Jupyter ecosystem (i.e. `jupytext`) +must hence go into the `conda-requirements.in` file. + +`SurfaceTopography` does not work well within a conda environment. Instead, this image introduces a separate +ipython kernel `SurfaceTopography` that just uses the container-internal system Python and a few system libraries, +i.e. `numpy`. Anything needed for production in connection with `SurfaceTopography` goes in `requirements.in` or +into `requirements.txt` directly. When modifying `requirements.in`, regenerate `requirments.txt`with pinned versions +as described below. + +If in need to quickly modify the `SurfaceTopography` kernel environment at runtime, pay attention to +breaking out of the default conda enviornment in the shell + +* `conda deactivate`, and +* removing any conda-related artifacts from the `$PATH`, i.e. with `export PATH=$(echo "$PATH" | sed -e 's|/opt/conda[^:]*:||g')` + +The latter is necessary to avoid conda compiler interfering with custom build steps when compiling against system libraries. + +## Python requirements + +To (re-)generate a `requirements.txt` with fixed package versions, use + +```console +python3 -m venv venv +source venv/bin/activate + +pip install --upgrade pip +pip install wheel +pip install pip-tools + +pip-compile requirements.in > requirements.txt +``` + +## Build container + +Build container from parent directory (`docker/jupyterlab`) with + + docker build -t imteksim/jupyterlab-surfacetopography -f jupyterlab-SurfaceTopography/Dockerfile . + +or write directly to tar for transfer with + + docker build --output type=tar,dest=imteksim-jupyterlab-SurfaceTopography.tar -t imteksim/jupyterlab-surfacetopography -f jupyterlab-SurfaceTopography/Dockerfile . + +and load at target destination with + + docker load --input imteksim-jupyterlab-SurfaceTopography.tar + +## Certificates with acme.sh + +Identify the public hostname used for issuing SSL certificates, i.e. + + export HOSTNAME="SOME-UUID.fr.bw-cloud-instance.org" + +for a public bw-cloud instance and a seecure directory to hold certificates, i.e. + + export CERTDIR=${HOME}/acme.sh + +and use + + mkdir -p acme.sh + + # zerossl + docker run -v "${CERTDIR}:/acme.sh" --rm neilpang/acme.sh:latest \ + acme.sh --register-account -m ${MY_EMAIL_ADDRESS} + docker run -v "${CERTDIR}:/acme.sh" -p 80:80 --rm neilpang/acme.sh:latest \ + acme.sh --issue -d "${HOSTNAME}" --standalone --force + + # or, letsencrypt + docker run -v "${CERTDIR}:/acme.sh" --rm neilpang/acme.sh:latest \ + acme.sh --server letsencrypt --register-account -m ${MY_EMAIL_ADDRESS} + docker run -v "${CERTDIR}:/acme.sh" -p 80:80 --rm neilpang/acme.sh:latest \ + acme.sh --server letsencrypt --issue -d "${HOSTNAME}" --standalone --force + + sudo chown -R $USER:$USER $HOME/acme.sh + +to (re-)issue certiicates. + +## Fonts + +Microsoft fonts can be installed with + + sudo apt-get install -y fontconfig + sudo apt-get install -y ttf-mscorefonts-installer + sudo fc-cache -f + +Check with + + $ fc-match Arial + LiberationSans-Regular.ttf: "Liberation Sans" "Regular" + +Find location of installed fonts with + + $ dpkg-query -L ttf-mscorefonts-installer + /. + /usr + /usr/lib + /usr/lib/msttcorefonts + /usr/lib/msttcorefonts/update-ms-fonts + /usr/share + /usr/share/doc + /usr/share/doc/ttf-mscorefonts-installer + /usr/share/doc/ttf-mscorefonts-installer/README.Debian + /usr/share/doc/ttf-mscorefonts-installer/changelog.gz + /usr/share/doc/ttf-mscorefonts-installer/copyright + /usr/share/fonts + /usr/share/fonts/truetype + /usr/share/lintian + /usr/share/lintian/overrides + /usr/share/lintian/overrides/ttf-mscorefonts-installer + /usr/share/package-data-downloads + /usr/share/package-data-downloads/ttf-mscorefonts-installer + /var + /var/lib + /var/lib/msttcorefonts + +## Run Jupyter Lab + +Identify a persistent workspace directory, i.e. + + export WORKDIR=${HOME}/work + +and, optionally, a directory of additional fonts to make available to matplotlib, i.e. as above + + export FONTDIR=/usr/share/fonts/truetype/msttcorefonts + +Run public Jupyter Lab on default https port with fixed password + + docker run -d --rm -p 443:443 \ + -v ${WORKDIR}:/home/jovyan/work \ + -v ${FONTDIR}:/fonts \ + -v ${CERTDIR}/${HOSTNAME}:/etc/ssl/notebook \ + imteksim/jupyterlab-surfacetopography \ + start-notebook.sh \ + --ServerApp.keyfile=/etc/ssl/notebook/${HOSTNAME}.key \ + --ServerApp.certfile=/etc/ssl/notebook/${HOSTNAME}.cer \ + --ServerApp.password='argon2:$argon2id$v=19$m=10240,t=10,p=8$Jg1gFoiE0ybmBCVG+1s6uA$Jxz4/1591Z7so7JK2M1lRA' \ + --ServerApp.ip='*' \ + --ServerApp.port=443 + +Note that the hash of the password is passed. + + argon2:$argon2id$v=19$m=10240,t=10,p=8$Jg1gFoiE0ybmBCVG+1s6uA$Jxz4/1591Z7so7JK2M1lRA + +corresponds to password `imtek-simulation` and has been generated with + + from notebook.auth import passwd + passwd() + +Add + + --user root -e GRANT_SUDO=yes -e NB_GID=100 -e NB_USER=jovyan + +to the docker command line arguments if you need passwordless `sudo` within the container. + +## Access Jupyter Lab web interface + +Make sure `https` port 443 is reachable, navigate browser to `https://${HOSTNAME}` and log in with password specified on Jupyter Lab launch. diff --git a/docker/jupyterlab/jupyterlab-SurfaceTopography/conda-requirements.in b/docker/jupyterlab/jupyterlab-SurfaceTopography/conda-requirements.in new file mode 100644 index 0000000..b8384fb --- /dev/null +++ b/docker/jupyterlab/jupyterlab-SurfaceTopography/conda-requirements.in @@ -0,0 +1,2 @@ +jupyterlab_autorun_cells +jupytext diff --git a/docker/jupyterlab/jupyterlab-SurfaceTopography/etc/fonts.conf b/docker/jupyterlab/jupyterlab-SurfaceTopography/etc/fonts.conf new file mode 100644 index 0000000..0a2f35e --- /dev/null +++ b/docker/jupyterlab/jupyterlab-SurfaceTopography/etc/fonts.conf @@ -0,0 +1,6 @@ + + + + +/fonts + diff --git a/docker/jupyterlab/jupyterlab-SurfaceTopography/requirements.in b/docker/jupyterlab/jupyterlab-SurfaceTopography/requirements.in new file mode 100644 index 0000000..33cc704 --- /dev/null +++ b/docker/jupyterlab/jupyterlab-SurfaceTopography/requirements.in @@ -0,0 +1,36 @@ +click +pep517 +tomli +adhesion +ase +asgiref +contactmechanics +cycler +dtool +dtool_lookup_api +dtoolcore +dtool-s3 +gromacs +GromacsWrapper +imteksimfw +ipython +ipywidgets +Jinja2 +matplotlib +MDAnalysis +miniball +nglview +numpy +openpyxl +ovito<=3.6.0 +pandas +panedr +ParmEd +pymongo +pytest +PySide2 +PyYAML +scipy +scikit-learn +seaborn +git+https://github.com/IMTEK-Simulation/code-snippets.git diff --git a/docker/jupyterlab/jupyterlab-SurfaceTopography/requirements.txt b/docker/jupyterlab/jupyterlab-SurfaceTopography/requirements.txt new file mode 100644 index 0000000..d87e00b --- /dev/null +++ b/docker/jupyterlab/jupyterlab-SurfaceTopography/requirements.txt @@ -0,0 +1,503 @@ +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile requirements.in +# +adhesion==0.90.0 + # via -r requirements.in +aiohttp==3.8.3 + # via dtool-lookup-api +aiosignal==1.3.1 + # via aiohttp +arrow==1.2.3 + # via jinja2-time +ase==3.22.1 + # via -r requirements.in +asgiref==3.5.2 + # via + # -r requirements.in + # dtool-lookup-api +asttokens==2.1.0 + # via stack-data +async-timeout==4.0.2 + # via aiohttp +attrs==22.1.0 + # via + # aiohttp + # pytest +backcall==0.2.0 + # via ipython +bcrypt==4.0.1 + # via paramiko +biopython==1.79 + # via mdanalysis +boto3==1.26.5 + # via dtool-s3 +botocore==1.29.5 + # via + # boto3 + # s3transfer +certifi==2022.9.24 + # via requests +cffi==1.15.1 + # via + # cryptography + # pynacl +charset-normalizer==2.1.1 + # via + # aiohttp + # requests +click==8.1.3 + # via + # -r requirements.in + # click-plugins + # dtool-annotation + # dtool-cli + # dtool-config + # dtool-create + # dtool-info + # dtool-overlay + # dtool-s3 + # dtool-tag + # flask +click-plugins==1.1.1 + # via dtool-cli +contactmechanics==1.0.0 + # via + # -r requirements.in + # adhesion +contourpy==1.0.6 + # via matplotlib +cryptography==38.0.3 + # via paramiko +cycler==0.11.0 + # via + # -r requirements.in + # matplotlib +debugpy==1.6.3 + # via ipykernel +decorator==5.1.1 + # via ipython +defusedxml==0.7.1 + # via surfacetopography +dill==0.3.6 + # via imteksimfw +dnspython==2.2.1 + # via pymongo +dtool==3.26.2 + # via -r requirements.in +dtool-annotation==0.1.1 + # via dtool +dtool-cli==0.7.1 + # via + # dtool + # dtool-annotation + # dtool-create + # dtool-info + # dtool-overlay + # dtool-s3 + # dtool-tag +dtool-config==0.4.1 + # via dtool +dtool-create==0.23.4 + # via + # dtool + # imteksimfw +dtool-http==0.5.1 + # via + # dtool + # dtool-create +dtool-info==0.16.2 + # via dtool +dtool-lookup-api==0.5.1 + # via + # -r requirements.in + # imteksimfw +dtool-overlay==0.3.1 + # via dtool +dtool-s3==0.14.1 + # via -r requirements.in +dtool-symlink==0.3.1 + # via + # dtool + # dtool-create +dtool-tag==0.1.1 + # via dtool +dtoolcore==3.18.2 + # via + # -r requirements.in + # dtool + # dtool-annotation + # dtool-cli + # dtool-config + # dtool-create + # dtool-http + # dtool-info + # dtool-lookup-api + # dtool-overlay + # dtool-s3 + # dtool-symlink + # dtool-tag +entrypoints==0.4 + # via jupyter-client +et-xmlfile==1.1.0 + # via openpyxl +exceptiongroup==1.0.1 + # via pytest +executing==1.2.0 + # via stack-data +fasteners==0.18 + # via mdanalysis +fireworks==2.0.3 + # via imteksimfw +flask==2.2.2 + # via + # fireworks + # flask-paginate +flask-paginate==2022.1.8 + # via fireworks +fonttools==4.38.0 + # via matplotlib +frozenlist==1.3.3 + # via + # aiohttp + # aiosignal +griddataformats==1.0.1 + # via mdanalysis +gromacs==0.0.0 + # via -r requirements.in +gromacswrapper==0.8.2 + # via -r requirements.in +gsd==2.6.1 + # via mdanalysis +gunicorn==20.1.0 + # via fireworks +h5py==3.7.0 + # via surfacetopography +idna==3.4 + # via + # requests + # yarl +igor==0.3 + # via surfacetopography +importlib-metadata==5.0.0 + # via flask +imteksimcs @ git+https://github.com/IMTEK-Simulation/code-snippets.git + # via -r requirements.in +imteksimfw==0.5.1 + # via -r requirements.in +iniconfig==1.1.1 + # via pytest +ipykernel==6.17.0 + # via ipywidgets +ipython==8.6.0 + # via + # -r requirements.in + # ipykernel + # ipywidgets +ipywidgets==8.0.2 + # via + # -r requirements.in + # nglview +itsdangerous==2.1.2 + # via flask +jedi==0.18.1 + # via ipython +jinja2==3.1.2 + # via + # -r requirements.in + # dtool-info + # fireworks + # flask + # imteksimfw + # jinja2-time +jinja2-time==0.2.0 + # via imteksimfw +jmespath==1.0.1 + # via + # boto3 + # botocore +joblib==1.2.0 + # via + # mdanalysis + # scikit-learn +jupyter-client==7.4.4 + # via ipykernel +jupyter-core==5.0.0 + # via jupyter-client +jupyterlab-widgets==3.0.3 + # via + # ipywidgets + # nglview +kiwisolver==1.4.4 + # via matplotlib +markupsafe==2.1.1 + # via + # jinja2 + # werkzeug +matplotlib==3.6.2 + # via + # -r requirements.in + # ase + # gromacswrapper + # mdanalysis + # seaborn + # surfacetopography +matplotlib-inline==0.1.6 + # via + # ipykernel + # ipython +mdanalysis==2.3.0 + # via -r requirements.in +miniball==1.1.0 + # via -r requirements.in +mmtf-python==1.1.3 + # via mdanalysis +monty==2022.9.9 + # via + # fireworks + # imteksimfw +mrcfile==1.4.3 + # via griddataformats +msgpack==1.0.4 + # via mmtf-python +mufft==0.23.1 + # via + # adhesion + # contactmechanics + # surfacetopography +multidict==6.0.2 + # via + # aiohttp + # yarl +nest-asyncio==1.5.6 + # via + # ipykernel + # jupyter-client +networkx==2.8.8 + # via mdanalysis +nglview==3.0.3 + # via -r requirements.in +numkit==1.2.2 + # via gromacswrapper +numpi==0.3.1 + # via + # adhesion + # contactmechanics + # surfacetopography +numpy==1.23.4 + # via + # -r requirements.in + # adhesion + # ase + # biopython + # contactmechanics + # contourpy + # griddataformats + # gromacswrapper + # gsd + # h5py + # imteksimcs + # matplotlib + # mdanalysis + # miniball + # mrcfile + # mufft + # nglview + # numkit + # numpi + # numpyencoder + # ovito + # pandas + # pyedr + # scikit-learn + # scipy + # seaborn + # surfacetopography +numpyencoder==0.3.0 + # via surfacetopography +openpyxl==3.0.10 + # via -r requirements.in +ovito==3.6.0 + # via -r requirements.in +packaging==21.3 + # via + # dtool-s3 + # ipykernel + # matplotlib + # mdanalysis + # pytest +pandas==1.5.1 + # via + # -r requirements.in + # imteksimcs + # panedr + # seaborn +panedr==0.7.0 + # via -r requirements.in +paramiko==2.12.0 + # via imteksimfw +parmed==3.4.3 + # via -r requirements.in +parse==1.19.0 + # via dtool-overlay +parso==0.8.3 + # via jedi +pbr==5.11.0 + # via + # panedr + # pyedr +pep517==0.13.0 + # via -r requirements.in +pexpect==4.8.0 + # via ipython +pickleshare==0.7.5 + # via ipython +pillow==9.3.0 + # via + # matplotlib + # surfacetopography +platformdirs==2.5.3 + # via jupyter-core +pluggy==1.0.0 + # via pytest +prompt-toolkit==3.0.32 + # via ipython +psutil==5.9.4 + # via ipykernel +ptyprocess==0.7.0 + # via pexpect +pure-eval==0.2.2 + # via stack-data +pycparser==2.21 + # via cffi +pyedr==0.7.0 + # via panedr +pygments==2.13.0 + # via + # dtool-info + # ipython +pymongo==4.3.2 + # via + # -r requirements.in + # fireworks +pynacl==1.5.0 + # via paramiko +pyparsing==3.0.9 + # via + # matplotlib + # packaging +pyside2==5.15.2.1 + # via + # -r requirements.in + # ovito +pytest==7.2.0 + # via -r requirements.in +python-dateutil==2.8.2 + # via + # arrow + # botocore + # fireworks + # jupyter-client + # matplotlib + # pandas + # surfacetopography +pytz==2022.6 + # via pandas +pyyaml==6.0 + # via + # -r requirements.in + # dtool-lookup-api + # surfacetopography +pyzmq==24.0.1 + # via + # ipykernel + # jupyter-client +requests==2.28.1 + # via + # dtool-http + # surfacetopography +ruamel-yaml==0.17.21 + # via + # dtool-create + # fireworks + # imteksimfw +ruamel-yaml-clib==0.2.7 + # via ruamel-yaml +s3transfer==0.6.0 + # via boto3 +scikit-learn==1.1.3 + # via -r requirements.in +scipy==1.9.3 + # via + # -r requirements.in + # ase + # griddataformats + # imteksimcs + # mdanalysis + # numkit + # scikit-learn +seaborn==0.12.1 + # via -r requirements.in +shiboken2==5.15.2.1 + # via pyside2 +six==1.16.0 + # via + # asttokens + # fireworks + # gromacswrapper + # imteksimfw + # numkit + # paramiko + # python-dateutil +stack-data==0.6.0 + # via ipython +surfacetopography==1.1 + # via + # adhesion + # contactmechanics +tabulate==0.9.0 + # via fireworks +threadpoolctl==3.1.0 + # via + # mdanalysis + # scikit-learn +tomli==2.0.1 + # via + # -r requirements.in + # pep517 + # pytest +tornado==6.2 + # via + # ipykernel + # jupyter-client +tqdm==4.64.1 + # via + # fireworks + # mdanalysis +traitlets==5.5.0 + # via + # ipykernel + # ipython + # ipywidgets + # jupyter-client + # jupyter-core + # matplotlib-inline +urllib3==1.26.12 + # via + # botocore + # requests +wcwidth==0.2.5 + # via prompt-toolkit +werkzeug==2.2.2 + # via flask +widgetsnbextension==4.0.3 + # via ipywidgets +yarl==1.8.1 + # via aiohttp +zipp==3.10.0 + # via importlib-metadata + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/docker/jupyterlab/jupyterlab-SurfaceTopography/start-wrapper.sh b/docker/jupyterlab/jupyterlab-SurfaceTopography/start-wrapper.sh new file mode 100755 index 0000000..67c2320 --- /dev/null +++ b/docker/jupyterlab/jupyterlab-SurfaceTopography/start-wrapper.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -e + +# delete and rebuild matplotlib font cache +# rm -rf /home/${NB_USER}/.cache/matplotlib +fc-cache --force +PATH=$(echo "$PATH" | sed -e 's|/opt/conda[^:]*:||g') python3 -c 'import matplotlib.font_manager; matplotlib.font_manager._load_fontmanager(try_read_cache=False)' + +echo +echo "matplotlib cache dir:" +echo +PATH=$(echo "$PATH" | sed -e 's|/opt/conda[^:]*:||g') python3 -c "import matplotlib; print(matplotlib.get_cachedir())" +echo +echo "matplotlib fonts:" +echo +PATH=$(echo "$PATH" | sed -e 's|/opt/conda[^:]*:||g') python3 -c "import matplotlib.font_manager ; [print(f) for f in matplotlib.font_manager.findSystemFonts(fontpaths=None)]" +echo +exec "$@"