Skip to content

Instantly share code, notes, and snippets.

@datakurre
Last active December 9, 2023 01:41
Show Gist options
  • Save datakurre/49b6fbc4bafdef029183 to your computer and use it in GitHub Desktop.
Save datakurre/49b6fbc4bafdef029183 to your computer and use it in GitHub Desktop.
Multi-kernel Jupyter notebook environment and Docker container with Nix
*.ipynb
*.png
*.tar.gz
.ipynb_checkpoints
.ipython
.jupyter
.sentinel.*
with import <nixpkgs> {};
let dependencies = rec {
builder = builtins.toFile "builder.sh" ''
source $stdenv/setup
mkdir -p $out
cat > $out/kernel.json << EOF
$json
EOF
'';
jupyter = python35Packages.notebook.override {
postInstall = with python35Packages; ''
mkdir -p $out/bin
ln -s ${jupyter_core}/bin/jupyter $out/bin
wrapProgram $out/bin/jupyter \
--prefix PYTHONPATH : "${notebook}/lib/python3.5/site-packages:$PYTHONPATH" \
--prefix PATH : "${notebook}/bin:$PATH"
'';
};
python34 = pkgs.python34.buildEnv.override {
extraLibs = with python34Packages; [
# Kernel
ipykernel
ipywidgets
# Custom packages
beautifulsoup4
# bokeh
# cloudpickle
cython
dill
lightning
matplotlib
numba
numpy
pandas
patsy
pillow
# scikitimage
# scikitlearn
scipy
seaborn
# statsmodels
# sympy
];
};
python34_kernel = stdenv.mkDerivation rec {
name = "python34";
buildInputs = [ python34 ];
json = builtins.toJSON {
argv = [ "${python34}/bin/python3.4"
"-m" "ipykernel" "-f" "{connection_file}" ];
display_name = "Python 3.4";
language = "python";
env = { PYTHONPATH = ""; };
};
inherit builder;
};
haskell_kernel = stdenv.mkDerivation rec {
name = "haskell";
buildInputs = [ ihaskell ];
json = builtins.toJSON {
argv = [ "${ihaskell}/bin/ihaskell"
"kernel" "{connection_file}"
"--ghclib" "${ihaskell}/lib/ghc-7.10.2"];
display_name = "Haskell";
language = "haskell";
env = { PATH = "${ihaskell}/bin"; };
};
builder = writeText "builder.sh" ''
source $stdenv/setup
mkdir -p $out
ln -s ${ihaskell}/share/*ghc*/ihaskell*/html/* $out
cat > $out/kernel.json << EOF
$json
EOF
'';
};
R = rWrapper.override {
packages = with rPackages; [
# Kernel
rzmq
repr
IRkernel
IRdisplay
# Custom packages
RCurl
RSQLite
# dplyr
# forecast
ggplot2
nycflights13
plyr
randomForest
reshape2
# rmarkdown
shiny
stringr
# tidyr
tm
wordcloud
];
};
R_kernel = stdenv.mkDerivation rec {
name = "ir";
buildInputs = [ R ];
json = builtins.toJSON {
argv = [ "${R}/bin/R"
"--slave" "-e" "IRkernel::main()"
"--args" "{connection_file}" ];
display_name = "R";
language = "R";
};
inherit builder;
};
jupyter_config_dir = stdenv.mkDerivation {
name = "jupyter";
buildInputs = [
python34_kernel
haskell_kernel
R_kernel
];
builder = writeText "builder.sh" ''
source $stdenv/setup
mkdir -p $out/etc/jupyter/kernels $out/etc/jupyter/migrated
ln -s ${python34_kernel} $out/etc/jupyter/kernels/${python34_kernel.name}
ln -s ${haskell_kernel} $out/etc/jupyter/kernels/${haskell_kernel.name}
ln -s ${R_kernel} $out/etc/jupyter/kernels/${R_kernel.name}
cat > $out/etc/jupyter/jupyter_notebook_config.py << EOF
import os
c.KernelSpecManager.whitelist = {
'${python34_kernel.name}',
'${haskell_kernel.name}',
'${R_kernel.name}'
}
c.NotebookApp.ip = os.environ.get('JUPYTER_NOTEBOOK_IP', 'localhost')
EOF
'';
};
tini = stdenv.mkDerivation rec {
version = "0.8.3";
name = "tini-${version}";
src = fetchurl {
url = "https://github.com/krallin/tini/archive/v0.8.3.tar.gz";
sha256 ="1w7rj4crrcyv25idmh4asbp2sxzwyihy5mbpw384bzxjzaxn9xpa";
};
NIX_CFLAGS_COMPILE = [
"-DPR_SET_CHILD_SUBREAPER=36"
"-DPR_GET_CHILD_SUBREAPER=37"
];
buildInputs = [ cmake ];
postInstall = ''
rm $out/bin/tini-static
'';
};
};
in with dependencies;
stdenv.mkDerivation rec {
name = "jupyter";
env = buildEnv { name = name; paths = buildInputs; };
builder = builtins.toFile "builder.sh" ''
source $stdenv/setup; ln -s $env $out
'';
buildInputs = [
jupyter
jupyter_config_dir
] ++ stdenv.lib.optionals stdenv.isLinux [ bash fontconfig tini ];
shellHook = ''
mkdir -p $PWD/.jupyter
export JUPYTER_CONFIG_DIR=${jupyter_config_dir}/etc/jupyter
export JUPYTER_PATH=${jupyter_config_dir}/etc/jupyter
export JUPYTER_DATA_DIR=$PWD/.jupyter
export JUPYTER_RUNTIME_DIR=$PWD/.jupyter
'';
}
FROM scratch
ADD default.nix.tar.gz /
ENV FONTCONFIG_FILE="/etc/fonts/fonts.conf" \
JUPYTER_NOTEBOOK_IP="*" \
JUPYTER_CONFIG_DIR="/etc/jupyter" \
JUPYTER_PATH="/etc/jupyter" \
JUPYTER_DATA_DIR="/mnt/.jupyter" \
JUPYTER_RUNTIME_DIR="/mnt/.jupyter"
EXPOSE 8888
ENTRYPOINT ["/bin/tini", "--", "/bin/jupyter"]
IMAGE := jupyter
EXPRESSION := default.nix
DOCKER := docker
BUILDER_IMAGE := nix-builder
DATA_CONTAINER := nix-store
BUILD_OPTIONS := --rm=true --force-rm=true --no-cache=true
IF_STORE = $(DOCKER) ps -a | grep $(DATA_CONTAINER) &&
IF_BUILDER = $(DOCKER) images | grep $(BUILDER_IMAGE) &&
IF_IMAGE = $(DOCKER) images | grep $(IMAGE) &&
IF_NOT_STORE = $(DOCKER) ps -a | grep $(DATA_CONTAINER) ||
IF_NOT_BUILDER = $(DOCKER) images | grep $(BUILDER_IMAGE) ||
MAKE_IMAGE := .sentinel.image
MAKE_BUILDER := .sentinel.builder
run: $(MAKE_IMAGE)
$(DOCKER) run --rm -v $(PWD):/mnt -w /mnt -P $(IMAGE) notebook
image: $(MAKE_IMAGE)
@:
$(MAKE_IMAGE): Dockerfile $(EXPRESSION).tar.gz
$(DOCKER) build -t $(IMAGE) $(BUILD_OPTIONS) .
@touch $(MAKE_IMAGE)
$(EXPRESSION).tar.gz: $(EXPRESSION) $(MAKE_BUILDER)
$(IF_NOT_STORE) $(DOCKER) create --name $(DATA_CONTAINER) $(BUILDER_IMAGE)
$(DOCKER) run --rm --volumes-from=$(DATA_CONTAINER) -v $(PWD):/mnt \
$(BUILDER_IMAGE) /mnt/$(EXPRESSION)
builder: $(MAKE_BUILDER)
@:
$(MAKE_BUILDER): nix-builder.docker nix-builder.sh
$(IF_NOT_BUILDER) $(DOCKER) build -t $(BUILDER_IMAGE) -f nix-builder.docker $(BUILD_OPTIONS) .
@touch $(MAKE_BUILDER)
clean:
$(IF_IMAGE) $(DOCKER) rmi --force=true $(IMAGE) || true
@rm -f $(EXPRESSION).tar.gz $(MAKE_IMAGE) $(MAKE_BUILDER)
purge: clean
$(IF_STORE) $(DOCKER) rm --volumes=true $(DATA_CONTAINER) || true
$(IF_BUILDER) $(DOCKER) rmi --force=true $(BUILDER_IMAGE) || true
.PHONY: run image builder clean
FROM debian:jessie
RUN apt-get update && apt-get install -y curl bzip2 adduser graphviz
RUN adduser --disabled-password --gecos '' user
RUN mkdir -m 0755 /nix && chown user /nix
USER user
ENV USER user
WORKDIR /home/user
RUN curl https://nixos.org/nix/install | sh
VOLUME /nix
COPY nix-builder.sh /home/user/
ENTRYPOINT ["/home/user/nix-builder.sh"]
#!/bin/bash
source ~/.nix-profile/etc/profile.d/nix.sh
mkdir tmp
nix-channel --update
nix-build $1
if [ -h result/etc ]; then echo Error: Build resulted /etc as symlink && exit 1; fi
nix-store -q result --graph | sed 's/#ff0000/#ffffff/' | dot -Nstyle=bold -Tpng > $1.png
tar cvz --transform="s|^result/||" tmp `nix-store -qR result` result/* > $1.tar.gz
@rodfersou
Copy link

you are the best!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment