Installation via containers

Unlike the direct installation method, here you will only need to have one program directly installed on your computer (other software will be installed in the image itself) - Docker, which we will use to create our software image. This image will then be used as a read-only (i.e. immutable) template for quick container creation.

You can also install the following software:

Install the above software (or, at the very least, just the docker software) and proceed to the next section.

Important

The resulting docker image is designed for learning purposes on your own machine only. It’s not meant (nor is it safe) to deploy the created image on cloud or production servers, as it doesn’t contain any security measures at all.

Tip

You don’t need an account to use docker. Furthermore, to prevent accidentally pushing an image to a public docker registry it is recommended to avoid creating an account or logging in, at least until you are more familiar with docker.

Note

If you are unfamiliar with docker then, after installing the appropriate software, see the following sections:

  • See the section on the linux command line - our docker image is based on Ubuntu, so we will need to be familiar with some of the most common terminal commands.
  • See the section on docker basics, which contains a number of examples on how to build simple images, create and access containers, as well as remove older ones.

Full docker image and configuration files

Our main goal is to create a docker image with the following software, which we will access through our web browser:

  • RStudio server.
  • JupyterLab.
  • code-server.

In order to manage these applications easier, we will utilize nginx as a reverse proxy and create a static .html webpage with links to the apps inside the container. We will also use supervisor, which will launch and monitor all of the above software when we start the container.

On your desktop create a folder named dockerDS and then create the following folder/file1 structure:

dockerDS
├── config
   ├── rstudio
   │   ├── rserver.conf
   │   ├── rsession.conf
   │   ├── logging.conf
   │   ├── rstudio-prefs.json
   │   ├── rstudio_bindings.json
   │   ├── editor_bindings.json
   │   ├── addins.json
   │   └── environment.txt
   │   └── install_libraries.R
   ├── python
   │   ├── ipython_config.py
   │   ├── jupyter_lab_config.py
   │   ├── jupyter_server_config.py
   │   └── requirements.txt
   ├── code-server
   │   └── config.yaml
   ├── nginx
   │   └── nginx.conf
   ├── www
   │   └── index.html
   └── supervisor
       ├── supervisord.conf
       ├── nginxgo.conf
       ├── rserver.conf
       ├── jupyterlab.conf
       └── codeserver.conf
└── datascience.dockerfile

To summarize the above:

  • Inside the dockerDS folder create a folder named config.
  • Inside the config folder create the following folders: rstudio, python, code-server, nginx, www and supervisor.
  • Populate the folders with specific files that are outlined below.

Configuration files for rstudio

Inside /dockerDS/config/rstudio/ directory add the following files2:

Create /dockerDS/config/rstudio/rserver.conf with the following content:

# /etc/rstudio/rserver.conf
# RStudio Server Configuration File
## https://docs.posit.co/ide/server-pro/reference/rserver_conf.html#server-settings

www-address=127.0.0.1
www-port=8787

auth-timeout-minutes=0
auth-stay-signed-in-days=365

See the official rserver.conf documentation for a list of available options. We are interested in the following options:

  • www-address - the network address that RStudio server will listen on for incoming connections. We want to use a reverse proxy, so we should set it to 127.0.0.1. Otherwise, we would have to specify 0.0.0.0.

  • www-port - the port that RStudio server will bind to while listening for incoming connections. See this answer on stackoverflow for more info on ports.

  • auth-timeout-minutes - the number of minutes a user will stay logged in while idle before required to sign in again. We set this to 0 to disable it.

  • auth-stay-signed-in-days - the number of days to keep a user signed in when using the “Stay Signed In” option. We set this to 365 days in order to prevent disconnections due to inactivity.

If you find some other options that you may need to tweak, feel free to customize this file.

Create /dockerDS/config/rstudio/rsession.conf with the following content:

# /etc/rstudio/rsession.conf
# R Session Configuration File
## https://docs.posit.co/ide/server-pro/reference/rsession_conf.html#session-settings
## https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/directory_management.html

session-timeout-minutes=0

session-default-working-dir=/media/container_shared/
session-default-new-project-dir=/media/container_shared/

restrict-directory-view=1
directory-view-allow-list=/media/container_shared/

See the official rsession.conf documentation for a list of available options. We are interested in the following options:

  • session-timeout-minutes - the amount of minutes before a session times out, at which point the session will either suspend or exit. We set it to 0 to disable the time out timer.

  • session-default-working - specifies the default working directory to use for new sessions. We will use persistent volumes to save our projects and user settings, so we specify that this directory will be inside the /media/container_shared/ directory in the docker image/container.

  • session-default-new-project-dir - specifies the default directory to use for new projects. A similar (now deprecated) . We will leave it set the same as session-default-working just in case.

  • restrict-directory-view - indicates whether or not to restrict the directories that can be viewed within the IDE. Since the data inside the docker container won’t be mutable, we don’t want to accidentally save important files inside the container. That is why we set it to 1. Note that this does not prevent us from seeing the directories themselves inside the container, but it prevents opening/saving files in the container itself.

  • directory-view-allow-list - specifies a list of directories exempt from directory view restrictions, separated by a colon character. Along with the restrict-directory-view setting, we set /media/container_shared/ as the only directory for loading/saving files in our container.

Create /dockerDS/config/rstudio/logging.conf with the following content:

# /etc/rstudio/logging.conf
# Logging Configuration file

## https://docs.posit.co/ide/server-pro/server_management/logging.html#configuration-file

[*]
log-level=info
logger-type=stderr

# Prevent INFO messages being print to stdout in RStudio Server
[@rsession-rstudio]
log-level=warn
logger-type=syslog

The above logging configuration file is used to set RStudio server messages to stderr, which will be captured by our supervisor process. Note that we change the logging to syslog for the @rsession-rstudio process, since its warning and error output would be printed directly to our rstudio session console window. More configuration options can be found in the official documentation on logging configuration.

Create /dockerDS/config/rstudio/rstudio-prefs.json with the following content:

{
    "save_workspace": "never",
    "always_save_history": false,
    "reuse_sessions_for_project_links": true,
    "posix_terminal_shell": "bash",
    "rainbow_parentheses": true
}

Two important links relating to customizing RStudio preferences:

  • Session user settings - a list of settings supported in the rstudio-prefs.json file, along with their type, allowable values, and defaults.

  • Customizing session settings - contains general documentation on additional customization options, if needed.

The settings that we have changed are:

  • save_workspace - whether to save the workspace to an .Rdata file after the R session ends. We usually want have a fresh start with a clean environment in order to guarantee replicable results.

  • always_save_history - we’ll use .R scripts and do not need to save every single command that we’ve run throughout our sessions.

  • reuse_sessions_for_project_links- whether to reuse sessions when opening projects in rstudio. If we have multiple projects that we will access throughout our session, there is no need to restart the session. The idea is that our projects should have code that clear the working environment.

  • posix_terminal_shell - the terminal shell to use on POSIX operating systems (Linux/MacOS). We will specify a bash terminal shell to have some file coloring.

  • rainbow_parentheses - whether to highlight parentheses in a variety of colors. Useful if we have multiple parenthesis in our code and want an easier way to identify them.

Feel free to customize this file to suit your needs. Note that you will also be able to change and store persistent settings in the following directory in our shared folder: /media/container_shared/.rstudio. This file simply defines the “default” settings.

Create /dockerDS/config/rstudio/rstudio_bindings.json with the following content:

{
    "closeSourceDoc": "Ctrl+Alt+W"
}

RStudio server opens in the browser, so pressing Ctrl+W will close the browser tab instead of closing the .R code tab inside the RStudio server editor. To prevent this, we define a new shortcut for closing files inside the RStudio editor as Ctrl+Alt+W.

Create /dockerDS/config/rstudio/editor_bindings.json with the following content:

{}

This file contains no custom bindings but is required to prevent warning messages from RStudio server.

Create /dockerDS/config/rstudio/addins.json with the following content:

{}

This file contains no custom bindings but is required to prevent warning messages from RStudio server.

Create /dockerDS/config/rstudio/environment.txt with the following content:

AER
DAAG
DT
GGally
IRdisplay
IRkernel
MASS
Matrix
OECD
RCurl
ROCR
Rcpp
Rcrawler
arrow
astsa
bookdown
caTools
car
caret
cowplot
crayon
data.table
devtools
doParallel
doSNOW
dplyr
dyn
dynlm
e1071
eurostat
fGarch
fUnitRoots
duckdb
fansi
feather
fma
fontawesome
foreach
forecast
fpp
fpp2
fpp3
gdata
ggiraph
ggplot2
ggvis
glmnet
gplots
gt
htmltools
htmlwidgets
imputeTS
kableExtra
knitr
languageserver
fst
lars
latex2exp
lattice
leaps
lmtest
lrmest
lubridate
mFilter
markdown
mfx
mice
microbenchmark
mlr3
mlr3verse
multcomp
nnet
nortest
orcutt
pROC
pak
patchwork
pbdZMQ
plm
plotly
polynom
posterior
prophet
quantmod
randomForest
readxl
renv
repr
reshape2
purrr
qs
reticulate
rmarkdown
rpart
rpart.plot
rstudioapi
rugarch
rzmq
sandwich
seasonal
shiny
shinydashboard
shinythemes
rvest
spdep
stargazer
stringr
swirl
tempdisagg
tidymodels
tidyverse
tree
tsDyn
tseries
txtplot
urca
vars
viridisLite
waveslim
writexl
yaml
zoo
skimr
vroom

The above file contains a list of all of the libraries, that we want to install in our docker image. If you need additional libraries - make sure to add them to the list.

Create /dockerDS/config/rstudio/install_libraries.R with the following content:

# Pass argument to script to change working directory to the file location
# e.g., Rscript /tmp/install_libraries.R /tmp/
args <- commandArgs(trailingOnly = TRUE)
if(length(args) > 0){
  setwd(args[1])
}

## Read the file with the list of libraries:
lib_list <- unname(unlist(na.omit(read.table("./environment.txt"))))

## Drop any packages, which are already installed as the base, or recommended packages:
new_packages <- installed.packages()[installed.packages()[,'Package'] %in% lib_list, ]
new_packages <- data.frame(new_packages[, c("Package", "Version", "Priority")])
new_packages <- new_packages[(new_packages$Priority %in% c("base", "recommended")), ]
if(nrow(new_packages) > 0){
  lib_list <- setdiff(lib_list, unique(new_packages$Package))
}

## Install the remaining libraries (uses the default CRAN, which is set by the dockerfile)
install.packages(lib_list)

## Other libraries, that are outside of CRAN (only latest versions):
install.packages("polars", repos = "https://rpolars.r-universe.dev/bin/linux/jammy/4.3") 
install.packages("cmdstanr", repos = c("https://mc-stan.org/r-packages/", getOption("repos")))
# https://pkg.yangzhuoranyang.com/tsdl/articles/tsdl.html
devtools::install_github("FinYang/tsdl")

The above code will load the environment.txt file and install its libraries, along with a couple libraries from external (i.e. non-CRAN) sources. We will override the default CRAN URL with one from Posit Package Manager globally inside the docker image, so no other settings are necessary.

Configuration files for python and jupyterLab

Inside /dockerDS/config/python/ directory add the following files:

Create /dockerDS/config/python/ipython_config.py with the following content:

# Configuration file for ipython.

c = get_config()  #noqa

c.Completer.use_jedi = False

The above config file with the commented-out default settings can be generated by running the following terminal commands inside the docker container:

ipython profile create
ipython --debug -c 'exit()'

Note that c = get_config() is always included, as it sets the default configuration. The other option that we need is:

  • c.Completer.use_jedi - we disable Jedi, an autocompletion and code analysis library for Python. It is sometimes quite slow, so we disable it.

Create /dockerDS/config/python/jupyter_lab_config.py with the following content:

# Configuration file for lab.

c = get_config()  #noqa

c.ServerApp.ip = '127.0.0.1'
c.ServerApp.port = 8888
c.IdentityProvider.token = ''
c.ServerApp.base_url = '/jupyterlab/'
c.ServerApp.open_browser = False
c.ServerApp.disable_check_xsrf = False
c.ServerApp.root_dir = '/media/container_shared/'
c.ServerApp.terminado_settings = {'shell_command': ['/bin/bash']}
c.LabApp.user_settings_dir = '/media/container_shared/.jupyter/lab/user-settings/'

The config file with the commented-out default settings can be generated by running the following terminal command inside the docker container:

jupyter lab --generate-config

Note that c = get_config() is always included, as it sets the default configuration. The other options that we need are:

  • c.ServerApp.ip - the IP address the Jupyter server will listen on.
  • c.ServerApp.port - the port that the Jupyter server will listen on.
  • c.IdentityProvider.token - by default a random token will be generating as part of the server url. We disable it by default.
  • c.ServerApp.base_url - base URL for the Jupyter server.
  • c.ServerApp.open_browser - whether to open in a browser after starting. Since we are connecting to the Jupyter server on a docker container, we disable this option as it only works on a local Jupyter installation.
  • c.ServerApp.disable_check_xsrf - Jupyter server includes protection from cross-site request forgeries. We disable all authentication and security checks under the assumption that we will always run this container on our machine.
  • c.ServerApp.root_dir - the directory to use for notebooks and kernels. We set it to our shared directory - /media/container_shared/.
  • c.ServerApp.terminado_settings - we set the terminal window inside Jupyter server to be a bash terminal.
  • c.LabApp.user_settings_dir - we want the user settings to persist, so we set them to /media/container_shared/.jupyter/lab/user-settings/.

Create /dockerDS/config/python/jupyter_server_config.py with the following content:

# Configuration file for jupyter-server.

c = get_config()  #noqa

c.ContentsManager.allow_hidden = True

The config file with the commented-out default settings can be generated by running the following terminal command inside the docker container:

jupyter server --generate-config

Note that c = get_config() is always included, as it sets the default configuration. The other option that we need is:

  • c.ContentsManager.allow_hidden - allow access to hidden files.

Create /dockerDS/config/python/requirements.txt with the following content:

--find-links https://download.pytorch.org/whl/torch_stable.html
absl-py==2.1.0
aiohttp==3.9.3
aiohttp-cors==0.7.0
aiosignal==1.3.1
altair==5.2.0
anyio==4.2.0
argon2-cffi==23.1.0
argon2-cffi-bindings==21.2.0
arrow==1.3.0
arviz==0.17.0
asciitree==0.3.3
asttokens==2.4.1
astunparse==1.6.3
async-lru==2.0.4
attrs==23.2.0
Babel==2.14.0
bambi==0.13.0
beartype==0.17.0
beautifulsoup4==4.12.3
bleach==6.1.0
blessed==1.20.0
blinker==1.7.0
bokeh==2.4.3
cachetools==5.3.2
certifi==2024.2.2
cffi==1.16.0
cftime==1.6.3
charset-normalizer==3.3.2
click==8.1.7
click-default-group==1.2.4
cloudpickle==3.0.0
cloup==2.1.2
cmdstanpy==1.2.0
colorama==0.4.6
colorful==0.5.6
comm==0.2.1
commonmark==0.9.1
cons==0.4.6
contourpy==1.2.0
cycler==0.12.1
dask==2024.1.1
datar==0.15.4
datatable==1.1.0
debugpy==1.8.0
decorator==5.1.1
defusedxml==0.7.1
diot==0.2.3
distlib==0.3.8
distributed==2024.1.1
duckdb==0.9.2
etuples==0.3.9
executing==2.0.1
fasteners==0.19
fastjsonschema==2.19.1
fastprogress==1.0.3
filelock==3.13.1
flatbuffers==23.5.26
fonttools==4.47.2
formulae==0.5.1
fqdn==1.5.1
frozenlist==1.4.1
fsspec==2023.12.2
gast==0.5.4
gitdb==4.0.11
GitPython==3.1.41
glcontext==2.5.0
google-api-core==2.16.2
google-auth==2.27.0
google-auth-oauthlib==1.2.0
google-pasta==0.2.0
googleapis-common-protos==1.62.0
gpustat==1.1.1
graphviz==0.20.1
great-tables==0.2.0
greenlet==3.0.3
griffe==0.40.0
grpcio==1.60.1
h5netcdf==1.3.0
h5py==3.10.0
htmltools==0.5.1
idna==3.6
importlib-metadata==7.0.1
importlib-resources==6.1.1
inflection==0.5.1
ipykernel==6.29.0
ipython==8.21.0
ipywidgets==8.1.1
isoduration==20.11.0
isosurfaces==0.1.0
jedi==0.19.1
Jinja2==3.1.3
joblib==1.3.2
json5==0.9.14
jsonpointer==2.4
jsonschema==4.21.1
jsonschema-specifications==2023.12.1
jupyter==1.0.0
jupyter-cache==1.0.0
jupyter-console==6.6.3
jupyter-events==0.9.0
jupyter-lsp==2.2.2
jupyter_client==8.6.0
jupyter_core==5.7.1
jupyter_server==2.12.5
jupyter_server_terminals==0.5.2
jupyterlab==4.0.12
jupyterlab-lsp==5.0.2
jupyterlab-widgets==3.0.9
jupyterlab_pygments==0.3.0
jupyterlab_server==2.25.2
keras==2.15.0
kiwisolver==1.4.5
lckr_jupyterlab_variableinspector==3.2.1
libclang==16.0.6
llvmlite==0.42.0
locket==1.0.0
logical-unification==0.4.6
manim==0.18.0
ManimPango==0.5.0
mapbox-earcut==1.0.1
Markdown==3.5.2
markdown-it-py==3.0.0
MarkupSafe==2.1.5
matplotlib==3.8.2
matplotlib-inline==0.1.6
mdurl==0.1.2
miniKanren==1.0.3
mistune==3.0.2
mizani==0.9.3
ml-dtypes==0.2.0
moderngl==5.10.0
moderngl-window==2.4.4
modin==0.26.1
modin-spreadsheet==0.1.2
mpmath==1.3.0
msgpack==1.0.7
multidict==6.0.5
multipledispatch==1.0.0
nbclient==0.9.0
nbconvert==7.14.2
nbformat==5.9.2
nest-asyncio==1.6.0
netCDF4==1.6.5
networkx==3.2.1
notebook==7.0.7
notebook_shim==0.2.3
numba==0.59.0
numcodecs==0.12.1
numexpr==2.9.0
numpy==1.26.3
nvidia-ml-py==12.535.133
oauthlib==3.2.2
opencensus==0.11.4
opencensus-context==0.1.3
opt-einsum==3.3.0
overrides==7.7.0
packaging==23.2
pandas==2.1.4
pandocfilters==1.5.1
parso==0.8.3
partd==1.4.1
patsy==0.5.6
pexpect==4.9.0
Pillow==9.5.0
pipda==0.13.1
platformdirs==4.2.0
plotnine==0.12.4
plum-dispatch==2.3.2
polars==0.20.6
prometheus-client==0.19.0
prompt-toolkit==3.0.43
protobuf==4.23.4
psutil==5.9.8
ptyprocess==0.7.0
pure-eval==0.2.2
py-spy==0.3.14
pyarrow==15.0.0
pyasn1==0.5.1
pyasn1-modules==0.3.0
pycairo==1.25.1
pycparser==2.21
pydantic==1.10.14
pydeck==0.8.1b0
pydub==0.25.1
pyglet==2.0.10
Pygments==2.17.2
pymc==5.10.3
pyparsing==3.1.1
pyrr==0.10.3
pytensor==2.18.6
python-dateutil==2.8.2
python-json-logger==2.0.7
python-simpleconf==0.6.0
pytz==2024.1
PyYAML==6.0.1
pyzmq==25.1.2
qtconsole==5.5.1
QtPy==2.4.1
quartodoc==0.7.2
ray==2.9.1
referencing==0.33.0
requests==2.31.0
requests-oauthlib==1.3.1
rfc3339-validator==0.1.4
rfc3986-validator==0.1.1
rich==13.7.0
rpds-py==0.17.1
rsa==4.9
scikit-learn==1.4.0
scipy==1.12.0
screeninfo==0.8.1
seaborn==0.13.2
Send2Trash==1.8.2
simplug==0.3.2
siuba==0.4.2
six==1.16.0
skia-pathops==0.7.4
skimpy==0.0.14
smart-open==6.4.0
smmap==5.0.1
sniffio==1.3.0
sortedcontainers==2.4.0
soupsieve==2.5
sphobjinv==2.3.1
SQLAlchemy==2.0.25
srt==3.5.3
stack-data==0.6.3
stanio==0.3.0
statsmodels==0.14.1
streamlit==1.31.0
svgelements==1.9.6
sympy==1.12
tabulate==0.9.0
tblib==3.0.0
tenacity==8.2.3
tensorboard==2.15.1
tensorboard-data-server==0.7.2
tensorflow==2.15.0.post1
tensorflow-estimator==2.15.0
tensorflow-io-gcs-filesystem==0.35.0
termcolor==2.4.0
terminado==0.18.0
threadpoolctl==3.2.0
tinycss2==1.2.1
toml==0.10.2
toolz==0.12.1
torch==2.2.0+cpu
torchaudio==2.2.0+cpu
torchvision==0.17.0+cpu
tornado==6.4
tqdm==4.66.1
traitlets==5.14.1
typeguard==4.1.5
types-python-dateutil==2.8.19.20240106
typing_extensions==4.9.0
tzdata==2023.4
tzlocal==5.2
ujson==5.9.0
uri-template==1.3.0
urllib3==2.2.0
validators==0.22.0
virtualenv==20.25.0
watchdog==3.0.0
wcwidth==0.2.13
webcolors==1.13
webencodings==0.5.1
websocket-client==1.7.0
Werkzeug==3.0.1
widgetsnbextension==4.0.9
wrapt==1.14.1
xarray==2024.1.1
xarray-datatree==0.0.13
xarray-einstats==0.7.0
yarl==1.9.4
zarr==2.16.1
zict==3.0.0
zipp==3.17.0

The above file contains the names and versions of various libraries (main libraries along with their dependent libraries).

Configuration files for code-server (vscode)

Inside /dockerDS/config/code-server/ directory, add the following file:

Create /dockerDS/config/code-server/config.yaml with the following content:

# /root/.config/code-server/config.yaml
# Code Server Configuration file
# Each key in the file maps directly to a code-server flag 
# (run code-server --help to see a listing of all the flags). 
# Any flags passed to code-server will take priority over the config file.

bind-addr: 127.0.0.1:8080
auth: none
cert: false
user-data-dir: /media/container_shared/.vscode/
extensions-dir: /root/.local/share/code-server/extensions/
disable-telemetry: true
disable-update-check: true
disable-workspace-trust: true

Additional settings can be found by running code-server --help inside the container.

The settings that we have changed are:

  • bind-addr - address to bind to in host:port.

  • auth - type of authentication to use. We don’t want to have any authentication, so we set it to none.

  • cert - the ability to secure your connection between client and server using SSL/TSL certificates. Since we are connecting to this container locally - we won’t setup any certificates.

  • user-data-dir - we make sure that the user settings of code-server ar saved to /media/container_shared/.vscode/. This ensures that our settings persist even when we remove or create new containers.

  • extensions-dir - we will install code-server extensions under the root user in /root/.local/share/code-server/extensions/. In order for us to access these extensions, we have to change the extensions directory. Note that this will prevent us from installing more extensions.

  • disable-telemetry - we disable telemetry data collection.

  • disable-update-check - we don’t want to check if a never version is available, since docker containers are immutable.

  • disable-workspace-trust - workspace trust is a feature driven by the security risks associated with unintended code execution when a user opens a workspace in vscode. We disable this feature to prevent continuous popups about workspace trust, under the assumption that the contents of any loaded workspace are not malicious. In production environments, this safety feature is very important.

Configuration files for nginx

nginx is a web server that can also be used as a reverse proxy (video example).

Inside /dockerDS/config/nginx/ directory, add the following file:

Create /dockerDS/config/nginx/nginx.conf with the following content:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

# Enable to run in foreground for supervisor; https://stackoverflow.com/a/28099946
# daemon off;

events {
    worker_connections 768;
    # multi_accept on;
}

http {

  # https://stackoverflow.com/a/23764479
  # https://github.com/jupyterlab/jupyterlab/issues/4214
  # http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size
  client_max_body_size 0;

  map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
  }

  server {
    listen 80;
    
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    # Static webpage
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    root /www/static;
    gzip_static on;
    
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    # Supervisor
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    location /supervisor/ {
      rewrite ^/supervisor(/.*) $1 break;
      proxy_pass http://localhost:9001/;
      proxy_redirect http://localhost:9001/ $scheme://$host/supervisor/;
      proxy_set_header Host $host/supervisor/;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
    }
    
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    # RStudio Server
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    
    # https://github.com/rstudio/rstudio/issues/2834#issuecomment-459502330
    rewrite ^/auth-sign-in(.*) "$scheme://$server_name/rstudio/auth-sign-in$1?appUri=%2Frstudio"; 
    rewrite ^/auth-sign-out(.*) "$scheme://$server_name/rstudio/auth-sign-out$1?appUri=%2Frstudio";
    location /rstudio/ {
      rewrite ^/rstudio/(.*)$ /$1 break;
      proxy_pass http://localhost:8787;
      proxy_redirect http://localhost:8787/ $scheme://$host/rstudio/;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
      proxy_read_timeout 20d;
    }
    
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    # JupyterLab
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    
    # https://jupyterhub.readthedocs.io/en/1.2.0/installation-guide-hard.html#using-nginx
    # https://blog.nathantsoi.com/article/run-jupyter-notebook-behind-a-nginx-reverse-proxy-subpath/
    location /jupyterlab/ {
      #rewrite /jupyterlab(.*) $1  break;
      proxy_pass http://localhost:8888;
      # pass some extra stuff to the backend
      proxy_set_header Host $host;
      proxy_set_header X-Real-Ip $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    # location ~* /jupyter/(api/kernels/[^/]+/(channels|iopub|shell|stdin)|terminals/websocket|lsp/)/? {...}
    location ~ /jupyterlab/api/kernels/ {
      proxy_pass            http://localhost:8888;
      proxy_set_header      X-Real-IP $remote_addr;
      proxy_set_header      Host $host;
      proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
      # websocket support
      proxy_http_version    1.1;
      proxy_set_header      Upgrade "websocket";
      proxy_set_header      Connection "Upgrade";
      proxy_read_timeout    86400;
    }
    location ~ /jupyterlab/terminals/ {
      proxy_pass            http://localhost:8888;
      proxy_set_header      X-Real-IP $remote_addr;
      proxy_set_header      Host $host;
      proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
      # websocket support
      proxy_http_version    1.1;
      proxy_set_header      Upgrade "websocket";
      proxy_set_header      Connection "Upgrade";
      proxy_read_timeout    86400;
    }
    location ~ /jupyterlab/api/events/ {
      proxy_pass            http://localhost:8888;
      proxy_set_header      X-Real-IP $remote_addr;
      proxy_set_header      Host $host;
      proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
      # websocket support
      proxy_http_version    1.1;
      proxy_set_header      Upgrade "websocket";
      proxy_set_header      Connection "Upgrade";
      proxy_read_timeout    86400;
    }
    location ~ /jupyterlab/lsp/ {
      proxy_pass            http://localhost:8888;
      proxy_set_header      X-Real-IP $remote_addr;
      proxy_set_header      Host $host;
      proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
      # WebSocket support
      proxy_http_version    1.1;
      proxy_set_header      Upgrade "websocket";
      proxy_set_header      Connection "Upgrade";
      proxy_read_timeout    86400;
    }
    
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    # Visual Studio code-server
    # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@    
    # https://github.com/coder/code-server/blob/main/docs/guide.md#using-lets-encrypt-with-nginx
    location /vscode/ {
      proxy_pass http://localhost:8080;
      proxy_set_header Host $host;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection upgrade;
      proxy_set_header Accept-Encoding gzip;
    }   
  }
}

