diff --git a/Dockerfile b/Dockerfile index 0efc883..0550477 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,26 +16,44 @@ ####################################################################################################### # Base image from JupyterLab ####################################################################################################### -ARG BASE_IMAGE=jupyter/base-notebook +ARG BASE_IMAGE=quay.io/jupyter/base-notebook ARG BASE_TAG=latest FROM ${BASE_IMAGE}:${BASE_TAG} -# Update apt and install basic utils +# Update apt and install basic utils that may be helpful for users to install their own dependencies. USER root RUN apt update --yes -RUN apt install --yes --no-install-recommends wget git +RUN apt install --yes --no-install-recommends \ + sudo wget git openssh-client rsync curl + +# Give NB_USER sudo power for "/usr/bin/apt-get install/update" or "/usr/bin/apt install/update". +USER root +RUN groupadd apt-users +RUN usermod -aG apt-users $NB_USER +# Allow members of the apt-users group to execute only apt-get commands without a password +RUN echo "%apt-users ALL=(ALL) NOPASSWD: /usr/bin/apt-get update, /usr/bin/apt-get install *" >> /etc/sudoers +RUN echo "%apt-users ALL=(ALL) NOPASSWD: /usr/bin/apt update, /usr/bin/apt install *" >> /etc/sudoers ####################################################################################################### # Go and GoNB Libraries ####################################################################################################### ARG GO_VERSION=1.23.2 ENV GOROOT=/usr/local/go -ENV GOPATH=/opt/go +ENV GOPATH=$HOME/go ENV PATH=$PATH:$GOROOT/bin:$GOPATH/bin -# Create Go directory for user -- that will not move if the user home directory is moved. -USER root -RUN mkdir ${GOPATH} && chown ${NB_USER}:users ${GOPATH} +# Add exported variables to $NB_USER .profile: notice we start the docker as root, and it executes +# JupyterLab with a `su -l $NB_USER`, so the environment variables are lost. We could use --preserve_environment +# for GOROOT and GOPATH, but it feels safer to add these to .profile, so the autostart.sh script can also +# execute `su -l $NB_USER -c ""` if it wants. +USER $NB_USER +WORKDIR ${HOME} +RUN <> .profile + echo "export PATH=${PATH}" >> .profile + echo "export GOPATH=${GOPATH}" >> .profile + echo "export GOROOT=${GOROOT}" >> .profile +EOF USER root WORKDIR /usr/local @@ -56,7 +74,7 @@ RUN export GOPROXY=direct && \ # Prepare directory where Jupyter Lab will run, with the notebooks we want to demo ####################################################################################################### \ USER root -ARG NOTEBOOKS=/notebooks +ENV NOTEBOOKS=/notebooks # Create directory where notebooks will be stored, where Jupyter Lab will run by default. RUN mkdir ${NOTEBOOKS} && chown ${NB_USER}:users ${NOTEBOOKS} @@ -77,8 +95,11 @@ USER root RUN apt-get clean && rm -rf /var/lib/apt/lists/* # Start-up. -USER $NB_USER +USER root WORKDIR ${NOTEBOOKS} -EXPOSE 8888 -ENTRYPOINT ["tini", "-g", "--", "jupyter", "lab"] +# Script that checks for `autostart.sh` (and runs it if owned by root and present), and then starts +# JupyterLab. +COPY cmd/check_and_run_autostart.sh /usr/local/bin/ + +ENTRYPOINT ["tini", "-g", "--", "/usr/local/bin/check_and_run_autostart.sh"] diff --git a/README.md b/README.md index 36cf76c..9cf91f7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# GoNB, A Modern Go Kernel for Jupyter Notebooks +# GoNB, A Modern Go Kernel for Jupyter πŸ““NotebooksπŸ““ [![GoDev](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white)](https://pkg.go.dev/github.com/janpfeifer/gonb?tab=doc) [![GitHub](https://img.shields.io/github/license/janpfeifer/gonb)](https://github.com/Kwynto/gosession/blob/master/LICENSE) @@ -9,15 +9,12 @@ -## For a quick start, see the [**tutorial**](examples/tutorial.ipynb)! +## For a quick start, see the [**tutorial** 🧭](examples/tutorial.ipynb) -## Highlights: +## ✨ Highlights: -* **NEW**: Now supported by [Jupytext](https://github.com/mwouts/jupytext): it allows one to write the notebook as a normal. - Go file, and use [Jupytext](https://github.com/mwouts/jupytext) to convert to a notebook (with markdown support, etc). - See [example](https://github.com/mwouts/jupytext/issues/1244#issuecomment-2202097837). * Auto-complete and contextual help while coding. * Rich content display: HTML, markdown (with latex), images, javascript, svg, videos, etc. * Widgets (sliders, buttons) support: interact using HTML elements. Create your own widgets! @@ -27,6 +24,9 @@ It also supports arbitrary Go compilation flags to be used when executing the cells. * Faster execution than interpreted Go, used in other similar kernels -- at the cost of imperceptible increased start up, since each cell is compiled. +* Supported by [Jupytext](https://github.com/mwouts/jupytext): it allows one to write the notebook as a normal. + Go file, and use [Jupytext](https://github.com/mwouts/jupytext) to convert to a notebook (with markdown support, etc). + See [example](https://github.com/mwouts/jupytext/issues/1244#issuecomment-2202097837). * Run cell's `Test*` and `Benchmark*` functions with `go test`, simply adding `%test` to cell. * Support for `go.mod` and `go.work`, to allow local development. Including importing specific versions of libraries. * Debug using [gdlv](https://github.com/aarzilli/gdlv), a GUI for the [delve](https://github.com/go-delve/delve) debugger (see %help). @@ -38,7 +38,7 @@ * Online help and much more, see `%help`. * Compile and execute the Go code as WASM: allows one to do interactive widgets in notebooks. See `%wasm` (EXPERIMENTAL). -## Examples: +## πŸ‘οΈβ€πŸ—¨οΈ Examples: ### Auto-complete and Contextual Help @@ -57,7 +57,7 @@ https://github.com/janpfeifer/gonb/assets/7460115/f1187dad-4c10-4d21-a73e-909001 Browser Screenshot Demo -## Introduction +## 🌱 Introduction Go is a compiled language, but with very fast compilation, that allows one to use it in a REPL (Read-Eval-Print-Loop) fashion, by inserting a "Compile" step in the middle @@ -84,15 +84,15 @@ There is also that one can interact with (make a copy first) β€” if the link doesn't work (Google Drive sharing publicly is odd), [download it from GitHub](examples/google_colab_demo.ipynb) and upload it to Google's Colab. -Finally, because it's compiled and not intepreted, it has a slightly different "semantic" than the Python kernels. +Finally, because it's compiled and not interpreted, it has a slightly different "semantic" than the Python kernels. It's highly recommended quickly browsing through the [**tutorial**](examples/tutorial.ipynb). -## Installation +## πŸ“¦ Installation **Only for Linux and macOS. In Windows, it works in WSL or inside a Docker** -### Docker +### 🐳 Docker GoNB offers a [pre-built docker](https://hub.docker.com/r/janpfeifer/gonb_jupyterlab), that includes JupyterLab and GoNB. @@ -104,11 +104,13 @@ To start it: ```shell docker pull janpfeifer/gonb_jupyterlab:latest -docker run -it --rm -p 8888:8888 -v "${PWD}":/notebooks/host janpfeifer/gonb_jupyterlab:latest +docker run -it --rm -p 8888:8888 -v "${PWD}":/notebooks janpfeifer/gonb_jupyterlab:latest ``` Then copy&paste the URL that it outputs in your browser. +**Note**: The docker allows for customization by running an arbitrary script at start up as `root`, which allows +one to install any planned dependencies. See [docker.md](docs/docker.md) for details. ### Linux and macOS Installation Using Standard Go Tools @@ -149,7 +151,7 @@ Install there as if it were in a linux machine. A pure Windows installation is not supported at this time β€” but contributions to add support for it would be welcome :) -## FAQ +## πŸ€” FAQ * Is there are reference documentation ? * There is a help (run `%help` in a cell) and a [**tutorial**](examples/tutorial.ipynb), which is kept up-to-date and @@ -163,7 +165,7 @@ A pure Windows installation is not supported at this time β€” but contributions solutions to this. Often folks create a series of `Must()` functions, or simply use [this trivial `must` package](https://github.com/janpfeifer/must). -## TODOs +## πŸ“ TODOs Contributions are welcome! @@ -171,7 +173,7 @@ Contributions are welcome! * Installation. * Named-pipe implementation in `kernel/pipeexec.go`. -## Thanks +## πŸ’– Thanks * [Go](golang.org) * [Jupyter](https://jupyter.org/), what an awesome project. @@ -180,7 +182,7 @@ Contributions are welcome! (http://reneefrench.blogspot.com/), see Creative Commons 3.0 Attributions license in [Wikimedia](https://commons.wikimedia.org/wiki/File:Go_gopher_favicon.svg). -## Contributing +## 🀝 Contributing Contributions are very welcome. The code is generally well documented -- not always, but mostly. There are a also a couple of guides worth reading if contributing in the [`docs/`](https://github.com/janpfeifer/gonb/tree/main/docs) subdirectory. @@ -189,6 +191,6 @@ There are two parts of the project: 1. The kernel itself: that builds the binary package. Most subpackages are under `internal/`. 2. The UI library in the packages under `github.com/janpfeifer/gonb/gonbui`. -## Star History +## 🌟 Star History [![Star History Chart](https://api.star-history.com/svg?repos=janpfeifer/gonb&type=Date)](https://star-history.com/#janpfeifer/gonb&Date) diff --git a/binder/postBuild b/binder/postBuild index 2919d35..dde86be 100755 --- a/binder/postBuild +++ b/binder/postBuild @@ -1,7 +1,7 @@ #!/bin/bash set -eu -GO_VERSION=1.20 +GO_VERSION=1.23.2 curl -sfL https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz | tar -xz diff --git a/cmd/check_and_run_autostart.sh b/cmd/check_and_run_autostart.sh new file mode 100755 index 0000000..b12ca93 --- /dev/null +++ b/cmd/check_and_run_autostart.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# This script is included in the Docker, and is executed at startup of the docker, allowing the user to write +# an arbitrary setup script in `autostart.sh` for the image -- things like installing databases, credentials, etc. +# +# Notice ${NOTEBOOKS} is /notebooks in the container, and is assumed to be mounted from the host directory that +# will have the users notebooks. + +# Makes sure we are not using $NB_USER's GOPATH. +export GOPATH=/root/go + +# Check if autostart.sh exists +if [[ -f "${NOTEBOOKS}/autostart.sh" ]]; then + # Check if it's owned by root and is executable + if [[ "$(stat -c '%U' "${NOTEBOOKS}/autostart.sh")" = "root" && -x "${NOTEBOOKS}/autostart.sh" ]]; then + # Run autostart.sh as root + echo "Running autostart.sh as root..." + "${NOTEBOOKS}/autostart.sh" + else + # Print a message indicating why it's not running + echo "autostart.sh exists but is not owned by root or not executable. Not running it." + fi +else + echo "No autostart.sh initialization script." +fi + +# Run JupyterLab from $NOTEBOOKS as user $NB_USER. +su -l "${NB_USER}" -c "cd \"${NOTEBOOKS}\" ; jupyter lab" diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index fcc526f..2cd598a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,14 @@ # GoNB Changelog +## Next + +* Feature request #138 + * Added openssh-client, rsync and curl, to allow users to install other dependencies. + * Added sudo for apt install and apt update. + * Added support for `autostart.sh` that if present in the mounted container `/notebooks` directory, and if root owned + and set as executable. +* Updated Dockerfile to latest version to JupyterLab -- now the base docker is served `quay.io/jupyter/base-notebook` + ## v0.10.5, Added SendAsDownload * Added `dom.SendAsDownload` to send data from cells to the client by triggering a browser download. #134 diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 0000000..18f9f46 --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,41 @@ +# Docker Customization + +1. The docker runs _JupyterLab_ and _GoNB_ under the user `$NB_USER` (== "jovyan"). +2. It has configured `sudo` privileges for `apt update` and `apt install *`. So a cell with + `!sudo apt install ` will work, and install your package. +3. One can always create another docker based on `janpfeifer/gonb_jupyterlab@latest` +4. Create an `autostart.sh` script, see next section. + +## Customization with `autostart.sh` + +If you create the file `autostart.sh` in the directory mounted under `/notebooks` in the container, +**owned by `root` and with executable permissions**, it will be executed at start up of the container by default +**as `root`**. + +This allows you to download/install databases, or set up credentials, etc. + +Example of an `autostart.sh` that: + +- Sets the timezone +- Installs [`nats`](github.com/nats-io/natscli/) for the jupyer user (given by `$NB_USER`). + +``` +# Set the German timezone (so time.Now() returns German time) +apt-get install -y tzdata +ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime + +# some locale magic to make "date" answer with German format +echo 'de_DE.UTF-8 UTF-8' >> /etc/locale.gen +locale-gen +echo 'LC_ALL="de_DE.utf8"' > /etc/default/locale +export LC_ALL="de_DE.UTF-8" +dpkg-reconfigure locales + +# check that it works +date + +# Installing Go tools for $NB_USER. +su -l "$NB_USER" -c "go install github.com/nats-io/natscli/nats@latest" +``` + +More details in the `Dockerfile` and in the small start script `cmd/check_and_run_autostart.sh`.