Skip to content

Commit

Permalink
Merge pull request #8 from guimou/cuda-monai
Browse files Browse the repository at this point in the history
Monai + Streamlit 1.10.0
  • Loading branch information
guimou authored Jun 25, 2022
2 parents 4b4cffe + ecd644c commit 416a91f
Show file tree
Hide file tree
Showing 74 changed files with 10,150 additions and 207 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ node_modules/
*.egg-info/
.ipynb_checkpoints
*.tsbuildinfo
*.lock
__pycache__

# Ensure embedme does not run ont node_modules README.md files.
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ Nothing there!

### Added

- New notebook image: CUDA 11.6.2 + Monai 0.9.0 + Streamlit 1.10.0 notebook (quay.io/guimou/s2i-monai-notebook:0.0.2)

### Modified

- Streamlit image updated to streamlit 1.10.0 - fixes #5
- fix Streamlit launch scripts for directory context - fixes #6
- new streamlit image: quay.io/guimou/s2i-generic-data-science-streamlit-notebook:0.0.7

## [0.0.10] - 2022-06-22

### Added

- nbgitpuller added to Streamlit notebook (quay.io/guimou/s2i-generic-data-science-streamlit-notebook:0.0.6)

### Modified
Expand Down
16 changes: 16 additions & 0 deletions monai-notebook/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Monai Notebook

Custom notebook based on RHODS standard data science notebook, adding:

* CUDA, which is a requirement for Monai.