Configuration files for supervisor

Supervisor is allows its users to monitor and control a number of processes on UNIX-like operating systems. We will use it to run:

  • supervisor web interface to monitor the various processes listed below.
  • RStudio server.
  • jupyterlab.
  • code-server.
  • nginx server as a reverse proxy for all of the above processes.

Inside /dockerDS/config/supervisor/ directory add the following files:

Create /dockerDS/config/supervisor/supervisord.conf with the following content:

; supervisor config file

[unix_http_server]
file=/var/run/supervisor.sock   ; (the path to the socket file)
chmod=0700                      ; socket file mode (default 0700)

[supervisord]
user=root
nodaemon=true
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid            ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor             ; ('AUTO' child log dir, default $TEMP)

[inet_http_server]
port=*:9001

; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]; http://supervisord.org/configuration.html#supervisorctl-section-settings
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL  for a unix socket
;serverurl=http://localhost:9001

; The [include] section can just contain the "files" setting.  This
; setting can list multiple files (separated by whitespace or
; newlines).  It can also contain wildcards.  The filenames are
; interpreted as relative to this file.  Included files *cannot*
; include files themselves.

;[eventlistener:process-monitor]
;command=bash -c "printf 'READY\n' && while read line; do kill -SIGQUIT $PPID; done < /dev/stdin"
;events=PROCESS_STATE_STOPPED,PROCESS_STATE_EXITED,PROCESS_STATE_FATAL
;stdout_logfile=/dev/stdout
;stdout_logfile_maxbytes=0
;stdout_logfile_backups=0
;stderr_logfile=/dev/stderr
;stderr_logfile_maxbytes=0
;stderr_logfile_backups=0

; beware possible race condition
; if one of these services exit before the process-monitor is up

[include]
files = /etc/supervisor/conf.d/*.conf

Create /dockerDS/config/supervisor/nginxgo.conf with the following content:

; Config for nginx

[program:nginxgo]
;user=root
command=/usr/sbin/nginx -g 'daemon off;'
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autostart=true
autorestart=false
exitcodes=0
priority=100

Create /dockerDS/config/supervisor/rserver.conf with the following content:

; Config for RStudio Server

[program:rserver]
;user=rstudio         ; https://github.com/rstudio/rstudio/issues/1663#issuecomment-401476714
environment=RSTUDIO_CONFIG_HOME=/media/container_shared/.rstudio
command=/usr/lib/rstudio-server/bin/rserver --server-daemonize=0
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
startsecs=0
autorestart=false
exitcodes=0

According to the settings file locations documentation and the documentation on session settings we need to make sure that RStudio configuration location is in the shared folder. We can do this by setting an environmental variable RSTUDIO_CONFIG_HOME to /media/container_shared/.rstudio.

Create /dockerDS/config/supervisor/jupyterlab.conf with the following content:

; Config for Jupyter Lab

[program:jupyter-lab]
user=root
command=jupyter lab --allow-root --config=/root/.jupyter/jupyter_lab_config.py
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=false

Create /dockerDS/config/supervisor/codeserver.conf with the following content:

; Config for VS Code Server

[program:code-server] 
;user=rstudio
command=/usr/bin/code-server --config /root/.config/code-server/config.yaml /media/container_shared/
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
startsecs=0
autorestart=false
exitcodes=0

The static webpage

To make it easier to quickly open different processes, we can create a handy static .html webpage, which will be served by our nginx server and link to our software.

Create /dockerDS/config/www/index.html with the following content:

<!DOCTYPE html>
<html>
<head>
<style>
.button {
  display: inline-block;
  border-radius: 4px;
  background-color: #DBDBDB;
  border: none;
  color: #FFFFFF;
  text-align: center;
  font-size: 28px;
  padding: 20px;
  width: 200px;
  transition: all 0.5s;
  cursor: pointer;
  margin: 5px;
}

.button:active {
  transform: scale(.8);
}

.button span {
  cursor: pointer;
  display: inline-block;
  position: relative;
  transition: 0.5s;
}

.button span:after {
  content: '\00bb';
  position: absolute;
  opacity: 0;
  top: 0;
  right: -20px;
  transition: 0.5s;
}

.button:hover span {
  padding-right: 25px;
}

.button:hover span:after {
  opacity: 1;
  right: 0;
}

td {
  border: 1px solid black;
  width: 100px;
  height: 80px;
  overflow: hidden;
  text-align: center; 
  vertical-align: middle;  
}

img {
  height: 80px;
}

</style>
</head>
<body>

<table>
<tbody>
<tr>
<td colspan="3" style="width:100%">
    <a href="http://localhost/supervisor" target="_blank">
    <button class="button" style="vertical-align:middle; width:90%">
    <span style="color: #DE252A; font-weight: bold;"> <!-- supervisor -->
    Supervisor
    </span>
    </button>
    </a>
</td>
</tr>
<tr>
<td>
    <a href="http://localhost/jupyterlab" target="_blank">      
    <button class="button" style="vertical-align:middle">
    <span> <!-- jupyter -->
    <img src="data:image/png;base64,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" />
    </span>
    </button>
    </a>
</td>
<td>
    <a href="http://localhost/rstudio" target="_blank">
    <button class="button" style="vertical-align:middle">
    <span> <!-- rstudio -->
    <img style="display:block; object-fit: contain;" width="100%" height="100%" src="data:image/png;base64,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" />
    </span>
    </button>
    </a>
</td>
<td>
    <a href="http://localhost/vscode" target="_blank">      
    <button class="button" style="vertical-align:middle">
    <span> <!-- vscode -->
    <img src="data:image/png;base64,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" />
    </span>
    </button>
    </a>
</td>
</tr>
</tbody>
</table>

</body>
</html>

Then, once you have the container up and running, connecting to http://localhost:80 will load the following .html page with the following buttons:

A screenshot of the static webpage. Each button opens a separate service running inside the container.

The dockerfile

Finally, inside the root folder (i.e. in dockerDS) you will need to create the following dockerfile:

Create /dockerDS/datascience.dockerfile with the following content:

FROM ubuntu:22.04 AS build

# https://stackoverflow.com/a/65054865 
ENV DEBIAN_FRONTEND noninteractive

# ARG declarations - only available during building
## https://quarto.org/docs/download/
ARG QUARTO_VERSION=1.3.450
## https://cran.r-project.org/bin/windows/base/
ARG R_VERSION=4.3.2
## https://packagemanager.posit.co/client/#/repos/cran/setup?snapshot=latest
ARG CRAN=${1:-${CRAN:-"https://packagemanager.posit.co/cran/__linux__/jammy/2023-12-08"}}
## https://www.python.org/downloads/
ARG PYTHON_VERSION=3.11.7
## https://posit.co/download/rstudio-desktop/
ARG RSTUDIO_VERSION=2023.09.1-494
## https://github.com/rstudio/tinytex-releases (environmental variables are used in the "install-bin-unix.sh" script)
ARG TINYTEX_INSTALLER=TinyTeX
ARG TINYTEX_VERSION=2023.12
## https://github.com/stan-dev/cmdstan/releases/
ARG STAN_VERSION=2.33.1
## https://deb.nodesource.com/
ARG NODE_MAJOR=20
## https://github.com/coder/code-server/releases
ARG VSCODE_VERSION=4.19.1
## Used to setup a user for RStudio server
ARG DEFAULT_USER=${2:-${DEFAULT_USER:-"rstudio"}}

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Ubuntu apps and packages
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

RUN apt-get update --fix-missing  \
    && apt-get upgrade -yq \
    && apt-get install -yq --no-install-recommends \
    sudo \
    curl ca-certificates gnupg \
    locales git zip unzip wget make perl \
    supervisor nginx

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Configure default locale, see also: https://stackoverflow.com/a/38553499
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

#RUN apt-get update --fix-missing && apt-get install -y locales lsb-release
RUN localedef -i en_US -f UTF-8 en_US.UTF-8
ENV LANG=${LANG:-"en_US.UTF-8"}
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
RUN /usr/sbin/locale-gen --lang "${LANG}"
RUN /usr/sbin/update-locale --reset LANG="${LANG}"

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Configure non-root user for RStudio server (required)
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

## Note: user must be created BEFORE any software is installed, otherwise it might not be available for that user
RUN useradd -s /bin/bash -m "$DEFAULT_USER" \
    && echo "${DEFAULT_USER}:${DEFAULT_USER}" | chpasswd \
    && usermod -a -G staff "${DEFAULT_USER}" \
    && mkdir -p "/home/${DEFAULT_USER}/.config/rstudio/" \
    && chown -R "${DEFAULT_USER}:${DEFAULT_USER}" "/home/${DEFAULT_USER}"

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Install NodeJS (https://deb.nodesource.com/)
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
    && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list \
    && apt-get update && apt-get install nodejs -y \
    && npm install -g npm@latest

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Install Quarto ( https://docs.posit.co/resources/install-quarto/ )
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

RUN curl -o quarto.tar.gz -L https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-amd64.tar.gz \
    && mkdir -p /opt/quarto/${QUARTO_VERSION} \
    && tar -zxvf quarto.tar.gz -C "/opt/quarto/${QUARTO_VERSION}" --strip-components=1 \
    && rm -f quarto.tar.gz \
    && ln -s /opt/quarto/${QUARTO_VERSION}/bin/quarto /usr/local/bin/quarto

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Install R ( https://docs.posit.co/resources/install-r/ )
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

# Required libraries for R:
RUN apt-get update --fix-missing && apt-get install -yq gdebi-core
# Download and install R:
RUN curl -O https://cdn.rstudio.com/r/ubuntu-2204/pkgs/r-${R_VERSION}_1_amd64.deb \
    && apt-get install -yq --no-install-recommends ./r-${R_VERSION}_1_amd64.deb \
    && rm -f ./r-${R_VERSION}_1_amd64.deb \
    && ln -s /opt/R/${R_VERSION}/bin/R /usr/local/bin/R \
    && ln -s /opt/R/${R_VERSION}/bin/Rscript /usr/local/bin/Rscript

# Add a default CRAN mirror
RUN echo "options(repos = c(CRAN = '${CRAN}'), download.file.method = 'libcurl')" >> "opt/R/${R_VERSION}/lib/R/etc/Rprofile.site"
# Set HTTPUserAgent for Posit Pacakge Manager:
RUN echo "options(HTTPUserAgent = sprintf('R/%s R (%s)', getRversion(), paste(getRversion(), R.version['platform'], R.version['arch'], R.version['os'])))" >> "opt/R/${R_VERSION}/lib/R/etc/Rprofile.site"
# https://docs.rstudio.com/rspm/admin/serving-binaries/#binaries-r-configuration-linux

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Install Python ( https://docs.posit.co/resources/install-python/ )
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

RUN curl -O https://cdn.rstudio.com/python/ubuntu-2204/pkgs/python-${PYTHON_VERSION}_1_amd64.deb \
    && apt-get install -yq --no-install-recommends ./python-${PYTHON_VERSION}_1_amd64.deb \
    && rm -rf python-${PYTHON_VERSION}_1_amd64.deb \
    && /opt/python/${PYTHON_VERSION}/bin/python3 -m pip install --upgrade pip \
    && /opt/python/${PYTHON_VERSION}/bin/python3 -m pip install --upgrade setuptools

#RUN ln -s /opt/python/${PYTHON_VERSION}/bin/python3 /usr/bin/python
RUN echo "PATH=/opt/python/${PYTHON_VERSION}/bin:$PATH" >> ~/.bashrc
#RUN echo "export PATH=/opt/python/${PYTHON_VERSION}/bin:$PATH" >> ~/.bashrc

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Install RStudio ( https://posit.co/download/rstudio-server/ )
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

# Required libraries for RStudio:
RUN apt-get update --fix-missing \
    && apt-get install -yq psmisc libssl-dev libclang-dev libclang-dev libpq5
# Download and install RStudio:
RUN curl -o rstudio-server.deb "https://download2.rstudio.org/server/jammy/amd64/rstudio-server-${RSTUDIO_VERSION}-amd64.deb" \
    && dpkg -i rstudio-server.deb  \
    && rm -rf rstudio-server.deb \
    && ln -fs /usr/lib/rstudio-server/bin/rstudio-server /usr/local/bin \
    && ln -fs /usr/lib/rstudio-server/bin/rserver /usr/local/bin

# https://github.com/rocker-org/rocker-versioned2/issues/137
RUN rm -f /var/lib/rstudio-server/secure-cookie-key
# https://docs.posit.co/ide/server-pro/load_balancing/configuration.html#lock-configuration
RUN echo "lock-type=advisory" >/etc/rstudio/file-locks

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Configuration for RStudio server
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

COPY /config/rstudio/rstudio-prefs.json /etc/rstudio/rstudio-prefs.json
COPY /config/rstudio/rsession.conf /etc/rstudio/rsession.conf
COPY /config/rstudio/rserver.conf /etc/rstudio/rserver.conf
COPY /config/rstudio/logging.conf /etc/rstudio/logging.conf

# https://docs.posit.co/ide/server-pro/rstudio_pro_sessions/customizing_session_settings.html#keybindings
COPY /config/rstudio/addins.json /etc/rstudio/keybindings/addins.json
COPY /config/rstudio/editor_bindings.json /etc/rstudio/keybindings/editor_bindings.json
COPY /config/rstudio/rstudio_bindings.json /etc/rstudio/keybindings/rstudio_bindings.json

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Install TinyTeX (https://yihui.org/tinytex/)
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

# Note: must be AFTER non-root user is created, otherwise quarto does not detect tinytex
RUN curl -sL "https://yihui.org/tinytex/install-bin-unix.sh" | sh \
    && /root/.TinyTeX/bin/*/tlmgr path remove \
    && mv /root/.TinyTeX/ /opt/TinyTeX \
    && /opt/TinyTeX/bin/*/tlmgr option sys_bin /usr/local/bin \
    && /opt/TinyTeX/bin/*/tlmgr path add \
    && tlmgr update --self --all \
    && fmtutil-sys --all

