Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# ignore dotfiles and directories (except .gitignore)
.*
!.gitignore
environment/image-tags
30 changes: 26 additions & 4 deletions environment/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,40 @@
# Start from a core stack version
FROM jupyter/datascience-notebook:9e63909e0317

# Volumes aren't in place yet
# Volumes aren't in place yet, get the stuff into the container
WORKDIR /home/jovyan/
COPY --chown=${NB_UID}:${NB_GID} . .

# Set up jupyterlab/ for UI to use
# Allow these build-args to be passed into the Dockerfile's context for tagging the image from environment/docker-environment-common.sh
## NOTE: You can update REPOSITORY_URL in environment/docker-environment-common.sh
ARG REPOSITORY_URL
ARG BUILD_DATE
ARG REVISION
ARG LATEST_GIT_TAG
# Tag the image. Schema based on https://github.com/opencontainers/image-spec/blob/main/annotations.md.
## NOTE: org.opencontainers.image.version will always be the latest Git release tag
LABEL \
org.opencontainers.image.created=$BUILD_DATE \
org.opencontainers.image.authors="adrury@mtholyoke.edu" \
org.opencontainers.image.url="$REPOSITORY_URL/blob/main/environment/README.md" \
org.opencontainers.image.documentation="$REPOSITORY_URL/wiki" \
org.opencontainers.image.source=$REPOSITORY_URL \
org.opencontainers.image.revision=$REVISION \
org.opencontainers.image.vendor="Trustees of Mount Holyoke College" \
org.opencontainers.image.license="MIT" \
org.opencontainers.image.title="Docker Data Science Environment" \
org.opencontainers.image.description="Standardized and reproducible data science research environment" \
org.opencontainers.image.version=$LATEST_GIT_TAG

# Set up jupyterlab/ for UI to use, putting data/ and analysis/ at the root of the UI
WORKDIR /home/jovyan/
RUN mkdir jupyterlab
WORKDIR /home/jovyan/jupyterlab
RUN ln -s ../analysis analysis
RUN ln -s ../data data
WORKDIR /home/jovyan/environment

# Install Python packages from requirements.txt file
WORKDIR /home/jovyan/environment
RUN pip install --quiet --no-cache-dir --requirement ./requirements.txt && \
fix-permissions "${CONDA_DIR}" && \
fix-permissions "/home/${NB_USER}"
Expand All @@ -25,5 +47,5 @@ RUN ./r-packages.R
# Install JupyterLab extensions
RUN ./install-jupyter-extensions.sh


