Unify bash variables usage and add quotes where needed

This commit is contained in:
Ayaz Salikhov
2021-05-26 13:06:10 +03:00
parent e9301f4115
commit 0999f1a36f
26 changed files with 186 additions and 186 deletions

View File

@@ -80,7 +80,7 @@ JupyterLab, where `hostname` is the name of the computer running docker and `tok
token printed in the console. Docker destroys the container after notebook server exit, but any token printed in the console. Docker destroys the container after notebook server exit, but any
files written to `~/work` in the container remain intact on the host. files written to `~/work` in the container remain intact on the host.
docker run --rm -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v "$PWD":/home/jovyan/work jupyter/datascience-notebook:33add21fab64 docker run --rm -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v "${PWD}":/home/jovyan/work jupyter/datascience-notebook:33add21fab64
## Contributing ## Contributing

View File

@@ -19,7 +19,7 @@ RUN apt-get update --yes && \
gcc && \ gcc && \
apt-get clean && rm -rf /var/lib/apt/lists/* apt-get clean && rm -rf /var/lib/apt/lists/*
USER $NB_UID USER ${NB_UID}
# R packages including IRKernel which gets installed globally. # R packages including IRKernel which gets installed globally.
RUN conda install --quiet --yes \ RUN conda install --quiet --yes \

View File

@@ -60,14 +60,14 @@ RUN apt-get update --yes && \
# Configure environment # Configure environment
ENV CONDA_DIR=/opt/conda \ ENV CONDA_DIR=/opt/conda \
SHELL=/bin/bash \ SHELL=/bin/bash \
NB_USER=$NB_USER \ NB_USER="${NB_USER}" \
NB_UID=$NB_UID \ NB_UID=${NB_UID} \
NB_GID=$NB_GID \ NB_GID=${NB_GID} \
LC_ALL=en_US.UTF-8 \ LC_ALL=en_US.UTF-8 \
LANG=en_US.UTF-8 \ LANG=en_US.UTF-8 \
LANGUAGE=en_US.UTF-8 LANGUAGE=en_US.UTF-8
ENV PATH=$CONDA_DIR/bin:$PATH \ ENV PATH="${CONDA_DIR}/bin:${PATH}" \
HOME=/home/$NB_USER \ HOME="/home/${NB_USER}" \
CONDA_VERSION="${conda_version}" \ CONDA_VERSION="${conda_version}" \
MINIFORGE_VERSION="${miniforge_version}" MINIFORGE_VERSION="${miniforge_version}"
@@ -86,18 +86,18 @@ RUN sed -i 's/^#force_color_prompt=yes/force_color_prompt=yes/' /etc/skel/.bashr
RUN echo "auth requisite pam_deny.so" >> /etc/pam.d/su && \ RUN echo "auth requisite pam_deny.so" >> /etc/pam.d/su && \
sed -i.bak -e 's/^%admin/#%admin/' /etc/sudoers && \ sed -i.bak -e 's/^%admin/#%admin/' /etc/sudoers && \
sed -i.bak -e 's/^%sudo/#%sudo/' /etc/sudoers && \ sed -i.bak -e 's/^%sudo/#%sudo/' /etc/sudoers && \
useradd -l -m -s /bin/bash -N -u $NB_UID $NB_USER && \ useradd -l -m -s /bin/bash -N -u "${NB_UID}" "${NB_USER}" && \
mkdir -p $CONDA_DIR && \ mkdir -p "${CONDA_DIR}" && \
chown $NB_USER:$NB_GID $CONDA_DIR && \ chown "${NB_USER}:${NB_GID}" "${CONDA_DIR}" && \
chmod g+w /etc/passwd && \ chmod g+w /etc/passwd && \
fix-permissions "${HOME}" && \ fix-permissions "${HOME}" && \
fix-permissions "${CONDA_DIR}" fix-permissions "${CONDA_DIR}"
USER $NB_UID USER ${NB_UID}
ARG PYTHON_VERSION=default ARG PYTHON_VERSION=default
# Setup work directory for backward-compatibility # Setup work directory for backward-compatibility
RUN mkdir "/home/$NB_USER/work" && \ RUN mkdir "/home/${NB_USER}/work" && \
fix-permissions "/home/${NB_USER}" fix-permissions "/home/${NB_USER}"
# Install conda as jovyan and check the sha256 sum provided on the download site # Install conda as jovyan and check the sha256 sum provided on the download site
@@ -106,20 +106,20 @@ WORKDIR /tmp
# Prerequisites installation: conda, mamba, pip, tini # Prerequisites installation: conda, mamba, pip, tini
RUN wget --quiet "https://github.com/conda-forge/miniforge/releases/download/${miniforge_version}/${miniforge_installer}" && \ RUN wget --quiet "https://github.com/conda-forge/miniforge/releases/download/${miniforge_version}/${miniforge_installer}" && \
echo "${miniforge_checksum} *${miniforge_installer}" | sha256sum --check && \ echo "${miniforge_checksum} *${miniforge_installer}" | sha256sum --check && \
/bin/bash "${miniforge_installer}" -f -b -p $CONDA_DIR && \ /bin/bash "${miniforge_installer}" -f -b -p "${CONDA_DIR}" && \
rm "${miniforge_installer}" && \ rm "${miniforge_installer}" && \
# Conda configuration see https://conda.io/projects/conda/en/latest/configuration.html # Conda configuration see https://conda.io/projects/conda/en/latest/configuration.html
echo "conda ${CONDA_VERSION}" >> $CONDA_DIR/conda-meta/pinned && \ echo "conda ${CONDA_VERSION}" >> "${CONDA_DIR}/conda-meta/pinned" && \
conda config --system --set auto_update_conda false && \ conda config --system --set auto_update_conda false && \
conda config --system --set show_channel_urls true && \ conda config --system --set show_channel_urls true && \
if [ ! $PYTHON_VERSION = 'default' ]; then conda install --yes python=$PYTHON_VERSION; fi && \ if [ ! ${PYTHON_VERSION} = 'default' ]; then conda install --yes python=${PYTHON_VERSION}; fi && \
conda list python | grep '^python ' | tr -s ' ' | cut -d '.' -f 1,2 | sed 's/$/.*/' >> $CONDA_DIR/conda-meta/pinned && \ conda list python | grep '^python ' | tr -s ' ' | cut -d '.' -f 1,2 | sed 's/$/.*/' >> "${CONDA_DIR}/conda-meta/pinned" && \
conda install --quiet --yes \ conda install --quiet --yes \
"conda=${CONDA_VERSION}" \ "conda=${CONDA_VERSION}" \
'pip' && \ 'pip' && \
conda update --all --quiet --yes && \ conda update --all --quiet --yes && \
conda clean --all -f -y && \ conda clean --all -f -y && \
rm -rf /home/$NB_USER/.cache/yarn && \ rm -rf "/home/${NB_USER}/.cache/yarn" && \
fix-permissions "${CONDA_DIR}" && \ fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}" fix-permissions "/home/${NB_USER}"
@@ -137,7 +137,7 @@ RUN conda install --quiet --yes \
npm cache clean --force && \ npm cache clean --force && \
jupyter notebook --generate-config && \ jupyter notebook --generate-config && \
jupyter lab clean && \ jupyter lab clean && \
rm -rf /home/$NB_USER/.cache/yarn && \ rm -rf "/home/${NB_USER}/.cache/yarn" && \
fix-permissions "${CONDA_DIR}" && \ fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}" fix-permissions "/home/${NB_USER}"
@@ -161,6 +161,6 @@ RUN sed -re "s/c.NotebookApp/c.ServerApp/g" \
fix-permissions /etc/jupyter/ fix-permissions /etc/jupyter/
# Switch back to jovyan to avoid accidental container runs as root # Switch back to jovyan to avoid accidental container runs as root
USER $NB_UID USER ${NB_UID}
WORKDIR $HOME WORKDIR "${HOME}"

View File

@@ -2,7 +2,7 @@
# set permissions on a directory # set permissions on a directory
# after any installation, if a directory needs to be (human) user-writable, # after any installation, if a directory needs to be (human) user-writable,
# run this script on it. # run this script on it.
# It will make everything in the directory owned by the group $NB_GID # It will make everything in the directory owned by the group ${NB_GID}
# and writable by that group. # and writable by that group.
# Deployments that want to set a specific user id can preserve permissions # Deployments that want to set a specific user id can preserve permissions
# by adding the `--group-add users` line to `docker run`. # by adding the `--group-add users` line to `docker run`.
@@ -11,14 +11,14 @@
# which would cause massive image explosion # which would cause massive image explosion
# right permissions are: # right permissions are:
# group=$NB_GID # group=${NB_GID}
# AND permissions include group rwX (directory-execute) # AND permissions include group rwX (directory-execute)
# AND directories have setuid,setgid bits set # AND directories have setuid,setgid bits set
set -e set -e
for d in "$@"; do for d in "$@"; do
find "$d" \ find "${d}" \
! \( \ ! \( \
-group "${NB_GID}" \ -group "${NB_GID}" \
-a -perm -g+rwX \ -a -perm -g+rwX \
@@ -26,7 +26,7 @@ for d in "$@"; do
-exec chgrp "${NB_GID}" {} \; \ -exec chgrp "${NB_GID}" {} \; \
-exec chmod g+rwX {} \; -exec chmod g+rwX {} \;
# setuid, setgid *on directories only* # setuid, setgid *on directories only*
find "$d" \ find "${d}" \
\( \ \( \
-type d \ -type d \
-a ! -perm -6000 \ -a ! -perm -6000 \

View File

@@ -14,9 +14,9 @@ if [[ -n "${JUPYTERHUB_API_TOKEN}" ]]; then
exec /usr/local/bin/start-singleuser.sh "$@" exec /usr/local/bin/start-singleuser.sh "$@"
elif [[ -n "${JUPYTER_ENABLE_LAB}" ]]; then elif [[ -n "${JUPYTER_ENABLE_LAB}" ]]; then
# shellcheck disable=SC1091 # shellcheck disable=SC1091
. /usr/local/bin/start.sh $wrapper jupyter lab "$@" . /usr/local/bin/start.sh ${wrapper} jupyter lab "$@"
else else
echo "WARN: Jupyter Notebook deprecation notice https://github.com/jupyter/docker-stacks#jupyter-notebook-deprecation-notice." echo "WARN: Jupyter Notebook deprecation notice https://github.com/jupyter/docker-stacks#jupyter-notebook-deprecation-notice."
# shellcheck disable=SC1091 # shellcheck disable=SC1091
. /usr/local/bin/start.sh $wrapper jupyter notebook "$@" . /usr/local/bin/start.sh ${wrapper} jupyter notebook "$@"
fi fi

View File

@@ -5,37 +5,37 @@
set -e set -e
# set default ip to 0.0.0.0 # set default ip to 0.0.0.0
if [[ "$NOTEBOOK_ARGS $*" != *"--ip="* ]]; then if [[ "${NOTEBOOK_ARGS} $*" != *"--ip="* ]]; then
NOTEBOOK_ARGS="--ip=0.0.0.0 $NOTEBOOK_ARGS" NOTEBOOK_ARGS="--ip=0.0.0.0 ${NOTEBOOK_ARGS}"
fi fi
# handle some deprecated environment variables # handle some deprecated environment variables
# from DockerSpawner < 0.8. # from DockerSpawner < 0.8.
# These won't be passed from DockerSpawner 0.9, # These won't be passed from DockerSpawner 0.9,
# so avoid specifying --arg=empty-string # so avoid specifying --arg=empty-string
if [ -n "$NOTEBOOK_DIR" ]; then if [ -n "${NOTEBOOK_DIR}" ]; then
# shellcheck disable=SC2089 # shellcheck disable=SC2089
NOTEBOOK_ARGS="--notebook-dir='$NOTEBOOK_DIR' $NOTEBOOK_ARGS" NOTEBOOK_ARGS="--notebook-dir='${NOTEBOOK_DIR}' ${NOTEBOOK_ARGS}"
fi fi
if [ -n "$JPY_PORT" ]; then if [ -n "${JPY_PORT}" ]; then
NOTEBOOK_ARGS="--port=$JPY_PORT $NOTEBOOK_ARGS" NOTEBOOK_ARGS="--port=${JPY_PORT} ${NOTEBOOK_ARGS}"
fi fi
if [ -n "$JPY_USER" ]; then if [ -n "${JPY_USER}" ]; then
NOTEBOOK_ARGS="--user=$JPY_USER $NOTEBOOK_ARGS" NOTEBOOK_ARGS="--user=${JPY_USER} ${NOTEBOOK_ARGS}"
fi fi
if [ -n "$JPY_COOKIE_NAME" ]; then if [ -n "${JPY_COOKIE_NAME}" ]; then
NOTEBOOK_ARGS="--cookie-name=$JPY_COOKIE_NAME $NOTEBOOK_ARGS" NOTEBOOK_ARGS="--cookie-name=${JPY_COOKIE_NAME} ${NOTEBOOK_ARGS}"
fi fi
if [ -n "$JPY_BASE_URL" ]; then if [ -n "${JPY_BASE_URL}" ]; then
NOTEBOOK_ARGS="--base-url=$JPY_BASE_URL $NOTEBOOK_ARGS" NOTEBOOK_ARGS="--base-url=${JPY_BASE_URL} ${NOTEBOOK_ARGS}"
fi fi
if [ -n "$JPY_HUB_PREFIX" ]; then if [ -n "${JPY_HUB_PREFIX}" ]; then
NOTEBOOK_ARGS="--hub-prefix=$JPY_HUB_PREFIX $NOTEBOOK_ARGS" NOTEBOOK_ARGS="--hub-prefix=${JPY_HUB_PREFIX} ${NOTEBOOK_ARGS}"
fi fi
if [ -n "$JPY_HUB_API_URL" ]; then if [ -n "${JPY_HUB_API_URL}" ]; then
NOTEBOOK_ARGS="--hub-api-url=$JPY_HUB_API_URL $NOTEBOOK_ARGS" NOTEBOOK_ARGS="--hub-api-url=${JPY_HUB_API_URL} ${NOTEBOOK_ARGS}"
fi fi
NOTEBOOK_BIN="jupyterhub-singleuser" NOTEBOOK_BIN="jupyterhub-singleuser"
# shellcheck disable=SC1091,SC2086,SC2090 # shellcheck disable=SC1091,SC2086,SC2090
. /usr/local/bin/start.sh "$NOTEBOOK_BIN" $NOTEBOOK_ARGS "$@" . /usr/local/bin/start.sh "${NOTEBOOK_BIN}" ${NOTEBOOK_ARGS} "$@"

View File

@@ -13,28 +13,28 @@ fi
run-hooks () { run-hooks () {
# Source scripts or run executable files in a directory # Source scripts or run executable files in a directory
if [[ ! -d "$1" ]] ; then if [[ ! -d "${1}" ]] ; then
return return
fi fi
echo "$0: running hooks in $1" echo "${0}: running hooks in ${1}"
for f in "$1/"*; do for f in "${1}/"*; do
case "$f" in case "${f}" in
*.sh) *.sh)
echo "$0: running $f" echo "${0}: running ${f}"
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "$f" source "${f}"
;; ;;
*) *)
if [[ -x "$f" ]] ; then if [[ -x "${f}" ]] ; then
echo "$0: running $f" echo "${0}: running ${f}"
"$f" "${f}"
else else
echo "$0: ignoring $f" echo "${0}: ignoring ${f}"
fi fi
;; ;;
esac esac
done done
echo "$0: done running hooks in $1" echo "${0}: done running hooks in ${1}"
} }
run-hooks /usr/local/bin/start-notebook.d run-hooks /usr/local/bin/start-notebook.d
@@ -44,73 +44,73 @@ if [ "$(id -u)" == 0 ] ; then
# Only attempt to change the jovyan username if it exists # Only attempt to change the jovyan username if it exists
if id jovyan &> /dev/null ; then if id jovyan &> /dev/null ; then
echo "Set username to: $NB_USER" echo "Set username to: ${NB_USER}"
usermod -d "/home/$NB_USER" -l "$NB_USER" jovyan usermod -d "/home/${NB_USER}" -l "${NB_USER}" jovyan
fi fi
# handle home and working directory if the username changed # handle home and working directory if the username changed
if [[ "$NB_USER" != "jovyan" ]]; then if [[ "${NB_USER}" != "jovyan" ]]; then
# changing username, make sure homedir exists # changing username, make sure homedir exists
# (it could be mounted, and we shouldn't create it if it already exists) # (it could be mounted, and we shouldn't create it if it already exists)
if [[ ! -e "/home/$NB_USER" ]]; then if [[ ! -e "/home/${NB_USER}" ]]; then
echo "Relocating home dir to /home/$NB_USER" echo "Relocating home dir to /home/${NB_USER}"
mv /home/jovyan "/home/$NB_USER" || ln -s /home/jovyan "/home/$NB_USER" mv /home/jovyan "/home/${NB_USER}" || ln -s /home/jovyan "/home/${NB_USER}"
fi fi
# if workdir is in /home/jovyan, cd to /home/$NB_USER # if workdir is in /home/jovyan, cd to /home/${NB_USER}
if [[ "$PWD/" == "/home/jovyan/"* ]]; then if [[ "${PWD}/" == "/home/jovyan/"* ]]; then
newcwd="/home/$NB_USER/${PWD:13}" newcwd="/home/${NB_USER}/${PWD:13}"
echo "Setting CWD to $newcwd" echo "Setting CWD to ${newcwd}"
cd "$newcwd" cd "${newcwd}"
fi fi
fi fi
# Handle case where provisioned storage does not have the correct permissions by default # Handle case where provisioned storage does not have the correct permissions by default
# Ex: default NFS/EFS (no auto-uid/gid) # Ex: default NFS/EFS (no auto-uid/gid)
if [[ "$CHOWN_HOME" == "1" || "$CHOWN_HOME" == 'yes' ]]; then if [[ "${CHOWN_HOME}" == "1" || "${CHOWN_HOME}" == 'yes' ]]; then
echo "Changing ownership of /home/$NB_USER to $NB_UID:$NB_GID with options '${CHOWN_HOME_OPTS}'" echo "Changing ownership of /home/${NB_USER} to ${NB_UID}:${NB_GID} with options '${CHOWN_HOME_OPTS}'"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
chown $CHOWN_HOME_OPTS "$NB_UID:$NB_GID" "/home/$NB_USER" chown ${CHOWN_HOME_OPTS} "${NB_UID}:${NB_GID}" "/home/${NB_USER}"
fi fi
if [ -n "$CHOWN_EXTRA" ]; then if [ -n "${CHOWN_EXTRA}" ]; then
for extra_dir in $(echo "$CHOWN_EXTRA" | tr ',' ' '); do for extra_dir in $(echo "${CHOWN_EXTRA}" | tr ',' ' '); do
echo "Changing ownership of ${extra_dir} to $NB_UID:$NB_GID with options '${CHOWN_EXTRA_OPTS}'" echo "Changing ownership of ${extra_dir} to ${NB_UID}:${NB_GID} with options '${CHOWN_EXTRA_OPTS}'"
# shellcheck disable=SC2086 # shellcheck disable=SC2086
chown $CHOWN_EXTRA_OPTS "$NB_UID:$NB_GID" "$extra_dir" chown ${CHOWN_EXTRA_OPTS} "${NB_UID}:${NB_GID}" "${extra_dir}"
done done
fi fi
# Change UID:GID of NB_USER to NB_UID:NB_GID if it does not match # Change UID:GID of NB_USER to NB_UID:NB_GID if it does not match
if [ "$NB_UID" != "$(id -u "$NB_USER")" ] || [ "$NB_GID" != "$(id -g "$NB_USER")" ]; then if [ "${NB_UID}" != "$(id -u "${NB_USER}")" ] || [ "${NB_GID}" != "$(id -g "${NB_USER}")" ]; then
echo "Set user $NB_USER UID:GID to: $NB_UID:$NB_GID" echo "Set user ${NB_USER} UID:GID to: ${NB_UID}:${NB_GID}"
if [ "$NB_GID" != "$(id -g "$NB_USER")" ]; then if [ "${NB_GID}" != "$(id -g "${NB_USER}")" ]; then
groupadd -f -g "$NB_GID" -o "${NB_GROUP:-${NB_USER}}" groupadd -f -g "${NB_GID}" -o "${NB_GROUP:-${NB_USER}}"
fi fi
userdel "$NB_USER" userdel "${NB_USER}"
useradd --home "/home/$NB_USER" -u "$NB_UID" -g "$NB_GID" -G 100 -l "$NB_USER" useradd --home "/home/${NB_USER}" -u "${NB_UID}" -g "${NB_GID}" -G 100 -l "${NB_USER}"
fi fi
# Enable sudo if requested # Enable sudo if requested
if [[ "$GRANT_SUDO" == "1" || "$GRANT_SUDO" == 'yes' ]]; then if [[ "${GRANT_SUDO}" == "1" || "${GRANT_SUDO}" == 'yes' ]]; then
echo "Granting $NB_USER sudo access and appending $CONDA_DIR/bin to sudo PATH" echo "Granting ${NB_USER} sudo access and appending ${CONDA_DIR}/bin to sudo PATH"
echo "$NB_USER ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/notebook echo "${NB_USER} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/notebook
fi fi
# Add $CONDA_DIR/bin to sudo secure_path # Add ${CONDA_DIR}/bin to sudo secure_path
sed -r "s#Defaults\s+secure_path\s*=\s*\"?([^\"]+)\"?#Defaults secure_path=\"\1:$CONDA_DIR/bin\"#" /etc/sudoers | grep secure_path > /etc/sudoers.d/path sed -r "s#Defaults\s+secure_path\s*=\s*\"?([^\"]+)\"?#Defaults secure_path=\"\1:${CONDA_DIR}/bin\"#" /etc/sudoers | grep secure_path > /etc/sudoers.d/path
# Exec the command as NB_USER with the PATH and the rest of # Exec the command as NB_USER with the PATH and the rest of
# the environment preserved # the environment preserved
run-hooks /usr/local/bin/before-notebook.d run-hooks /usr/local/bin/before-notebook.d
echo "Executing the command:" "${cmd[@]}" echo "Executing the command:" "${cmd[@]}"
exec sudo -E -H -u "$NB_USER" PATH="$PATH" XDG_CACHE_HOME="/home/$NB_USER/.cache" PYTHONPATH="${PYTHONPATH:-}" "${cmd[@]}" exec sudo -E -H -u "${NB_USER}" PATH="${PATH}" XDG_CACHE_HOME="/home/${NB_USER}/.cache" PYTHONPATH="${PYTHONPATH:-}" "${cmd[@]}"
else else
if [[ "$NB_UID" == "$(id -u jovyan 2>/dev/null)" && "$NB_GID" == "$(id -g jovyan 2>/dev/null)" ]]; then if [[ "${NB_UID}" == "$(id -u jovyan 2>/dev/null)" && "${NB_GID}" == "$(id -g jovyan 2>/dev/null)" ]]; then
# User is not attempting to override user/group via environment # User is not attempting to override user/group via environment
# variables, but they could still have overridden the uid/gid that # variables, but they could still have overridden the uid/gid that
# container runs as. Check that the user has an entry in the passwd # container runs as. Check that the user has an entry in the passwd
# file and if not add an entry. # file and if not add an entry.
STATUS=0 && whoami &> /dev/null || STATUS=$? && true STATUS=0 && whoami &> /dev/null || STATUS=$? && true
if [[ "$STATUS" != "0" ]]; then if [[ "${STATUS}" != "0" ]]; then
if [[ -w /etc/passwd ]]; then if [[ -w /etc/passwd ]]; then
echo "Adding passwd file entry for $(id -u)" echo "Adding passwd file entry for $(id -u)"
sed -e "s/^jovyan:/nayvoj:/" /etc/passwd > /tmp/passwd sed -e "s/^jovyan:/nayvoj:/" /etc/passwd > /tmp/passwd
@@ -122,24 +122,24 @@ else
fi fi
fi fi
# Warn if the user isn't going to be able to write files to $HOME. # Warn if the user isn't going to be able to write files to ${HOME}.
if [[ ! -w /home/jovyan ]]; then if [[ ! -w /home/jovyan ]]; then
echo 'Container must be run with group "users" to update files' echo 'Container must be run with group "users" to update files'
fi fi
else else
# Warn if looks like user want to override uid/gid but hasn't # Warn if looks like user want to override uid/gid but hasn't
# run the container as root. # run the container as root.
if [[ -n "$NB_UID" && "$NB_UID" != "$(id -u)" ]]; then if [[ -n "${NB_UID}" && "${NB_UID}" != "$(id -u)" ]]; then
echo "Container must be run as root to set NB_UID to $NB_UID" echo "Container must be run as root to set NB_UID to ${NB_UID}"
fi fi
if [[ -n "$NB_GID" && "$NB_GID" != "$(id -g)" ]]; then if [[ -n "${NB_GID}" && "${NB_GID}" != "$(id -g)" ]]; then
echo "Container must be run as root to set NB_GID to $NB_GID" echo "Container must be run as root to set NB_GID to ${NB_GID}"
fi fi
fi fi
# Warn if looks like user want to run in sudo mode but hasn't run # Warn if looks like user want to run in sudo mode but hasn't run
# the container as root. # the container as root.
if [[ "$GRANT_SUDO" == "1" || "$GRANT_SUDO" == 'yes' ]]; then if [[ "${GRANT_SUDO}" == "1" || "${GRANT_SUDO}" == 'yes' ]]; then
echo 'Container must be run as root to grant sudo permissions' echo 'Container must be run as root to grant sudo permissions'
fi fi

View File

@@ -8,7 +8,7 @@ FROM $BASE_CONTAINER
LABEL maintainer="Jupyter Project <jupyter@googlegroups.com>" LABEL maintainer="Jupyter Project <jupyter@googlegroups.com>"
ENV TAG="33add21fab64" ENV TAG="33add21fab64"
WORKDIR $HOME WORKDIR "${HOME}"
COPY binder/README.ipynb . COPY binder/README.ipynb .
# Fix permissions on README.ipynb as root # Fix permissions on README.ipynb as root
@@ -17,6 +17,6 @@ USER root
RUN fix-permissions README.ipynb RUN fix-permissions README.ipynb
# Switch back to jovyan to avoid accidental container runs as root # Switch back to jovyan to avoid accidental container runs as root
USER $NB_UID USER ${NB_UID}
WORKDIR $HOME WORKDIR "${HOME}"

View File

@@ -27,7 +27,7 @@ RUN apt-get update --yes && \
apt-get clean && rm -rf /var/lib/apt/lists/* apt-get clean && rm -rf /var/lib/apt/lists/*
# Julia dependencies # Julia dependencies
# install Julia packages in /opt/julia instead of $HOME # install Julia packages in /opt/julia instead of ${HOME}
ENV JULIA_DEPOT_PATH=/opt/julia \ ENV JULIA_DEPOT_PATH=/opt/julia \
JULIA_PKGDIR=/opt/julia \ JULIA_PKGDIR=/opt/julia \
JULIA_VERSION="${julia_version}" JULIA_VERSION="${julia_version}"
@@ -44,13 +44,13 @@ RUN mkdir "/opt/julia-${JULIA_VERSION}" && \
# Show Julia where conda libraries are \ # Show Julia where conda libraries are \
RUN mkdir /etc/julia && \ RUN mkdir /etc/julia && \
echo "push!(Libdl.DL_LOAD_PATH, \"$CONDA_DIR/lib\")" >> /etc/julia/juliarc.jl && \ echo "push!(Libdl.DL_LOAD_PATH, \"${CONDA_DIR}/lib\")" >> /etc/julia/juliarc.jl && \
# Create JULIA_PKGDIR \ # Create JULIA_PKGDIR \
mkdir "${JULIA_PKGDIR}" && \ mkdir "${JULIA_PKGDIR}" && \
chown "${NB_USER}" "${JULIA_PKGDIR}" && \ chown "${NB_USER}" "${JULIA_PKGDIR}" && \
fix-permissions "${JULIA_PKGDIR}" fix-permissions "${JULIA_PKGDIR}"
USER $NB_UID USER ${NB_UID}
# R packages including IRKernel which gets installed globally. # R packages including IRKernel which gets installed globally.
RUN conda install --quiet --yes \ RUN conda install --quiet --yes \
@@ -91,4 +91,4 @@ RUN julia -e 'import Pkg; Pkg.update()' && \
rm -rf "${HOME}/.local" && \ rm -rf "${HOME}/.local" && \
fix-permissions "${JULIA_PKGDIR}" "${CONDA_DIR}/share/jupyter" fix-permissions "${JULIA_PKGDIR}" "${CONDA_DIR}/share/jupyter"
WORKDIR $HOME WORKDIR "${HOME}"

View File

@@ -24,7 +24,7 @@ The other pages in this documentation describe additional uses and features in d
**Example 3:** This command pulls the ``jupyter/datascience-notebook`` image tagged ``33add21fab64`` from Docker Hub if it is not already present on the local host. It then starts an *ephemeral* container running a Jupyter Notebook server and exposes the server on host port 10000. The command mounts the current working directory on the host as ``/home/jovyan/work`` in the container. The server logs appear in the terminal. Visiting ``http://<hostname>:10000/lab?token=<token>`` in a browser loads JupyterLab, where ``hostname`` is the name of the computer running docker and ``token`` is the secret token printed in the console. Docker destroys the container after notebook server exit, but any files written to ``~/work`` in the container remain intact on the host.:: **Example 3:** This command pulls the ``jupyter/datascience-notebook`` image tagged ``33add21fab64`` from Docker Hub if it is not already present on the local host. It then starts an *ephemeral* container running a Jupyter Notebook server and exposes the server on host port 10000. The command mounts the current working directory on the host as ``/home/jovyan/work`` in the container. The server logs appear in the terminal. Visiting ``http://<hostname>:10000/lab?token=<token>`` in a browser loads JupyterLab, where ``hostname`` is the name of the computer running docker and ``token`` is the secret token printed in the console. Docker destroys the container after notebook server exit, but any files written to ``~/work`` in the container remain intact on the host.::
docker run --rm -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v "$PWD":/home/jovyan/work jupyter/datascience-notebook:33add21fab64 docker run --rm -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v "${PWD}":/home/jovyan/work jupyter/datascience-notebook:33add21fab64
Table of Contents Table of Contents
----------------- -----------------

View File

@@ -23,19 +23,19 @@ docker run -d -p 8888:8888 jupyter/base-notebook start-notebook.sh --NotebookApp
You may instruct the `start-notebook.sh` script to customize the container environment before launching You may instruct the `start-notebook.sh` script to customize the container environment before launching
the notebook server. You do so by passing arguments to the `docker run` command. the notebook server. You do so by passing arguments to the `docker run` command.
- `-e NB_USER=jovyan` - Instructs the startup script to change the default container username from `jovyan` to the provided value. Causes the script to rename the `jovyan` user home folder. For this option to take effect, you must run the container with `--user root`, set the working directory `-w /home/$NB_USER` and set the environment variable `-e CHOWN_HOME=yes` (see below for detail). This feature is useful when mounting host volumes with specific home folder. - `-e NB_USER=jovyan` - Instructs the startup script to change the default container username from `jovyan` to the provided value. Causes the script to rename the `jovyan` user home folder. For this option to take effect, you must run the container with `--user root`, set the working directory `-w /home/${NB_USER}` and set the environment variable `-e CHOWN_HOME=yes` (see below for detail). This feature is useful when mounting host volumes with specific home folder.
- `-e NB_UID=1000` - Instructs the startup script to switch the numeric user ID of `$NB_USER` to the given value. This feature is useful when mounting host volumes with specific owner permissions. For this option to take effect, you must run the container with `--user root`. (The startup script will `su $NB_USER` after adjusting the user ID.) You might consider using modern Docker options `--user` and `--group-add` instead. See the last bullet below for details. - `-e NB_UID=1000` - Instructs the startup script to switch the numeric user ID of `${NB_USER}` to the given value. This feature is useful when mounting host volumes with specific owner permissions. For this option to take effect, you must run the container with `--user root`. (The startup script will `su ${NB_USER}` after adjusting the user ID.) You might consider using modern Docker options `--user` and `--group-add` instead. See the last bullet below for details.
- `-e NB_GID=100` - Instructs the startup script to change the primary group of`$NB_USER` to `$NB_GID` (the new group is added with a name of `$NB_GROUP` if it is defined, otherwise the group is named `$NB_USER`). This feature is useful when mounting host volumes with specific group permissions. For this option to take effect, you must run the container with `--user root`. (The startup script will `su $NB_USER` after adjusting the group ID.) You might consider using modern Docker options `--user` and `--group-add` instead. See the last bullet below for details. The user is added to supplemental group `users` (gid 100) in order to allow write access to the home directory and `/opt/conda`. If you override the user/group logic, ensure the user stays in group `users` if you want them to be able to modify files in the image. - `-e NB_GID=100` - Instructs the startup script to change the primary group of`${NB_USER}` to `${NB_GID}` (the new group is added with a name of `${NB_GROUP}` if it is defined, otherwise the group is named `${NB_USER}`). This feature is useful when mounting host volumes with specific group permissions. For this option to take effect, you must run the container with `--user root`. (The startup script will `su ${NB_USER}` after adjusting the group ID.) You might consider using modern Docker options `--user` and `--group-add` instead. See the last bullet below for details. The user is added to supplemental group `users` (gid 100) in order to allow write access to the home directory and `/opt/conda`. If you override the user/group logic, ensure the user stays in group `users` if you want them to be able to modify files in the image.
- `-e NB_GROUP=<name>` - The name used for `$NB_GID`, which defaults to `$NB_USER`. This is only used if `$NB_GID` is specified and completely optional: there is only cosmetic effect. - `-e NB_GROUP=<name>` - The name used for `${NB_GID}`, which defaults to `${NB_USER}`. This is only used if `${NB_GID}` is specified and completely optional: there is only cosmetic effect.
- `-e NB_UMASK=<umask>` - Configures Jupyter to use a different umask value from default, i.e. `022`. For example, if setting umask to `002`, new files will be readable and writable by group members instead of just writable by the owner. Wikipedia has a good article about [umask](https://en.wikipedia.org/wiki/Umask). Feel free to read it in order to choose the value that better fits your needs. Default value should fit most situations. Note that `NB_UMASK` when set only applies to the Jupyter process itself - you cannot use it to set a umask for additional files created during run-hooks e.g. via `pip` or `conda` - if you need to set a umask for these you must set `umask` for each command. - `-e NB_UMASK=<umask>` - Configures Jupyter to use a different umask value from default, i.e. `022`. For example, if setting umask to `002`, new files will be readable and writable by group members instead of just writable by the owner. Wikipedia has a good article about [umask](https://en.wikipedia.org/wiki/Umask). Feel free to read it in order to choose the value that better fits your needs. Default value should fit most situations. Note that `NB_UMASK` when set only applies to the Jupyter process itself - you cannot use it to set a umask for additional files created during run-hooks e.g. via `pip` or `conda` - if you need to set a umask for these you must set `umask` for each command.
- `-e CHOWN_HOME=yes` - Instructs the startup script to change the `$NB_USER` home directory owner and group to the current value of `$NB_UID` and `$NB_GID`. This change will take effect even if the user home directory is mounted from the host using `-v` as described below. The change is **not** applied recursively by default. You can change modify the `chown` behavior by setting `CHOWN_HOME_OPTS` (e.g., `-e CHOWN_HOME_OPTS='-R'`). - `-e CHOWN_HOME=yes` - Instructs the startup script to change the `${NB_USER}` home directory owner and group to the current value of `${NB_UID}` and `${NB_GID}`. This change will take effect even if the user home directory is mounted from the host using `-v` as described below. The change is **not** applied recursively by default. You can change modify the `chown` behavior by setting `CHOWN_HOME_OPTS` (e.g., `-e CHOWN_HOME_OPTS='-R'`).
- `-e CHOWN_EXTRA="<some dir>,<some other dir>"` - Instructs the startup script to change the owner and group of each comma-separated container directory to the current value of `$NB_UID` and `$NB_GID`. The change is **not** applied recursively by default. You can change modify the `chown` behavior by setting `CHOWN_EXTRA_OPTS` (e.g., `-e CHOWN_EXTRA_OPTS='-R'`). - `-e CHOWN_EXTRA="<some dir>,<some other dir>"` - Instructs the startup script to change the owner and group of each comma-separated container directory to the current value of `${NB_UID}` and `${NB_GID}`. The change is **not** applied recursively by default. You can change modify the `chown` behavior by setting `CHOWN_EXTRA_OPTS` (e.g., `-e CHOWN_EXTRA_OPTS='-R'`).
- `-e GRANT_SUDO=yes` - Instructs the startup script to grant the `NB_USER` user passwordless `sudo` capability. You do **not** need this option to allow the user to `conda` or `pip` install additional packages. This option is useful, however, when you wish to give `$NB_USER` the ability to install OS packages with `apt` or modify other root-owned files in the container. For this option to take effect, you must run the container with `--user root`. (The `start-notebook.sh` script will `su $NB_USER` after adding `$NB_USER` to sudoers.) **You should only enable `sudo` if you trust the user or if the container is running on an isolated host.** - `-e GRANT_SUDO=yes` - Instructs the startup script to grant the `NB_USER` user passwordless `sudo` capability. You do **not** need this option to allow the user to `conda` or `pip` install additional packages. This option is useful, however, when you wish to give `${NB_USER}` the ability to install OS packages with `apt` or modify other root-owned files in the container. For this option to take effect, you must run the container with `--user root`. (The `start-notebook.sh` script will `su ${NB_USER}` after adding `${NB_USER}` to sudoers.) **You should only enable `sudo` if you trust the user or if the container is running on an isolated host.**
- `-e GEN_CERT=yes` - Instructs the startup script to generates a self-signed SSL certificate and configure Jupyter Notebook to use it to accept encrypted HTTPS connections. - `-e GEN_CERT=yes` - Instructs the startup script to generates a self-signed SSL certificate and configure Jupyter Notebook to use it to accept encrypted HTTPS connections.
- `-e JUPYTER_ENABLE_LAB=yes` - Instructs the startup script to run `jupyter lab` instead of the default `jupyter notebook` command. Useful in container orchestration environments where setting environment variables is easier than change command line parameters. - `-e JUPYTER_ENABLE_LAB=yes` - Instructs the startup script to run `jupyter lab` instead of the default `jupyter notebook` command. Useful in container orchestration environments where setting environment variables is easier than change command line parameters.
- `-e RESTARTABLE=yes` - Runs Jupyter in a loop so that quitting Jupyter does not cause the container to exit. This may be useful when you need to install extensions that require restarting Jupyter. - `-e RESTARTABLE=yes` - Runs Jupyter in a loop so that quitting Jupyter does not cause the container to exit. This may be useful when you need to install extensions that require restarting Jupyter.
- `-v /some/host/folder/for/work:/home/jovyan/work` - Mounts a host machine directory as folder in the container. Useful when you want to preserve notebooks and other work even after the container is destroyed. **You must grant the within-container notebook user or group (`NB_UID` or `NB_GID`) write access to the host directory (e.g., `sudo chown 1000 /some/host/folder/for/work`).** - `-v /some/host/folder/for/work:/home/jovyan/work` - Mounts a host machine directory as folder in the container. Useful when you want to preserve notebooks and other work even after the container is destroyed. **You must grant the within-container notebook user or group (`NB_UID` or `NB_GID`) write access to the host directory (e.g., `sudo chown 1000 /some/host/folder/for/work`).**
- `--user 5000 --group-add users` - Launches the container with a specific user ID and adds that user to the `users` group so that it can modify files in the default home directory and `/opt/conda`. You can use these arguments as alternatives to setting `$NB_UID` and `$NB_GID`. - `--user 5000 --group-add users` - Launches the container with a specific user ID and adds that user to the `users` group so that it can modify files in the default home directory and `/opt/conda`. You can use these arguments as alternatives to setting `${NB_UID}` and `${NB_GID}`.
## Startup Hooks ## Startup Hooks
@@ -103,7 +103,7 @@ You can bypass the provided scripts and specify an arbitrary start command. If y
## Conda Environments ## Conda Environments
The default Python 3.x [Conda environment](https://conda.io/projects/conda/en/latest/user-guide/concepts/environments.html) resides in `/opt/conda`. The `/opt/conda/bin` directory is part of the default `jovyan` user's `$PATH`. That directory is also whitelisted for use in `sudo` commands by the `start.sh` script. The default Python 3.x [Conda environment](https://conda.io/projects/conda/en/latest/user-guide/concepts/environments.html) resides in `/opt/conda`. The `/opt/conda/bin` directory is part of the default `jovyan` user's `${PATH}`. That directory is also whitelisted for use in `sudo` commands by the `start.sh` script.
The `jovyan` user has full read/write access to the `/opt/conda` directory. You can use either `pip`, `conda` or `mamba` to install new packages without any additional permissions. The `jovyan` user has full read/write access to the `/opt/conda` directory. You can use either `pip`, `conda` or `mamba` to install new packages without any additional permissions.

View File

@@ -84,17 +84,17 @@ FROM jupyter/scipy-notebook:latest
# Create a Python 2.x environment using conda including at least the ipython kernel # Create a Python 2.x environment using conda including at least the ipython kernel
# and the kernda utility. Add any additional packages you want available for use # and the kernda utility. Add any additional packages you want available for use
# in a Python 2 notebook to the first line here (e.g., pandas, matplotlib, etc.) # in a Python 2 notebook to the first line here (e.g., pandas, matplotlib, etc.)
RUN conda create --quiet --yes -p $CONDA_DIR/envs/python2 python=2.7 ipython ipykernel kernda && \ RUN conda create --quiet --yes -p "${CONDA_DIR}/envs/python2" python=2.7 ipython ipykernel kernda && \
conda clean --all -f -y conda clean --all -f -y
USER root USER root
# Create a global kernelspec in the image and modify it so that it properly activates # Create a global kernelspec in the image and modify it so that it properly activates
# the python2 conda environment. # the python2 conda environment.
RUN $CONDA_DIR/envs/python2/bin/python -m ipykernel install && \ RUN "${CONDA_DIR}/envs/python2/bin/python" -m ipykernel install && \
$CONDA_DIR/envs/python2/bin/kernda -o -y /usr/local/share/jupyter/kernels/python2/kernel.json "${CONDA_DIR}/envs/python2/bin/kernda" -o -y /usr/local/share/jupyter/kernels/python2/kernel.json
USER $NB_USER USER ${NB_UID}
``` ```
Ref: <https://github.com/jupyter/docker-stacks/issues/440> Ref: <https://github.com/jupyter/docker-stacks/issues/440>
@@ -113,28 +113,28 @@ ARG conda_env=python36
ARG py_ver=3.6 ARG py_ver=3.6
# you can add additional libraries you want conda to install by listing them below the first line and ending with "&& \" # you can add additional libraries you want conda to install by listing them below the first line and ending with "&& \"
RUN conda create --quiet --yes -p $CONDA_DIR/envs/$conda_env python=$py_ver ipython ipykernel && \ RUN conda create --quiet --yes -p "${CONDA_DIR}/envs/${conda_env}" python=${py_ver} ipython ipykernel && \
conda clean --all -f -y conda clean --all -f -y
# alternatively, you can comment out the lines above and uncomment those below # alternatively, you can comment out the lines above and uncomment those below
# if you'd prefer to use a YAML file present in the docker build context # if you'd prefer to use a YAML file present in the docker build context
# COPY --chown=${NB_UID}:${NB_GID} environment.yml /home/$NB_USER/tmp/ # COPY --chown=${NB_UID}:${NB_GID} environment.yml "/home/${NB_USER}/tmp/"
# RUN cd /home/$NB_USER/tmp/ && \ # RUN cd "/home/${NB_USER}/tmp/" && \
# conda env create -p $CONDA_DIR/envs/$conda_env -f environment.yml && \ # conda env create -p "${CONDA_DIR}/envs/${conda_env}" -f environment.yml && \
# conda clean --all -f -y # conda clean --all -f -y
# create Python 3.x environment and link it to jupyter # create Python 3.x environment and link it to jupyter
RUN $CONDA_DIR/envs/${conda_env}/bin/python -m ipykernel install --user --name=${conda_env} && \ RUN "${CONDA_DIR}/envs/${conda_env}/bin/python" -m ipykernel install --user --name="${conda_env}" && \
fix-permissions "${CONDA_DIR}" && \ fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}" fix-permissions "/home/${NB_USER}"
# any additional pip installs can be added by uncommenting the following line # any additional pip installs can be added by uncommenting the following line
# RUN $CONDA_DIR/envs/${conda_env}/bin/pip install # RUN "${CONDA_DIR}/envs/${conda_env}/bin/pip" install
# prepend conda environment to path # prepend conda environment to path
ENV PATH $CONDA_DIR/envs/${conda_env}/bin:$PATH ENV PATH "${CONDA_DIR}/envs/${conda_env}/bin:${PATH}"
# if you want this environment to be the default one, uncomment the following line: # if you want this environment to be the default one, uncomment the following line:
# ENV CONDA_DEFAULT_ENV ${conda_env} # ENV CONDA_DEFAULT_ENV ${conda_env}
@@ -266,7 +266,7 @@ RUN rm /etc/dpkg/dpkg.cfg.d/excludes && \
dpkg -l | grep ^ii | cut -d' ' -f3 | xargs apt-get install --yes --no-install-recommends --reinstall man && \ dpkg -l | grep ^ii | cut -d' ' -f3 | xargs apt-get install --yes --no-install-recommends --reinstall man && \
apt-get clean && rm -rf /var/lib/apt/lists/* apt-get clean && rm -rf /var/lib/apt/lists/*
USER $NB_UID USER ${NB_UID}
``` ```
Adding the documentation on top of an existing singleuser image wastes a lot of space and requires Adding the documentation on top of an existing singleuser image wastes a lot of space and requires
@@ -428,7 +428,7 @@ RUN echo 'deb https://cdn-fastly.deb.debian.org/debian jessie-backports main' >
# Add hadoop binaries # Add hadoop binaries
wget https://mirrors.ukfast.co.uk/sites/ftp.apache.org/hadoop/common/hadoop-2.7.3/hadoop-2.7.3.tar.gz && \ wget https://mirrors.ukfast.co.uk/sites/ftp.apache.org/hadoop/common/hadoop-2.7.3/hadoop-2.7.3.tar.gz && \
tar -xvf hadoop-2.7.3.tar.gz -C /usr/local && \ tar -xvf hadoop-2.7.3.tar.gz -C /usr/local && \
chown -R $NB_USER:users /usr/local/hadoop-2.7.3 && \ chown -R "${NB_USER}:users" /usr/local/hadoop-2.7.3 && \
rm -f hadoop-2.7.3.tar.gz && \ rm -f hadoop-2.7.3.tar.gz && \
# Install os dependencies required for pydoop, pyhive # Install os dependencies required for pydoop, pyhive
apt-get update --yes && \ apt-get update --yes && \
@@ -447,13 +447,13 @@ RUN echo "spark.driver.extraJavaOptions -Dhdp.version=2.5.3.0-37" >> /usr/local/
echo "spark.yarn.am.extraJavaOptions -Dhdp.version=2.5.3.0-37" >> /usr/local/spark/conf/spark-defaults.conf && \ echo "spark.yarn.am.extraJavaOptions -Dhdp.version=2.5.3.0-37" >> /usr/local/spark/conf/spark-defaults.conf && \
echo "spark.master=yarn" >> /usr/local/spark/conf/spark-defaults.conf && \ echo "spark.master=yarn" >> /usr/local/spark/conf/spark-defaults.conf && \
echo "spark.hadoop.yarn.timeline-service.enabled=false" >> /usr/local/spark/conf/spark-defaults.conf && \ echo "spark.hadoop.yarn.timeline-service.enabled=false" >> /usr/local/spark/conf/spark-defaults.conf && \
chown -R $NB_USER:users /usr/local/spark/conf/spark-defaults.conf && \ chown -R "${NB_USER}:users" /usr/local/spark/conf/spark-defaults.conf && \
# Create an alternative HADOOP_CONF_HOME so we can mount as a volume and repoint # Create an alternative HADOOP_CONF_HOME so we can mount as a volume and repoint
# using ENV var if needed # using ENV var if needed
mkdir -p /etc/hadoop/conf/ && \ mkdir -p /etc/hadoop/conf/ && \
chown $NB_USER:users /etc/hadoop/conf/ chown "${NB_USER}":users /etc/hadoop/conf/
USER $NB_USER USER ${NB_UID}
# Install useful jupyter extensions and python libraries like : # Install useful jupyter extensions and python libraries like :
# - Dashboards # - Dashboards
@@ -468,7 +468,7 @@ RUN pip install --quiet --no-cache-dir jupyter_dashboards faker && \
USER root USER root
# Ensure we overwrite the kernel config so that toree connects to cluster # Ensure we overwrite the kernel config so that toree connects to cluster
RUN jupyter toree install --sys-prefix --spark_opts="--master yarn --deploy-mode client --driver-memory 512m --executor-memory 512m --executor-cores 1 --driver-java-options -Dhdp.version=2.5.3.0-37 --conf spark.hadoop.yarn.timeline-service.enabled=false" RUN jupyter toree install --sys-prefix --spark_opts="--master yarn --deploy-mode client --driver-memory 512m --executor-memory 512m --executor-cores 1 --driver-java-options -Dhdp.version=2.5.3.0-37 --conf spark.hadoop.yarn.timeline-service.enabled=false"
USER $NB_USER USER ${NB_UID}
``` ```
Credit: [britishbadger](https://github.com/britishbadger) from Credit: [britishbadger](https://github.com/britishbadger) from
@@ -503,7 +503,7 @@ NB: this works for classic notebooks only
# Update with your base image of choice # Update with your base image of choice
FROM jupyter/minimal-notebook:latest FROM jupyter/minimal-notebook:latest
USER $NB_USER USER ${NB_UID}
RUN pip install --quiet --no-cache-dir jupyter_contrib_nbextensions && \ RUN pip install --quiet --no-cache-dir jupyter_contrib_nbextensions && \
jupyter contrib nbextension install --user && \ jupyter contrib nbextension install --user && \
@@ -530,7 +530,7 @@ RUN apt-get update --yes && \
apt-get install --yes --no-install-recommends swig && \ apt-get install --yes --no-install-recommends swig && \
apt-get clean && rm -rf /var/lib/apt/lists/* apt-get clean && rm -rf /var/lib/apt/lists/*
USER $NB_UID USER ${NB_UID}
RUN pip install --quiet --no-cache-dir auto-sklearn && \ RUN pip install --quiet --no-cache-dir auto-sklearn && \
fix-permissions "${CONDA_DIR}" && \ fix-permissions "${CONDA_DIR}" && \
@@ -548,11 +548,11 @@ ARG DELTA_CORE_VERSION="0.8.0"
USER root USER root
RUN echo "spark.jars.packages io.delta:delta-core_2.12:${DELTA_CORE_VERSION}" >> $SPARK_HOME/conf/spark-defaults.conf && \ RUN echo "spark.jars.packages io.delta:delta-core_2.12:${DELTA_CORE_VERSION}" >> "${SPARK_HOME}/conf/spark-defaults.conf" && \
echo 'spark.sql.extensions io.delta.sql.DeltaSparkSessionExtension' >> $SPARK_HOME/conf/spark-defaults.conf && \ echo 'spark.sql.extensions io.delta.sql.DeltaSparkSessionExtension' >> "${SPARK_HOME}/conf/spark-defaults.conf" && \
echo 'spark.sql.catalog.spark_catalog org.apache.spark.sql.delta.catalog.DeltaCatalog' >> $SPARK_HOME/conf/spark-defaults.conf echo 'spark.sql.catalog.spark_catalog org.apache.spark.sql.delta.catalog.DeltaCatalog' >> "${SPARK_HOME}/conf/spark-defaults.conf"
USER $NB_UID USER ${NB_UID}
# Run pyspark and exit to trigger the download of the delta lake jars # Run pyspark and exit to trigger the download of the delta lake jars
RUN echo "quit()" > /tmp/init-delta.py && \ RUN echo "quit()" > /tmp/init-delta.py && \

View File

@@ -55,7 +55,7 @@ d67fe77f1a84
**Example 2** This command pulls the `jupyter/r-notebook` image tagged `33add21fab64` from Docker Hub if it is not already present on the local host. It then starts a container running a Jupyter Notebook server and exposes the server on host port 10000. The server logs appear in the terminal and include a URL to the notebook server, but with the internal container port (8888) instead of the the correct host port (10000). **Example 2** This command pulls the `jupyter/r-notebook` image tagged `33add21fab64` from Docker Hub if it is not already present on the local host. It then starts a container running a Jupyter Notebook server and exposes the server on host port 10000. The server logs appear in the terminal and include a URL to the notebook server, but with the internal container port (8888) instead of the the correct host port (10000).
```bash ```bash
$ docker run --rm -p 10000:8888 -v "$PWD":/home/jovyan/work jupyter/r-notebook:33add21fab64 $ docker run --rm -p 10000:8888 -v "${PWD}":/home/jovyan/work jupyter/r-notebook:33add21fab64
Executing the command: jupyter notebook Executing the command: jupyter notebook
[I 19:31:09.573 NotebookApp] Writing notebook server cookie secret to /home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret [I 19:31:09.573 NotebookApp] Writing notebook server cookie secret to /home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret

View File

@@ -8,11 +8,11 @@
set -e set -e
# Get domain and email from environment # Get domain and email from environment
[ -z "$FQDN" ] && \ [ -z "${FQDN}" ] && \
echo "ERROR: Must set FQDN environment varable" && \ echo "ERROR: Must set FQDN environment varable" && \
exit 1 exit 1
[ -z "$EMAIL" ] && \ [ -z "${EMAIL}" ] && \
echo "ERROR: Must set EMAIL environment varable" && \ echo "ERROR: Must set EMAIL environment varable" && \
exit 1 exit 1
@@ -22,11 +22,11 @@ set -e
# Create Docker volume to contain the cert # Create Docker volume to contain the cert
: "${SECRETS_VOLUME:=my-notebook-secrets}" : "${SECRETS_VOLUME:=my-notebook-secrets}"
docker volume create --name $SECRETS_VOLUME 1>/dev/null docker volume create --name "${SECRETS_VOLUME}" 1>/dev/null
# Generate the cert and save it to the Docker volume # Generate the cert and save it to the Docker volume
docker run --rm -it \ docker run --rm -it \
-p 80:80 \ -p 80:80 \
-v $SECRETS_VOLUME:/etc/letsencrypt \ -v "${SECRETS_VOLUME}":/etc/letsencrypt \
quay.io/letsencrypt/letsencrypt:latest \ quay.io/letsencrypt/letsencrypt:latest \
certonly \ certonly \
--non-interactive \ --non-interactive \
@@ -34,15 +34,15 @@ docker run --rm -it \
--standalone \ --standalone \
--standalone-supported-challenges http-01 \ --standalone-supported-challenges http-01 \
--agree-tos \ --agree-tos \
--domain "$FQDN" \ --domain "${FQDN}" \
--email "$EMAIL" \ --email "${EMAIL}" \
$CERT_SERVER "${CERT_SERVER}"
# Set permissions so nobody can read the cert and key. # Set permissions so nobody can read the cert and key.
# Also symlink the certs into the root of the /etc/letsencrypt # Also symlink the certs into the root of the /etc/letsencrypt
# directory so that the FQDN doesn't have to be known later. # directory so that the FQDN doesn't have to be known later.
docker run --rm -it \ docker run --rm -it \
-v $SECRETS_VOLUME:/etc/letsencrypt \ -v "${SECRETS_VOLUME}":/etc/letsencrypt \
ubuntu:20.04 \ ubuntu:20.04 \
bash -c "ln -s /etc/letsencrypt/live/$FQDN/* /etc/letsencrypt/ && \ bash -c "ln -s /etc/letsencrypt/live/${FQDN}/* /etc/letsencrypt/ && \
find /etc/letsencrypt -type d -exec chmod 755 {} +" find /etc/letsencrypt -type d -exec chmod 755 {} +"

View File

@@ -7,17 +7,17 @@ set -e
# User must have slcli installed # User must have slcli installed
which slcli > /dev/null || (echo "SoftLayer cli not found (pip install softlayer)"; exit 1) which slcli > /dev/null || (echo "SoftLayer cli not found (pip install softlayer)"; exit 1)
USAGE="Usage: $(basename "$0") machine_name [domain]" USAGE="Usage: $(basename "${0}") machine_name [domain]"
E_BADARGS=85 E_BADARGS=85
# Machine name is first command line arg # Machine name is first command line arg
MACHINE_NAME=$1 && [ -z "$MACHINE_NAME" ] && echo "$USAGE" && exit $E_BADARGS MACHINE_NAME="${1}" && [ -z "${MACHINE_NAME}" ] && echo "${USAGE}" && exit ${E_BADARGS}
# Use SOFTLAYER_DOMAIN env var if domain name not set as second arg # Use SOFTLAYER_DOMAIN env var if domain name not set as second arg
DOMAIN="${2:-$SOFTLAYER_DOMAIN}" && [ -z "$DOMAIN" ] && \ DOMAIN="${2:-$SOFTLAYER_DOMAIN}" && [ -z "${DOMAIN}" ] && \
echo "Must specify domain or set SOFTLAYER_DOMAIN environment varable" && \ echo "Must specify domain or set SOFTLAYER_DOMAIN environment varable" && \
echo "$USAGE" && exit $E_BADARGS echo "${USAGE}" && exit ${E_BADARGS}
IP=$(docker-machine ip "$MACHINE_NAME") IP=$(docker-machine ip "${MACHINE_NAME}")
slcli dns record-add "$DOMAIN" "$MACHINE_NAME" A "$IP" slcli dns record-add "${DOMAIN}" "${MACHINE_NAME}" A "${IP}"

View File

@@ -9,7 +9,7 @@ USER root
# Add permanent apt-get installs and other root commands here # Add permanent apt-get installs and other root commands here
# e.g., RUN apt-get install --yes --no-install-recommends npm nodejs # e.g., RUN apt-get install --yes --no-install-recommends npm nodejs
USER $NB_UID USER ${NB_UID}
# Switch back to jovyan to avoid accidental container runs as root # Switch back to jovyan to avoid accidental container runs as root
# Add permanent pip/conda installs, data files, other user libs here # Add permanent pip/conda installs, data files, other user libs here

View File

@@ -6,7 +6,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Setup environment # Setup environment
# shellcheck disable=SC1091 # shellcheck disable=SC1091
source "$DIR/env.sh" source "${DIR}/env.sh"
# Build the notebook image # Build the notebook image
docker-compose -f "$DIR/notebook.yml" build docker-compose -f "${DIR}/notebook.yml" build

View File

@@ -6,7 +6,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Setup environment # Setup environment
# shellcheck disable=SC1091 # shellcheck disable=SC1091
source "$DIR/env.sh" source "${DIR}/env.sh"
# Bring down the notebook container, using container name as project name # Bring down the notebook container, using container name as project name
docker-compose -f "$DIR/notebook.yml" -p "$NAME" down docker-compose -f "${DIR}/notebook.yml" -p "${NAME}" down

View File

@@ -14,9 +14,9 @@ export NAME
export PORT export PORT
# Container work volume name # Container work volume name
: "${WORK_VOLUME:=$NAME-work}" : "${WORK_VOLUME:=${NAME}-work}"
export WORK_VOLUME export WORK_VOLUME
# Container secrets volume name # Container secrets volume name
: "${SECRETS_VOLUME:=$NAME-secrets}" : "${SECRETS_VOLUME:=${NAME}-secrets}"
export SECRETS_VOLUME export SECRETS_VOLUME

View File

@@ -6,14 +6,14 @@ set -e
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
USAGE="Usage: $(basename "$0") [--secure | --letsencrypt] [--password PASSWORD] [--secrets SECRETS_VOLUME]" USAGE="Usage: $(basename "${0}") [--secure | --letsencrypt] [--password PASSWORD] [--secrets SECRETS_VOLUME]"
# Parse args to determine security settings # Parse args to determine security settings
SECURE=${SECURE:=no} SECURE=${SECURE:=no}
LETSENCRYPT=${LETSENCRYPT:=no} LETSENCRYPT=${LETSENCRYPT:=no}
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
key="$1" key="${1}"
case $key in case "${key}" in
--secure) --secure)
SECURE=yes SECURE=yes
;; ;;
@@ -21,11 +21,11 @@ case $key in
LETSENCRYPT=yes LETSENCRYPT=yes
;; ;;
--secrets) --secrets)
SECRETS_VOLUME="$2" SECRETS_VOLUME="${2}"
shift # past argument shift # past argument
;; ;;
--password) --password)
PASSWORD="$2" PASSWORD="${2}"
export PASSWORD export PASSWORD
shift # past argument shift # past argument
;; ;;
@@ -35,17 +35,17 @@ esac
shift # past argument or value shift # past argument or value
done done
if [[ "$LETSENCRYPT" == yes || "$SECURE" == yes ]]; then if [[ "${LETSENCRYPT}" == yes || "${SECURE}" == yes ]]; then
if [ -z "${PASSWORD:+x}" ]; then if [ -z "${PASSWORD:+x}" ]; then
echo "ERROR: Must set PASSWORD if running in secure mode" echo "ERROR: Must set PASSWORD if running in secure mode"
echo "$USAGE" echo "${USAGE}"
exit 1 exit 1
fi fi
if [ "$LETSENCRYPT" == yes ]; then if [ "${LETSENCRYPT}" == yes ]; then
CONFIG=letsencrypt-notebook.yml CONFIG=letsencrypt-notebook.yml
if [ -z "${SECRETS_VOLUME:+x}" ]; then if [ -z "${SECRETS_VOLUME:+x}" ]; then
echo "ERROR: Must set SECRETS_VOLUME if running in letsencrypt mode" echo "ERROR: Must set SECRETS_VOLUME if running in letsencrypt mode"
echo "$USAGE" echo "${USAGE}"
exit 1 exit 1
fi fi
else else
@@ -59,14 +59,14 @@ fi
# Setup environment # Setup environment
# shellcheck disable=SC1091 # shellcheck disable=SC1091
source "$DIR/env.sh" source "${DIR}/env.sh"
# Create a Docker volume to store notebooks # Create a Docker volume to store notebooks
docker volume create --name "$WORK_VOLUME" docker volume create --name "${WORK_VOLUME}"
# Bring up a notebook container, using container name as project name # Bring up a notebook container, using container name as project name
echo "Bringing up notebook '$NAME'" echo "Bringing up notebook '${NAME}'"
docker-compose -f "$DIR/$CONFIG" -p "$NAME" up -d docker-compose -f "${DIR}/${CONFIG}" -p "${NAME}" up -d
IP=$(docker-machine ip "$(docker-machine active)") IP=$(docker-machine ip "$(docker-machine active)")
echo "Notebook $NAME listening on $IP:$PORT" echo "Notebook ${NAME} listening on ${IP}:${PORT}"

View File

@@ -9,7 +9,7 @@ USER root
# Add permanent apt-get installs and other root commands here # Add permanent apt-get installs and other root commands here
# e.g., RUN apt-get install --yes --no-install-recommends npm nodejs # e.g., RUN apt-get install --yes --no-install-recommends npm nodejs
USER $NB_UID USER ${NB_UID}
# Switch back to jovyan to avoid accidental container runs as root # Switch back to jovyan to avoid accidental container runs as root
# Add permanent pip/conda installs, data files, other user libs here # Add permanent pip/conda installs, data files, other user libs here

View File

@@ -77,7 +77,7 @@ The supplied `assemble` script performs a few key steps.
The first steps copy files into the location they need to be when the image is run, from the directory where they are initially placed by the `s2i` command. The first steps copy files into the location they need to be when the image is run, from the directory where they are initially placed by the `s2i` command.
```bash ```bash
cp -Rf /tmp/src/. /home/$NB_USER cp -Rf /tmp/src/. "/home/${NB_USER}"
rm -rf /tmp/src rm -rf /tmp/src
``` ```
@@ -85,12 +85,12 @@ rm -rf /tmp/src
The next steps are: The next steps are:
```bash ```bash
if [ -f /home/$NB_USER/environment.yml ]; then if [ -f "/home/${NB_USER}/environment.yml" ]; then
conda env update --name root --file /home/$NB_USER/environment.yml conda env update --name root --file "/home/${NB_USER}/environment.yml"
conda clean --all -f -y conda clean --all -f -y
else else
if [ -f /home/$NB_USER/requirements.txt ]; then if [ -f "/home/${NB_USER}/requirements.txt" ]; then
pip --no-cache-dir install -r /home/$NB_USER/requirements.txt pip --no-cache-dir install -r "/home/${NB_USER}/requirements.txt"
fi fi
fi fi
``` ```

View File

@@ -33,4 +33,4 @@ RUN apt-get update --yes && \
RUN update-alternatives --install /usr/bin/nano nano /bin/nano-tiny 10 RUN update-alternatives --install /usr/bin/nano nano /bin/nano-tiny 10
# Switch back to jovyan to avoid accidental container runs as root # Switch back to jovyan to avoid accidental container runs as root
USER $NB_UID USER ${NB_UID}

View File

@@ -39,7 +39,7 @@ WORKDIR /usr/local
# Configure Spark # Configure Spark
ENV SPARK_HOME=/usr/local/spark ENV SPARK_HOME=/usr/local/spark
ENV SPARK_OPTS="--driver-java-options=-Xms1024M --driver-java-options=-Xmx4096M --driver-java-options=-Dlog4j.logLevel=info" \ ENV SPARK_OPTS="--driver-java-options=-Xms1024M --driver-java-options=-Xmx4096M --driver-java-options=-Dlog4j.logLevel=info" \
PATH=$PATH:$SPARK_HOME/bin PATH="${PATH}:${SPARK_HOME}/bin"
RUN ln -s "spark-${APACHE_SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}" spark && \ RUN ln -s "spark-${APACHE_SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}" spark && \
# Add a link in the before_notebook hook in order to source automatically PYTHONPATH # Add a link in the before_notebook hook in order to source automatically PYTHONPATH
@@ -48,11 +48,11 @@ RUN ln -s "spark-${APACHE_SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}" spark && \
# Fix Spark installation for Java 11 and Apache Arrow library # Fix Spark installation for Java 11 and Apache Arrow library
# see: https://github.com/apache/spark/pull/27356, https://spark.apache.org/docs/latest/#downloading # see: https://github.com/apache/spark/pull/27356, https://spark.apache.org/docs/latest/#downloading
RUN cp -p "$SPARK_HOME/conf/spark-defaults.conf.template" "$SPARK_HOME/conf/spark-defaults.conf" && \ RUN cp -p "${SPARK_HOME}/conf/spark-defaults.conf.template" "${SPARK_HOME}/conf/spark-defaults.conf" && \
echo 'spark.driver.extraJavaOptions -Dio.netty.tryReflectionSetAccessible=true' >> $SPARK_HOME/conf/spark-defaults.conf && \ echo 'spark.driver.extraJavaOptions -Dio.netty.tryReflectionSetAccessible=true' >> "${SPARK_HOME}/conf/spark-defaults.conf" && \
echo 'spark.executor.extraJavaOptions -Dio.netty.tryReflectionSetAccessible=true' >> $SPARK_HOME/conf/spark-defaults.conf echo 'spark.executor.extraJavaOptions -Dio.netty.tryReflectionSetAccessible=true' >> "${SPARK_HOME}/conf/spark-defaults.conf"
USER $NB_UID USER ${NB_UID}
# Install pyarrow # Install pyarrow
RUN conda install --quiet --yes --satisfied-skip-solve \ RUN conda install --quiet --yes --satisfied-skip-solve \
@@ -61,4 +61,4 @@ RUN conda install --quiet --yes --satisfied-skip-solve \
fix-permissions "${CONDA_DIR}" && \ fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}" fix-permissions "/home/${NB_USER}"
WORKDIR $HOME WORKDIR "${HOME}"

View File

@@ -21,7 +21,7 @@ RUN apt-get update --yes && \
# Fix for devtools https://github.com/conda-forge/r-devtools-feedstock/issues/4 # Fix for devtools https://github.com/conda-forge/r-devtools-feedstock/issues/4
RUN ln -s /bin/tar /bin/gtar RUN ln -s /bin/tar /bin/gtar
USER $NB_UID USER ${NB_UID}
# R packages including IRKernel which gets installed globally. # R packages including IRKernel which gets installed globally.
RUN conda install --quiet --yes \ RUN conda install --quiet --yes \

View File

@@ -12,7 +12,7 @@ RUN apt-get update --yes && \
apt-get install --yes --no-install-recommends ffmpeg dvipng cm-super && \ apt-get install --yes --no-install-recommends ffmpeg dvipng cm-super && \
apt-get clean && rm -rf /var/lib/apt/lists/* apt-get clean && rm -rf /var/lib/apt/lists/*
USER $NB_UID USER ${NB_UID}
# Install Python 3 packages # Install Python 3 packages
RUN conda install --quiet --yes \ RUN conda install --quiet --yes \
@@ -62,6 +62,6 @@ ENV XDG_CACHE_HOME="/home/${NB_USER}/.cache/"
RUN MPLBACKEND=Agg python -c "import matplotlib.pyplot" && \ RUN MPLBACKEND=Agg python -c "import matplotlib.pyplot" && \
fix-permissions "/home/${NB_USER}" fix-permissions "/home/${NB_USER}"
USER $NB_UID USER ${NB_UID}
WORKDIR $HOME WORKDIR "${HOME}"