# tlmgr info schemes
# tlmgr info collections

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Install Python libraries and JupyterLab
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

# Required libraries for some Python libraries (e.g. manim):
RUN apt-get update --fix-missing \
    && apt-get install -yq build-essential libcairo2-dev libpango1.0-dev ffmpeg
## Note: the following is only needed, if an incomplete bundle of packages is installed
# https://docs.manim.community/en/stable/installation/linux.html#optional-dependencies
RUN tlmgr install collection-basic amsmath babel-english cbfonts-fd cm-super ctex doublestroke \
                  dvisvgm everysel fontspec frcursive fundus-calligra gnu-freefont jknapltx \
                  latex-bin mathastext microtype ms physics preview ragged2e relsize rsfs \
                  setspace standalone tipa wasy wasysym xcolor xetex xkeyval

COPY /config/python/requirements.txt /tmp/requirements.txt

RUN /opt/python/${PYTHON_VERSION}/bin/python3 -m pip install --upgrade pip \
    && /opt/python/${PYTHON_VERSION}/bin/python3 -m pip install -r /tmp/requirements.txt
# Disable jupyter announcement notification: https://stackoverflow.com/a/75552789
RUN /opt/python/${PYTHON_VERSION}/bin/jupyter labextension disable "@jupyterlab/apputils-extension:announcements"

## Install lsp language server for bash and markdown:
RUN npm install -g --save-dev bash-language-server unified-language-server
RUN npm cache clean --force

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Install R libraries
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

# Required libraries for some R libraries (see the commented-out `pak::...` code in 'install_libraries.R'):
# Note: make sure to exclude 'python3', `git`, `make`, since we already have them installed
RUN apt-get update --fix-missing \
    && apt-get install -yq libcurl4-openssl-dev libssl-dev libgit2-dev zlib1g-dev pandoc \
    libfreetype6-dev libjpeg-dev libpng-dev libtiff-dev libicu-dev \
    libfontconfig1-dev libfribidi-dev libharfbuzz-dev libxml2-dev imagemagick \
    libmagick++-dev gsfonts cmake libgdal-dev gdal-bin \
    libgeos-dev libproj-dev libsqlite3-dev libudunits2-dev libzmq3-dev pandoc-citeproc

COPY /config/rstudio/environment.txt /tmp/environment.txt
COPY /config/rstudio/install_libraries.R /tmp/install_libraries.R

RUN Rscript /tmp/install_libraries.R /tmp/
RUN ln -s /opt/python/${PYTHON_VERSION}/bin/jupyter /usr/bin/jupyter
RUN Rscript -e "IRkernel::installspec(user=FALSE)"
# Make sure that Python can be found:
RUN echo "Sys.setenv(RETICULATE_PYTHON = '/opt/python/${PYTHON_VERSION}/bin/python')" >> "opt/R/${R_VERSION}/lib/R/etc/Rprofile.site"
RUN echo "invisible(reticulate::py_available(initialize = TRUE))" >> "opt/R/${R_VERSION}/lib/R/etc/Rprofile.site"

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Configure CmdStan
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

