From deb2b4ddc766df28024892859fc2b741cf4d4208 Mon Sep 17 00:00:00 2001 From: Ste O'Brien Date: Tue, 8 Oct 2024 12:14:01 -0400 Subject: [PATCH] feat(Dockerfile,-kernel.json): Adding capabilities for containerized ipykernel --- Dockerfile | 10 +++++-- docs/containers.md | 53 +++++++++++++++++++++++++++++++++++++- kernel.json | 11 ++++++++ launch_kernel_apptainer.sh | 18 +++++++++++++ launch_kernel_docker.sh | 27 +++++++++++++++++++ 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 kernel.json create mode 100755 launch_kernel_apptainer.sh create mode 100755 launch_kernel_docker.sh diff --git a/Dockerfile b/Dockerfile index 273d43b..4a209b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM jupyter/minimal-notebook AS base # Install gammapy -RUN mamba install gcc jupyterlab "gammapy==1.2" --yes +RUN mamba install gcc jupyterlab "gammapy==1.2" ipykernel --yes WORKDIR /gammapy-tools @@ -43,6 +43,8 @@ WORKDIR /gammapy-tools/tmp_build/gammapy-tools RUN pip install . # RUN ./gammapy_tools/Hipparcos_MAG8_1997.dat $GAMMAPY_DATA/catalogs/ RUN cp /opt/conda/lib/python3.11/site-packages/gammapy_tools/Hipparcos_MAG8_1997.dat $GAMMAPY_DATA/ +RUN wget https://raw.githubusercontent.com/gammapy/gammapy/main/gammapy/datasets/map.py -O /opt/conda/lib/python3.11/site-packages/gammapy/datasets/map.py + USER root RUN mkdir /local_data @@ -51,4 +53,8 @@ RUN mkdir /local_data RUN rm -r /gammapy-tools/tmp_build USER jovyan RUN mamba clean -a --yes -WORKDIR /local_data \ No newline at end of file +WORKDIR /local_data + +# Keep alive for Docker ipykernel usage +RUN echo -e "#!/bin/bash\nwhile true; do sleep 5; done" >> /gammapy-tools/keep_alive.sh ; chmod a+x /gammapy-tools/keep_alive.sh +CMD ["/gammapy-tools/keep_alive.sh"] \ No newline at end of file diff --git a/docs/containers.md b/docs/containers.md index 82c3d85..7b473b0 100644 --- a/docs/containers.md +++ b/docs/containers.md @@ -90,4 +90,55 @@ This will have access to data mounted in `/local_data` and run the python versio Finally, you can start an interactive shell using: ``` singularity/apptainer shell -B /path/to/my/data:/local_data gammapy-tools.sif -``` \ No newline at end of file +``` + +## Containerized Jupyter Kernel + +One can used a containerized Jupyter kernel through one's own python environment, regardless of the setup (venv, poetry, conda, mamba, etc). The benifit of this method is that all the python code is evaluated in a reproducable containerized environment, without needing to worry about file permission, mounts/binds, networking or any other boundries of when using Docker or Apptainer/Singularity. + +To do this you need either Docker or Apptainer/Singularity installed and a working python install with ipykernel installed. +First make sure you've build either the Docker or Apptainer/Singularity image using the instructions above. +Next create a new custom kernel: +``` +python -m ipykernel install --user --name gammapy-kernel --display-name="gammapy-kernel" +``` +This will create a new directory (for example): +``` +Installed kernelspec custom-kernel in /home/obriens/.local/share/jupyter/kernels/gammapy-kernel +``` +Navigate to the `/home/obriens/.local/share/jupyter/kernels/gammapy-kernel/` (correcting for your own install) and replace the `kernel.json` file with the `kernel.json` [file from this repository ](../kernel.json): +``` +{ + "argv": [ + "/path/to/launch_kernel.sh", + "{connection_file}" + ], + "display_name": "gammapy-kernel", + "language": "python", + "metadata": { + "debugger": true + } +} +``` +Replace: +``` + "/path/to/launch_kernel.sh", +``` +With the path to the `launch_kernel_apptainer.sh` or `launch_kernel_docker.sh` file from this repository. +Make the `launch_kernel_apptainer.sh` or `launch_kernel_docker.sh` script executable, for example: +``` +chmod +x launch_kernel_apptainer.sh +``` +Export the environmental variable `GAMMAPY_KERNEL_IMAGE` to: +``` +export GAMMAPY_KERNEL_IMAGE=/path/to/gammapy-tools.sif +``` +for Apptainer/Singularity, or +``` +export GAMMAPY_KERNEL_IMAGE="docker_username/gammapy_tools:latest" +``` +for Docker. + +Launch a Jupyter instances as you normally do from any envrionment. When creating a new notebook you'll now see the option to use the containerized `gammapy-kernel`. + +For a detailed explaination, see [this post](https://www.physics.mcgill.ca/~obriens/Tutorials/containerized_kernels/). \ No newline at end of file diff --git a/kernel.json b/kernel.json new file mode 100644 index 0000000..716c8c5 --- /dev/null +++ b/kernel.json @@ -0,0 +1,11 @@ +{ + "argv": [ + "/path/to/launch_kernel.sh", + "{connection_file}" + ], + "display_name": "gammapy-kernel", + "language": "python", + "metadata": { + "debugger": true + } +} diff --git a/launch_kernel_apptainer.sh b/launch_kernel_apptainer.sh new file mode 100755 index 0000000..378c0bb --- /dev/null +++ b/launch_kernel_apptainer.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Get the filename of the connection file +connection_file=$(basename $1) +container_name="gammapy_server" +image_name=$GAMMAPY_KERNEL_IMAGE +# Check if the server instance is currently running +if [ $(apptainer instance list $container_name | wc | awk '{print $1}') -ge 2 ]; then + echo "Server is running" +else + # if it isn't start an instance + echo "Starting the server" + # Bind the runtime-dir (where the connection files are) to /connections within the container + apptainer instance start --bind `jupyter --runtime-dir`:/connections $image_name $container_name +fi + +# Attach and run ipykernel_laucher +apptainer exec instance://$container_name python -m ipykernel_launcher -f /connections/$connection_file diff --git a/launch_kernel_docker.sh b/launch_kernel_docker.sh new file mode 100755 index 0000000..4f315f3 --- /dev/null +++ b/launch_kernel_docker.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Get the filename of the connection file +connection_file=$(basename $1) +container_name="gammapy_server" +image_name=$GAMMAPY_KERNEL_IMAGE + +# Check if the server is currently runnong +if [ "$( docker container inspect -f '{{.State.Running}}' $container_name )" = "true" ]; then + echo "Server is running" +else + # if not then start the server + echo "Starting the server" + # Get the path of where the connection files will be stored + connection_path="$(jupyter --runtime-dir)" + # Stop and remove the container if it already exists + docker stop $container_name + docker rm $container_name + # Create a new container + # Add it to the host network and mounting the connection_path + docker create --name=$container_name -v $connection_path:/connections --network=host $image_name + # Start this server instance + docker start $container_name +fi + +# Launch a ipykernel using the connection file that was passed as arg 1 +docker exec $container_name python -m ipykernel_launcher -f /connections/$connection_file