* [Monai](https://monai.io/) ([Github repo](https://github.com/Project-MONAI))

MONAI is a freely available, community-supported, PyTorch-based framework for deep learning in healthcare imaging. It provides domain-optimized foundational capabilities for developing healthcare imaging training workflows in a native PyTorch paradigm.
Project MONAI also includes MONAI Label, an intelligent open source image labeling and learning tool that helps researchers and clinicians collaborate, create annotated datasets, and build AI models in a standardized MONAI paradigm.

* [Streamlit](https://streamlit.io/) ([Github repo](https://github.com/streamlit/streamlit))

Streamlit turns data scripts into shareable web apps in minutes.
All in pure Python. No front‑end experience required.
See [details on Streamlit implementation](../streamlit-notebook/README.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Set current user in nss_wrapper
USER_ID=$(id -u)
GROUP_ID=$(id -g)

if [ x"$USER_ID" != x"0" -a x"$USER_ID" != x"1001" ]; then

NSS_WRAPPER_PASSWD=/opt/app-root/etc/passwd
NSS_WRAPPER_GROUP=/etc/group

cat /etc/passwd | sed -e 's/^default:/builder:/' > $NSS_WRAPPER_PASSWD

echo "default:x:${USER_ID}:${GROUP_ID}:Default Application User:${HOME}:/sbin/nologin" >> $NSS_WRAPPER_PASSWD

export NSS_WRAPPER_PASSWD
export NSS_WRAPPER_GROUP

LD_PRELOAD=libnss_wrapper.so
export LD_PRELOAD
fi
9 changes: 9 additions & 0 deletions monai-notebook/container/3.9/root/opt/app-root/etc/scl_enable
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# IMPORTANT: Do not add more content to this file unless you know what you are
# doing. This file is sourced everytime the shell session is opened.
# This will make scl collection binaries work out of box.
unset BASH_ENV PROMPT_COMMAND ENV
if head "/etc/redhat-release" | grep -q "^CentOS Linux release 7" || \
head "/etc/redhat-release" | grep -q "^Red Hat Enterprise Linux\( Server\)\? release 7"; then
source scl_source enable httpd24 $NODEJS_SCL rh-python39
fi
source /opt/app-root/bin/activate
Binary file not shown.
77 changes: 77 additions & 0 deletions monai-notebook/container/3.9/s2i/bin/assemble
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/bin/bash

# Thoth patch already applied

function is_django_installed() {
python -c "import django" &>/dev/null
}

function should_collectstatic() {
is_django_installed && [[ -z "$DISABLE_COLLECTSTATIC" ]]
}

function virtualenv_bin() {
# New versions of Python (>3.6) should use venv module
# from stdlib instead of virtualenv package
python3.9 -m venv $1
}

set -e

shopt -s dotglob
echo "---> Installing application source ..."
mv /tmp/src/* "$HOME"

# set permissions for any installed artifacts
fix-permissions /opt/app-root -P

if [[ ! -z "$UPGRADE_PIP_TO_LATEST" ]]; then
echo "---> Upgrading pip, setuptools and wheel to latest version ..."
if ! pip install -U pip setuptools wheel; then
echo "WARNING: Installation of the latest pip, setuptools and wheel failed, trying again from official PyPI with pip --isolated install"
pip install --isolated -U pip setuptools wheel
fi
fi

if [[ -z "$PIP_INDEX_URL" ]]; then
thamos install
else
pip install -r requirements.txt
fi

if [[ ( -f setup.py || -f setup.cfg ) && -z "$DISABLE_SETUP_PY_PROCESSING" ]]; then
echo "---> Installing application ..."
pip install .
fi

if should_collectstatic; then
(
echo "---> Collecting Django static files ..."

APP_HOME=$(readlink -f "${APP_HOME:-.}")
# Change the working directory to APP_HOME
PYTHONPATH="$(pwd)${PYTHONPATH:+:$PYTHONPATH}"
cd "$APP_HOME"

# Look for 'manage.py' in the current directory
manage_file=./manage.py

if [[ ! -f "$manage_file" ]]; then
echo "WARNING: seems that you're using Django, but we could not find a 'manage.py' file."
echo "'manage.py collectstatic' ignored."
exit
fi

if ! python $manage_file collectstatic --dry-run --noinput &> /dev/null; then
echo "WARNING: could not run 'manage.py collectstatic'. To debug, run:"
echo " $ python $manage_file collectstatic --noinput"
echo "Ignore this warning if you're not serving static files with Django."
exit
fi

python $manage_file collectstatic --noinput
)
fi

# set permissions for any installed artifacts
fix-permissions /opt/app-root -P
18 changes: 18 additions & 0 deletions monai-notebook/container/3.9/s2i/bin/init-wrapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/sh

# Overview of how this script works: http://veithen.io/2014/11/16/sigterm-propagation.html
# Set a trap to kill the main app process when this
# init script receives SIGTERM or SIGINT
trap 'kill -s TERM $PID' TERM INT
# Execute the main application in the background
"$@" &
PID=$!
# wait command always terminates when trap is caught, even if the process hasn't finished yet
wait $PID
# Remove the trap and wait till the app process finishes completely
trap - TERM INT
# We wait again, since the first wait terminates when trap is caught
wait $PID
# Exit with the exit code of the app process
STATUS=$?
exit $STATUS
142 changes: 142 additions & 0 deletions monai-notebook/container/3.9/s2i/bin/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#!/bin/bash
source /opt/app-root/etc/generate_container_user

set -e

function is_gunicorn_installed() {
hash gunicorn &>/dev/null
}

function is_django_installed() {
python -c "import django" &>/dev/null
}

function should_migrate() {
is_django_installed && [[ -z "$DISABLE_MIGRATE" ]]
}

# Guess the number of workers according to the number of cores
function get_default_web_concurrency() {
limit_vars=$(cgroup-limits)
local $limit_vars
if [ -z "${NUMBER_OF_CORES:-}" ]; then
echo 1
return
fi

local max=$((NUMBER_OF_CORES*2))
# Require at least 43 MiB and additional 40 MiB for every worker
local default=$(((${MEMORY_LIMIT_IN_BYTES:-MAX_MEMORY_LIMIT_IN_BYTES}/1024/1024 - 43) / 40))
default=$((default > max ? max : default))
default=$((default < 1 ? 1 : default))
# According to http://docs.gunicorn.org/en/stable/design.html#how-many-workers,
# 12 workers should be enough to handle hundreds or thousands requests per second
default=$((default > 12 ? 12 : default))
echo $default
}

function maybe_run_in_init_wrapper() {
if [[ -z "$ENABLE_INIT_WRAPPER" ]]; then
exec "$@"
else
exec $STI_SCRIPTS_PATH/init-wrapper "$@"
fi
}

APP_HOME=$(readlink -f "${APP_HOME:-.}")
# Change the working directory to APP_HOME
PYTHONPATH="$(pwd)${PYTHONPATH:+:$PYTHONPATH}"
cd "$APP_HOME"

if [ -z "$APP_SCRIPT" ] && [ -z "$APP_FILE" ] && [ -z "$APP_MODULE" ]; then
# Set default values for APP_SCRIPT and APP_FILE only when all three APP_
# variables are not defined by user. This prevents a situation when
# APP_MODULE is defined to app:application but the app.py file is found as the
# APP_FILE and then executed by Python instead of gunicorn.
APP_SCRIPT="app.sh"
APP_SCRIPT_DEFAULT=1
APP_FILE="app.py"
APP_FILE_DEFAULT=1
fi

if [ ! -z "$APP_SCRIPT" ]; then
if [[ -f "$APP_SCRIPT" ]]; then
echo "---> Running application from script ($APP_SCRIPT) ..."
if [[ "$APP_SCRIPT" != /* ]]; then
APP_SCRIPT="./$APP_SCRIPT"
fi
maybe_run_in_init_wrapper "$APP_SCRIPT"
elif [[ -z "$APP_SCRIPT_DEFAULT" ]]; then
echo "ERROR: file '$APP_SCRIPT' not found." && exit 1
fi
fi

if [ ! -z "$APP_FILE" ]; then
if [[ -f "$APP_FILE" ]]; then
echo "---> Running application from Python script ($APP_FILE) ..."
maybe_run_in_init_wrapper python "$APP_FILE"
elif [[ -z "$APP_FILE_DEFAULT" ]]; then
echo "ERROR: file '$APP_FILE' not found." && exit 1
fi
fi

# Look for 'manage.py' in the current directory
manage_file=./manage.py

if should_migrate; then
if [[ -f "$manage_file" ]]; then
echo "---> Migrating database ..."
python "$manage_file" migrate --noinput
else
echo "WARNING: seems that you're using Django, but we could not find a 'manage.py' file."
echo "Skipped 'python manage.py migrate'."
fi
fi

# If not set, use 8080 as the default port
if [ -z "$PORT" ]; then
PORT=8080
fi

if is_gunicorn_installed; then
setup_py=$(find "$HOME" -maxdepth 2 -type f -name 'setup.py' -print -quit)
# Look for wsgi module in the current directory
if [[ -z "$APP_MODULE" && -f "./wsgi.py" ]]; then
APP_MODULE=wsgi
elif [[ -z "$APP_MODULE" && -f "$setup_py" ]]; then
APP_MODULE="$(python "$setup_py" --name)"
fi

if [[ "$APP_MODULE" ]]; then
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-$(get_default_web_concurrency)}

# Default settings for gunicorn if none of the custom are set
if [ -z "$APP_CONFIG" ] && [ -z "$GUNICORN_CMD_ARGS" ]; then
GUNICORN_CMD_ARGS="--bind=0.0.0.0:$PORT --access-logfile=-"
gunicorn_settings_source="default"
else
gunicorn_settings_source="custom"
fi

# Gunicorn can read GUNICORN_CMD_ARGS as an env variable but because this is not
# supported in Gunicorn < 20 we still need for Python 2, we are using arguments directly.
echo "---> Serving application with gunicorn ($APP_MODULE) with $gunicorn_settings_source settings ..."
exec gunicorn "$APP_MODULE" $GUNICORN_CMD_ARGS --config "$APP_CONFIG"
fi
fi

if is_django_installed; then
if [[ -f "$manage_file" ]]; then
echo "---> Serving application with 'manage.py runserver 0.0.0.0:$PORT' ..."
echo "WARNING: this is NOT a recommended way to run you application in production!"
echo "Consider using gunicorn or some other production web server."
maybe_run_in_init_wrapper python "$manage_file" runserver 0.0.0.0:$PORT
else
echo "WARNING: seems that you're using Django, but we could not find a 'manage.py' file."
echo "Skipped 'python manage.py runserver'."
fi
fi

>&2 echo "ERROR: don't know how to run your application."
>&2 echo "Please set either APP_MODULE, APP_FILE or APP_SCRIPT environment variables, or create a file 'app.py' to launch your application."
exit 1
18 changes: 18 additions & 0 deletions monai-notebook/container/3.9/s2i/bin/usage
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/sh

DISTRO=`cat /etc/*-release | grep ^ID= | grep -Po '".*?"' | tr -d '"'`
NAMESPACE=centos
[[ $DISTRO =~ rhel* ]] && NAMESPACE=rhscl

cat <<EOF
This is a S2I python-3.9 ${DISTRO} base image:
There are multiple ways how to run the image, see documentation at:
https://github.com/sclorg/s2i-python-container/blob/master/3.9/README.md
To use it in Openshift, run:
oc new-app python:3.9~https://github.com/sclorg/s2i-python-container.git --context-dir=3.9/test/setup-test-app/
You can then run the resulting image via:
oc get pods
oc exec <pod> -- curl 127.0.0.1:8080
EOF
Loading

0 comments on commit 416a91f

Please sign in to comment.