# https://github.com/stan-dev/cmdstan
# https://mc-stan.org/cmdstanr/reference/install_cmdstan.html (C++ toolchain with "apt-get install make")
# https://mc-stan.org/cmdstanpy/installation.html#pypi-install-package-cmdstanpy
#RUN /opt/python/${PYTHON_VERSION}/bin/python3 -c "import cmdstanpy as stan; import multiprocessing; stan.install_cmdstan(version = '${STAN_VERSION}', dir = '/opt/cmdstan', cores = multiprocessing.cpu_count())"
#RUN Rscript -e "cmdstanr::install_cmdstan(version = '${STAN_VERSION}', dir = file.path('/opt/cmdstan'), cores = parallel::detectCores())"
#RUN echo "Sys.setenv(CMDSTAN = '/opt/cmdstan/cmdstan-${STAN_VERSION}')" >> "opt/R/${R_VERSION}/lib/R/etc/Rprofile.site"
#RUN echo "CMDSTAN='/opt/cmdstan/cmdstan-${STAN_VERSION}'" >> /etc/environment
# IMPORTANT: env variable `CMDSTAN` is set in the supervisor config section! using 'ENV CMDSTAN=...' doesn't work for both rstudio and root users.

## Alternative: install cmdstan in both the `root` and `rstudio` users:
RUN /opt/python/${PYTHON_VERSION}/bin/python3 -c "import cmdstanpy as stan; import multiprocessing; stan.install_cmdstan(version = '${STAN_VERSION}', dir = '/root/.cmdstan', cores = multiprocessing.cpu_count())"
RUN /opt/python/${PYTHON_VERSION}/bin/python3 -c "import cmdstanpy as stan; import multiprocessing; stan.install_cmdstan(version = '${STAN_VERSION}', dir = '/home/rstudio/.cmdstan', cores = multiprocessing.cpu_count())"

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Configure JupyterLab
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

## https://github.com/jupyter-lsp/jupyterlab-lsp#installation