# Put everything back so the UI doesn't get confused
WORKDIR /home/jovyan/
41 changes: 34 additions & 7 deletions environment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ Otherwise, you may proceed to [Starting a stopped container](#Starting-a-stopped

At the command line:
```bash
docker compose -f environment/compose.yml build
docker compose -f environment/compose.yml up -d
./environment/docker-environment-common.sh build
./environment/docker-environment-common.sh up
```

When you bring up JupyterLab, you may see this warning. That's okay, you can ignore it.
Expand All @@ -30,22 +30,47 @@ WARN[0000] Found orphan containers ([<some_container_name>]) for this project. I

To start the JupyterLab Docker container, at the command line:
```bash
docker compose -f environment/compose.yml start
./environment/docker-environment-common.sh start
```

### Accessing JupyterLab

When it's done spinning up, the container will be accessible via any webbrowser on the host machine at `http://localhost:PORT_NUMBER/` (eg. http://localhost:10000).
When it's done spinning up, the container will be accessible via any web browser on the host machine at `http://localhost:PORT_NUMBER/` (eg. http://localhost:10000).


## Stopping a container

To stop the JupyterLab Docker container, at the command line:
```bash
docker compose -f environment/compose.yml stop
./environment/docker-environment-common.sh stop
```


## View container logs

To view the JupyterLab Docker container logs, at the command line:
```bash
./environment/docker-environment-common.sh logs
```

Exit using `^C` (control + c) as many times as required.


## View container version

To view the JupyterLab Docker container version, at the command line:
```bash
./environment/docker-environment-common.sh version
```


## View container tags / labels

To view the JupyterLab Docker container tags, at the command line:
```bash
./environment/docker-environment-common.sh tags
```

# Structure

## Docker elements
Expand Down Expand Up @@ -80,6 +105,10 @@ Additional JupyterLab extensions to be installed when the container is built.

## Supporting files

### `docker-environment-common.sh`

This script helps abstract away the details of Docker, while maintaining a versioning/tagging system on the Docker images and containers. It is there to help make interacting with the Docker environment easier.

### `install-jupyter-extensions.sh`

This script installs the JupyterLab extensions, and is run by the `Dockerfile`.
Expand All @@ -88,5 +117,3 @@ This script installs the JupyterLab extensions, and is run by the `Dockerfile`.
### `jupyter_server_config.py`

This is where you can make changes to the Jupyter server configuration. By default, it sets the JupyterLab UI to launch in the `jupyterlab` folder of the main project and removes server authentication since this project is only meant to be run on a researcher's computer and not in a shared or production environment.


1 change: 1 addition & 0 deletions environment/compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
version: '3.9'
services:
datascience-notebook:
image: datascience-notebook:${TAG}
# Specify where the project parent directory is, and where the Dockerfile
# is within that structure.
build:
Expand Down
100 changes: 100 additions & 0 deletions environment/docker-environment-common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#! /bin/bash

# Controls to help generalize Docker commands.

# Usage information
function help() {
local bold=$(tput bold)
local normal=$(tput sgr0)
echo -e "${bold}Usage:${normal} $0 {start|stop|build|up|down|logs|images|version|labels|tags}"
echo
echo -e "Manage interactions with Docker / Compose"
echo -e "Some commands, like version and tags, will only work if the container is already running."
}

# Retrieve the appropriate image/container tag and generate the `docker compose` command.
function retrieve_tag() {
TAG_FILE="environment/image-tags"
if [ ! -f "$TAG_FILE" ]; then
echo "The tagfile $TAG_FILE does not exist, make sure to build the image!"
exit 3
fi
TAG=$(head -n1 $TAG_FILE)

if [ -z "${TAG}" ]; then
echo "The tag in $TAG_FILE is empty, make sure to build the image!"
exit 4
fi
export TAG
}


# Make sure Docker is running
if ! docker info > /dev/null 2>&1; then
echo "This script uses Docker, and it isn't running - please start Docker and try again!"
exit 1
fi

# Detect what action to take. Everything is handled pretty identically, aside from `build`.
case "$1" in
logs)
retrieve_tag
docker compose -f environment/compose.yml logs -f
;;

start)
retrieve_tag
docker compose -f environment/compose.yml start
;;

stop)
retrieve_tag
docker compose -f environment/compose.yml stop
;;
up)
retrieve_tag
docker compose -f environment/compose.yml up -d
;;

down)
retrieve_tag
docker compose -f environment/compose.yml down
;;

images|version)
retrieve_tag
docker compose -f environment/compose.yml images
;;

labels|tags)
retrieve_tag
CONTAINER_ID=`docker compose -f environment/compose.yml ps -q`
if [ -z "$CONTAINER_ID" ]; then
echo -e "No running containers. Try \`$0 build\` and \`$0 up\`"
exit 5
fi
docker inspect --format='{{ range $k,$v:=.Config.Labels }}{{ if eq (printf "%.24s" $k) "org.opencontainers.image" }}{{ $k }}: {{ $v }}{{ printf "\n" }}{{end}}{{end}}' $CONTAINER_ID
;;


build)
REPOSITORY_URL="https://github.com/mtholyoke/docker-data-science-environment" ## NOTE: Update this.
REVISION=$(git log --pretty=format:'%as_%h' -n 1)
LATEST_GIT_TAG="$(git describe --abbrev=0 --tags)"
BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
# PROGRESS="--progress=plain" # Print debug information during Docker build phase
NO_CACHE="--no-cache=true"

# Configure image tag information from the Git commit hash, used in compose.yml and in docker-environment-common.sh
export TAG=$REVISION_$LATEST_GIT_TAG
echo $TAG > environment/image-tags

# Build image
docker compose -f environment/compose.yml build $NO_CACHE --build-arg BUILD_DATE=$BUILD_DATE --build-arg REVISION=$REVISION --build-arg REPOSITORY_URL=$REPOSITORY_URL --build-arg LATEST_GIT_TAG=$LATEST_GIT_TAG $PROGRESS datascience-notebook
;;

*)
echo -e "Invalid argument: $1"
help
exit 2
esac