COPY /config/python/jupyter_lab_config.py /root/.jupyter/jupyter_lab_config.py
COPY /config/python/jupyter_server_config.py /root/.jupyter/jupyter_server_config.py
COPY /config/python/ipython_config.py /opt/python/${PYTHON_VERSION}/etc/ipython/ipython_config.py

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Install VSCode Server (https://github.com/coder/code-server)
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

## https://github.com/linuxserver/docker-code-server/blob/master/Dockerfile
## https://github.com/coder/code-server
## https://coder.com/docs/code-server/latest/FAQ#how-do-i-install-an-extension

## Get a list of commands that install code-server:
## curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run --version=${VSCODE_VERSION} --prefix=/usr/local
## Then run those commands:
RUN mkdir -p ~/.cache/code-server \
    && curl -#fL -o ~/.cache/code-server/code-server.deb.incomplete -C - https://github.com/coder/code-server/releases/download/v${VSCODE_VERSION}/code-server_${VSCODE_VERSION}_amd64.deb \
    && mv ~/.cache/code-server/code-server.deb.incomplete ~/.cache/code-server/code-server.deb \
    && dpkg -i ~/.cache/code-server/code-server.deb \
    && rm -rf ~/.cache/code-server
# which code-server

# Important: in order to connect without a proxy (like nginx), IP must be set to 0.0.0.0!
# https://github.com/coder/code-server/issues/1800#issuecomment-1341720112

## Install extensions: (only works if the 'extensions-dir' flag is set to /root/.local/share/code-server/extensions/)
## https://open-vsx.org
# https://open-vsx.org/extension/yzhang/markdown-all-in-one
RUN code-server --install-extension yzhang.markdown-all-in-one
# https://open-vsx.org/extension/ms-python/python
RUN code-server --install-extension ms-python.python
# https://open-vsx.org/extension/ms-pyright/pyright
RUN code-server --install-extension ms-pyright.pyright
# https://open-vsx.org/extension/REditorSupport/r
RUN code-server --install-extension REditorSupport.r
# https://open-vsx.org/extension/RDebugger/r-debugger
RUN code-server --install-extension RDebugger.r-debugger
# https://open-vsx.org/extension/quarto/quarto
RUN code-server --install-extension quarto.quarto
# https://open-vsx.org/extension/ms-toolsai/jupyter
RUN code-server --install-extension ms-toolsai.jupyter

COPY /config/code-server/config.yaml /root/.config/code-server/config.yaml

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Shared dir
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

RUN mkdir /media/container_shared/ \
    && chmod 777 /media/container_shared/

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Configure nginx
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

COPY /config/nginx/nginx.conf /etc/nginx/nginx.conf
COPY /config/www/index.html /www/static/index.html

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Cleanup
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

RUN apt-get install -yqf --no-install-recommends \
    && apt-get autoremove \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* \
    && rm -rf /var/tmp/* \
    && rm -rf /config/* \
    && rm -rf /tmp/* \
    && rm -rf /opt/conda/pkgs/* \
    && rm -rf /root/.conda/pkgs/* \
    && rm -rf /root/.cache/pip/* \
    && strip /opt/R/${R_VERSION}/lib/R/library/*/libs/*.so

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Supervisor
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
## Override the config file: /etc/supervisor/supervisord.conf
COPY /config/supervisor/supervisord.conf /etc/supervisor/supervisord.conf
# Copy RStudio Server config to supervisor:
COPY /config/supervisor/rserver.conf /etc/supervisor/conf.d/
# Copy JupyterLab config to supervisor
COPY /config/supervisor/jupyterlab.conf /etc/supervisor/conf.d/
# Copy VSCode Server config to supervisor
COPY /config/supervisor/codeserver.conf /etc/supervisor/conf.d/
# Copy nginx config to supervisor: https://stackoverflow.com/a/28099946
COPY /config/supervisor/nginxgo.conf /etc/supervisor/conf.d/

# Set CMDSTAN environmental variable:
# Note" .conf files must have some initial "environment=CMDSTAN=..." value
#RUN sed -i "s/environment=CMDSTAN=.*,/environment=CMDSTAN=\/opt\/cmdstan\/cmdstan-${STAN_VERSION},/g" /etc/supervisor/conf.d/rserver.conf
#RUN sed -i "s/environment=CMDSTAN=.*/environment=CMDSTAN=\/opt\/cmdstan\/cmdstan-${STAN_VERSION}/g" /etc/supervisor/conf.d/jupyterlab.conf
#RUN sed -i "s/environment=CMDSTAN=.*/environment=CMDSTAN=\/opt\/cmdstan\/cmdstan-${STAN_VERSION}/g" /etc/supervisor/conf.d/codeserver.conf

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Multi-stage building in order to reduce the amount of layers
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

# https://stackoverflow.com/a/56118557
FROM scratch
# https://specs.opencontainers.org/image-spec/annotations/?v=v1.0.1
LABEL org.opencontainers.image.title="Docker image for statistics, econometrics and data science" \
      org.opencontainers.image.description="Not for public registries" \
      org.opencontainers.image.authors="andrius.buteikis@mif.vu.lt" \
      org.opencontainers.image.url="" \
      org.opencontainers.image.version="1.2.5"

# Copy from existing docker image to reduce layers
COPY --from=build / /

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Finalize
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

#CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
# https://github.com/jupyter-lsp/jupyterlab-lsp#installation
# https://unix.stackexchange.com/a/207296
# https://unix.stackexchange.com/a/187148
CMD ["/bin/bash", "-c", "ln -sf / /media/container_shared/.lsp_symlink ; /usr/bin/supervisord -c /etc/supervisor/supervisord.conf"]

The multiple sets of tabs below contain a number of explanations for the commands in the datascience.dockerfile, organized in the order that they appear in the dockerfile.

  • We will be using Ubuntu 22.04 as our base image.
  • We set DEBIAN_FRONTEND to noninteractive to force installations use default answers to any of their interactive questions.
  • We then define a number of variables that contain the application versions, CRAN mirror and default user that will be used when building the docker file.
  • Finally, we install a number of applications that will let us configurte, download and install our software:
    • sudo - nedded to run some applications with super user privileges.
    • curl and wget - to download our software from the web.
    • ca-certificates and gnupg - needed to download NodeJS.
    • zip, unzip - to archive and extract our software.
    • make - utility to compile applications from source (needed for Stan)
    • perl - the perl programming language, used by some libraries in R.
    • locales - language and locale support, since R will need this information when installing packages (see here).
    • supervisor - allows us to launch and monitor multiple processes. This will let us launch RStudio, JupyterLab, code-server when starting the container.
    • nginx - a web server that can also be used as a reverse proxy. We will sue it to consolidate the number of urlks of our web applications into a single home page.
  • We then set a number of environmental variables for the locale.
  • Finally, we configure a default user, that will be used to login into RStudio with the following credentials:
    • username: rstudio
    • password: rstudio
    • We create this user at the beginning so that any software installed to /opt and /usr/local is readily available.

We install NodeJS following the official installation guide and upgrade npm to the latest version.

We install Quarto following the official installation guide.

We install R following the documentation at Posit. We also set the default CRAN mirror to a snapshot of a specific date that we’ve defined in the CRAN variable, as well as the HTTP user agent according to the documentation on serving binary packages.

We install Python following the documentation at Posit. We then upgrade pip and setuptools to the newest versions, as they are needed to download libraries and older versions may have expired url’s. We also make sure that this version of Python is available in our linux terminal by adding it to our .bashrc bash shell script.

We install RStudio Server. An example can be found at rocker-project.org project’s Github page, which has more customization options.

We COPY our configuration files from our machine to our docker image.

We install TinyTeX following an example on rstudio/r-base image on docker.

We install a few Ubuntu libraries, which may be needed for manim, including the optional LaTeX libraries.

We then COPY the /dockerDS/config/python/requirements.txt file, install the libraries and disable jupyter announcement notification on startup. Finally, we install the lsp language servers for bash and markdown, in case we need them.

If needed, the newest library versions can be installed with:

python -m pip install --upgrade pip
python -m pip install -U virtualenv numpy scipy numexpr matplotlib pandas 'modin[all]' statsmodels 'datatable>1.0.0' pymc 'cmdstanpy[all]' 'arviz[all]' bambi jupyterlab jupyterlab-lsp jupyter-cache scikit-learn tensorflow keras pyarrow polars duckdb tzdata datar patsy plotnine seaborn siuba streamlit great-tables skimpy beautifulsoup4 manim lckr-jupyterlab-variableinspector
python -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
python -m pip freeze > requirements.txt

Note:

  1. python-lsp-server[all] installs pycodestyle, which doesn’t work well with jupyter inside docker as it needs, so, for now, we only use it for R.
  2. The latest datatable dev version can be found here.

We firstly install any Ubuntu libraries, that are required by some packages. You can check the required libraries via the pak library inside the container and get the list of apt-get install ... libraries by running the following code in R:

pak::pkg_sysreqs(lib_list, upgrade = FALSE)$install_scripts

where lib_list is the vector, containing the names of all the libraries inside the /dockerDS/config/rstudio/environment.txt file. If you get an error of some conflicts - chances are that a base/recommended library is in the list!

Then we create a symbolic link to make jupyterlab easier to start by linking it to /usr/bin/jupyter. After that we add the R kernel to jupyterlab and add our Python installation to R’s path so that the correct version of Python can be called from RStudio, if need be.

There are two ways to install [Stan]:

There is a very important difference between the two different cmdstan versions, with regards to the environmental variable CMDSTAN:

In R:

If the environment variable “CMDSTAN” exists at load time then its value will be automatically set as the default path to CmdStan for the R session. If the environment variable “CMDSTAN” is set, but a valid CmdStan is not found in the supplied path, the path is treated as a top folder that contains CmdStan installations. In that case, the CmdStan installation with the largest version number will be set as the path to CmdStan for the R session.

In Python:

CmdStanPy uses the environment variable CMDSTAN to register the CmdStan installation location.

For this reason, we would need to set CMDSTAN to a specific version, otherwise the cmdstanpy will not work correctly. Since we want to access Stan from the rstudio user while inRStudio and the root user while in JupyterLab - we install Stan for both root and rstudio. While this takes up an additional 1 GB of data, but it is a more stable solution, since, in some cases, the environmental variable CMDSTAN wasn’t available in RStudio’s markdown, or quarto documents, as well as chunks with Python code.

You can verify whether Stan works as expected via the terminal:

Rscript -e "cmdstanr::cmdstan_path()"
python -c "import cmdstanpy as stan; print(stan.cmdstan_path())"
[1] "/home/rstudio/.cmdstan/cmdstan-2.33.1"
/home/rstudio/.cmdstan/cmdstan-2.33.1

Or by running a specific example directly in R:

library(cmdstanr)
#
a <- cmdstan_model(file.path(cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan'))
b <- a$sample(data = list(N = 10, y = c(0, 1, 0, 0, 0, 0, 0, 0, 0, 1)),
              seed = 123, chains = 4, parallel_chains = 4, refresh = 500, 
              iter_warmup = 1000, iter_sampling = 1000, show_messages = FALSE)
b$summary()
This is cmdstanr version 0.7.1
- CmdStanR documentation and vignettes: mc-stan.org/cmdstanr
- CmdStan path: /home/rstudio/.cmdstan/cmdstan-2.33.1
- CmdStan version: 2.33.1

A newer version of CmdStan is available. See ?install_cmdstan() to install it.
To disable this check set option or environment variable CMDSTANR_NO_VER_CHECK=TRUE.
# A tibble: 2 × 10
  variable   mean median    sd   mad      q5    q95  rhat ess_bulk ess_tail
  <chr>     <dbl>  <dbl> <dbl> <dbl>   <dbl>  <dbl> <dbl>    <dbl>    <dbl>
1 lp__     -7.26  -6.99  0.704 0.330 -8.76   -6.75   1.00    1952.    2046.
2 theta     0.250  0.234 0.119 0.121  0.0821  0.464  1.00    1552.    1621.

and Python:

import os
import pandas
pandas.set_option('display.max_columns', None)
pandas.set_option('display.width', 200)
import cmdstanpy as stan
#
a = stan.CmdStanModel(stan_file = os.path.join(stan.cmdstan_path(), 'examples', 'bernoulli', 'bernoulli.stan'))
b = a.sample(data = {'N': 10, 'y': [0, 1, 0, 0, 0, 0, 0, 0, 0, 1]}, \
             seed = 123, chains = 4, parallel_chains = 4, refresh = 500, \
             iter_warmup = 1000, iter_sampling = 1000, show_progress = False)
b.summary()
21:43:21 - cmdstanpy - INFO - CmdStan start processing
21:43:21 - cmdstanpy - INFO - Chain [1] start processing
21:43:21 - cmdstanpy - INFO - Chain [2] start processing
21:43:21 - cmdstanpy - INFO - Chain [3] start processing
21:43:21 - cmdstanpy - INFO - Chain [4] start processing
21:43:21 - cmdstanpy - INFO - Chain [2] done processing
21:43:21 - cmdstanpy - INFO - Chain [4] done processing
21:43:21 - cmdstanpy - INFO - Chain [1] done processing
21:43:21 - cmdstanpy - INFO - Chain [3] done processing
          Mean      MCSE    StdDev        5%       50%      95%    N_Eff  N_Eff/s    R_hat
lp__  -7.26358  0.017219  0.704111 -8.764440 -6.988110 -6.75037  1672.04  23549.8  1.00184
theta  0.24995  0.002967  0.119325  0.082037  0.233825  0.46429  1617.52  22781.9  1.00221

We COPY our configuration files from our machine to our docker image.

Important

Depending on the version of JupyterLab, R and Python, sometimes code completion doesn’t fully work. While in some cases, this is due to a bug in one of the libraries (which will usually be fixed in a future version), some of the setting changes can be toggled in order to, hopefully, fix problems with code completion. If you do not get code autocompletion suggestions when pressing Tab on your code - you can try to modify the following settings:

  • See the sections below to fully build your docker image.
  • Launch the docker container and open JupyterLab.
  • On the top menu, go to Settings -> Editor Settings.
  • In the Settings menu you should see two Code completion tabs, these tabs are for the @jupyter-lsp/jupyterlab-lsp:completion and @jupyterlab/completer-extension:manager plugins in JupyterLab.
  • In one of the Code Completion tabs change the following settings:
    • Continuous hinting - change this to be on.
    • Wait for kernel if busy - change this to be off.
    • Prioritize completion from kernel - change this to be on.
    • Case-sensitive filtering - change this to be off.
    • Include perfect matches - change this to be on.
    • Pre-filter matches - change this to be off.
  • In the other Code Completion tab change the following settings:
    • Show the documentation panel - change this to be on.
    • Enable autocompletion - change this to be on.

Experimenting with turning on/off some of the above settings should return some of the autocompletion functionality.

We get the commands via a dry run:

curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run --prefix=/usr/local

We then install extensions from open-vsx.org. Note that we install the pyright extension, since by default the Python extension does not contain pylance, as it is licensed for Microsoft products only. Finally, we COPY our configuration to the docker image.

We create a container_shared folder inside /media, that we will use a shared volume between our machine and the container. We also make the directory have 777 permission, which grants read, write, and execute permission to every user in our container, ensuring that we will be able to read and modify files/folder inside our shared directory.

We COPY the nginx configuration and our static .html webpage to the docker image.

We remove any temporary files to reduce the size of our docker image.

We COPY the configurations of each service, which will be controlled by supervisor.

To further reduce the size of our image via multi-stage building, which reduces the number of our docker layers. This reduces the final docker image by around 2 to 3 GB. We also add a numebr of labels following the OpenContainers Annotations Specification.

As a final step, we set supervisor to launch whenever we start our docker container. Note that we want to enable R documentation and code completion in JupyterLab, so we follow the documentation on github and create a symbolic link from our shared directory (i.e. the Jupyter root directory), which points to our system root /. We need to do this each time we start our container, in case we want to mount a different directory.

Building our docker image

We can now build our image by running the following command in our terminal:

run in your machines's terminal
docker build -f ./datascience.dockerfile -t datascience --pull=false .

It should take between 1 to 2 hours to build the docker image.

In multi-stage building, we can build up to a specific stage. In our case, we may want to stop after the build stage (the code between FROM ubuntu:22.04 AS build and COPY --from=build / /:

run in your machines's terminal
docker build --target build -f ./datascience.dockerfile -t datascience --pull=false .

We can inspect the number of layers in our docker build:

run in your machines's terminal
docker inspect --format '{{range .RootFS.Layers}}{{println .}}{{end}}' datascience:latest

Note that we wanted to reduce the number of layers to manage the build cache.

The built image history can be viewed with the followin command:

run in your machines's terminal
docker image history datascience:latest

We can view our created images as follows:

run in your machines's terminal
docker image ls

And finally, we can view the disk usage (built images, active containers and build cache):

run in your machines's terminal
docker system df

Running the prepared image

Firstly, make sure that you change the directory (via cd) inside the terminal to where you want to access your projects. Then, we can create and run a new (temporary) container from our build image via one of the following commands:

  • If we are using a windows powershell terminal:
run in your machines's terminal
docker run --rm --name ds-core -v ${PWD}/projects:/media/container_shared/ -p 80:80 datascience
  • If we are using a windows cmd terminal:
run in your machines's terminal
docker run --rm --name ds-core -v "%cd%":/media/container_shared/ -p 80:80 datascience

Note the following arguments:

  • --rm - automatically remove the container when it exits.
  • --name ds-core - we set our container name
  • -v ${PWD}/projects:/media/container_shared/ means that we bind mount a volume - we use our current working directory from the terminal (${PWD}, or "%cd%") and make it available inside the docker container’s /media/container_shared/ directory.
  • -p 80:80 - we bind a container’s port to the same host’s port.

If we want to limit the amount of hardware resources available to docker, we can modify our command with the following arguments (see here for more examples):

run in your machines's terminal
docker run --rm --cpus="0.5" --memory="2g" --memory-swap="20g" --name ds-core -v "%cd%":/media/container_shared/ -p 80:80 datascience

where:

  • --cpus - specify how much of the available CPU resources a container can use. If you have 1 CPU, setting --cpus="0.5" guarantees the container uses at most 50% of the CPU.
  • --memory - the maximum amount of memory the container can use, the minimum allowed value is "6m" (6 megabytes).
  • --memory-swap - the amount of memory this container is allowed to swap to disk. It only works if --memory is also set. Using swap allows the container to write excess memory requirements to disk when the container has exhausted all the RAM that’s available to it. There is a performance penalty for applications that swap memory to disk often. However, it is useful if your machine lacks the required amount of RAM. Note that:
    • --memory-swap represents the total amount of memory and swap that can be used, and --memory controls the amount used by non-swap memory. In other words the difference between --memory-swap and --memory is the amount of swap that can be used.
    • Setting it to -1 allows the container to use unlimited swap, up to the amount available on the host system.
    • If it is set to 0, then the value is treated as unset.
    • If the amount is set to the same value as --memory, then the container doesn’t have access to swap.
    • If --memory-swap is unset and --memory is set, the container can use as much swap as the --memory setting.
    • You need to configure swap memory on your on Windows host machine.

Finally, if we want to explore our image via bash inside our terminal, then we can run the following command:

run in your machines's terminal
docker run --rm --name ds-core -v ${PWD}/projects:/media/container_shared/ -p 80:80 -it datascience bash

where -it instructs docker to allocate a pseudoterminal connected to the container’s stdin and creating an interactive bash shell in the container.

Create a file named start_container.bat. In the code below replace "%cd%" with the directory in our OS that you want to access from the container. For example, you might have a projects folder in the following directory C:\Users\Andrius\Desktop\projects. You would then replace "%cd%" with C:\Users\Andrius\Desktop\projects. If your directory path name contains spaces - you would need to surround that directory with quotes.

start_container.bat
@echo off

setlocal
call :setESC

cls

REM stop container if it is running
docker stop ds-core

REM start "" /b cmd /c "timeout /nobreak 5 >nul & start "" http://localhost:80"
ECHO.
ECHO %ESC%[93m+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %ESC%[0m
ECHO (1) Wait until you see %ESC%[96m "INFO success: ... entered RUNNING state ..."%ESC%[0m
ECHO (2) Open the following URL in your browser:%ESC%[92m http://localhost:80 %ESC%[0m
ECHO (3) If you want to%ESC%[91m stop/close%ESC%[0m this docker container then press %ESC%[91m CTRL+C %ESC%[0m
ECHO %ESC%[93m+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %ESC%[0m
ECHO.%ESC%[96m 

docker run --rm --name ds-core -v "%cd%":/media/container_shared/ -p 80:80 datascience

ECHO.%ESC%[0m

pause

REM https://gist.github.com/mlocati/fdabcaeb8071d5c75a2d51712db24011#file-win10colors-cmd
:setESC
for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
  set ESC=%%b
  exit /B 0
)
exit /B 0

Opening this file should launch a windows terminal window and start the docker container.

Monitoring active containers

In a separate terminal window, run the following commands to view how much of our machine’s resources are being used by any active containers:

  • Current resource use:
run in your machine's terminal
docker stats --no-stream
  • Continuous resource usage monitoring (press Ctrl+C to close):
run in your machine's terminal
docker stats

While inside our docker container (or by opening the Terminal tab in RStudio server, or JupyterLab), we can check the disk usage of each directory inside the container by running the following :

run in your docker container's terminal
du -h -d 1 / -t +100MB 2> >(grep -v '^du:') | sort -hr
22G /
11G /media
6.7G    /opt
3.6G    /usr
1.1G    /home

Note that the /media directory contains our shared directory with files from our machine, so we can ignore it. And focus on the remaining directories:

run in your docker container's terminal
du -h -d 1 /opt | sort -hr
6.7G    /opt
4.5G    /opt/python
1.1G    /opt/R
836M    /opt/TinyTeX
306M    /opt/quarto
run in your docker container's terminal
du -h -d 2 /usr -t +100MB | sort -hr
3.6G    /usr
2.6G    /usr/lib
1.1G    /usr/lib/x86_64-linux-gnu
529M    /usr/lib/rstudio-server
455M    /usr/bin
364M    /usr/lib/code-server
310M    /usr/lib/llvm-14
291M    /usr/include
226M    /usr/share
162M    /usr/include/boost
131M    /usr/lib/gcc
run in your docker container's terminal
du -h -d 1 /home/rstudio | sort -hr
1.1G    /home/rstudio/.cmdstan
1.1G    /home/rstudio
520K    /home/rstudio/.local
488K    /home/rstudio/.cache
12K /home/rstudio/R
12K /home/rstudio/.config

We see that most of the space is occupied by R, RStudio, Python, Quarto, TinyTex and Stan, while the Ubuntu OS-specific libraries take up 2 to 3 GB of data.

Backing up and restoring the created image and clearing the build cache

Firstly, back up the docker image as a .tar file by running the following command in the terminal and saving it to the active directory in the terminal:

run in your machine's terminal
docker save -o ./datascience.tar datascience

The file should be approximately 12 GB in size. If you have 7-zip installed, you can reduce this size to only around 3.5 GB by creating a .tgz archive via the following command:

run in your machine's terminal
C:\"Program Files"\7-Zip\7z.exe a datascience.tgz datascience.tar -sdel

Then, delete the image inside docker (not the archive that we created) with the following command:

run in your machine's (powershell) terminal
docker rmi $(docker images 'datascience' -a -q)

After removing the image, we can clear the build cache to free-up space, since we won’t need to re-build our image:

run in your machine's terminal
docker builder prune --force

The build cache is used to make re-building the image quicker. In our case, the build cache could be anywhere from 25 GB or more (especially if we ran into errors and had to re-build).

We can then further inspect the total size taken up by everything else (e.g. other images that we have):

run in your machine's terminal
docker system df

If this was the only image the we’ve built - we should see 0B in Images/Containers/Local Volumes/Build Cache categories.

Finally, after clearing up some space, we load up our image into docker:

run in your machine's terminal
docker load -i ./datascience.tgz

If you did not create the .tgz archive - replace datascience.tgz with datascience.tar. It should take around 15-30 minutes to load the archived image into docker. We will only have to do this once after building the image. Any future containers will be created from this loaded image.

Finally, we run:

run in your machine's terminal
docker system df

to make note of our total image sizes. You should keep the datascience.tgz (or datascience.tar) archive in case you accidentally remove the image from docker and don’t want to re-build it from scratch.

If you want to remove everything run the following commands in your terminal:

run in your machine's (powershell) terminal
docker stop $(docker ps -a -q)
docker system prune -a --volumes --force

The first command stops all docker containers, while the second removes all unused containers/volumes/networks/images. Since we stop all containers with the first command - the seconds command will remove everything.


  1. Files have extensions, like .yaml, .conf, .txt, .R, .py, .dockerfile, etc., while folders do not have extensions.↩︎

  2. Click on each tab to get the different configuration files as well as explanations for each configuration file.↩︎