Serve bettr
We are currently serving bettr via shiny-server within singularity. So this recipe aims to install singularity on a linux machine, get the bettr image, and set up a cron to retrieve metrics.
The host needs to face the internet. And a firewall.
We are aware rstudioconnect could simplify this, or just running bettr
locally.
Installs
singularity
We assume an apt
-apt distribution, i.e. debian or ubuntu.
sudo apt-get update
sudo apt-get update && sudo apt-get install -y \
build-essential \
uuid-dev \
libgpgme-dev \
squashfs-tools \
libseccomp-dev \
wget \
pkg-config \
git \
cryptsetup-bin \
libgpgme11-dev
mkdir -p ~/soft/go
cd $_
export VERSION=1.13.5 OS=linux ARCH=amd64 && \
wget https://dl.google.com/go/go$VERSION.$OS-$ARCH.tar.gz
sudo tar -C /usr/local -xzvf go$VERSION.$OS-$ARCH.tar.gz
echo 'export GOPATH=${HOME}/go' >> ~/.bashrc && \
echo 'export PATH=/usr/local/go/bin:${PATH}:${GOPATH}/bin' >> ~/.bashrc && \
source ~/.bashrc
mkdir -p ~/soft/singularity
cd $_
export VERSION=3.8.3 && # adjust this as necessary \
wget https://github.com/sylabs/singularity/releases/download/v3.8.3/singularity-ce-3.8.3.tar.gz
tar -xzf singularity-*${VERSION}.tar.gz
cd sing*
./mconfig && \
make -C ./builddir
sudo make -C ./builddir install
# test
singularity exec library://alpine cat /etc/alpine-release
apache
Also, configure iptables. Or ufw, open port 80/443, 22, and whatever the port the bettr image is going to use below.
bettr image
The bettr image is generated by https://renkulab.io/gitlab/omnibenchmark/bettr-deployer .
serving the bettr app
To read the bettr image from the registry, an user token with read_registry
power is needed; below encoded as INGULARITY_DOCKER_PASSWORD
.
mkdir -p ~/bettr_deployer/apps ~/bettr_deployer/logs ~/bettr_deployer/lib ~/bettr_deployer/tmp
cd ~/bettr_deployer
export SINGULARITY_DOCKER_USERNAME='izaskun.xx@xxxuzh.ch'
export SINGULARITY_DOCKER_PASSWORD='KxasgasgasgxK' # read_registry granted
export NAMESPACE="omnibenchmark"
export ID="obm_bettr"
export VERSION="1d0b31b"
singularity instance start --env SHINY_LOG_STDERR=1 \
--bind ./apps:/srv/shiny-server/bettr \
--bind ./log:/var/log/shiny-server_bettr \
--bind ./lib:/var/lib/shiny-server \
--bind ./tmp:/tmp \
bettr-deployer_"$ID"-"$VERSION".sif "$ID"_"$VERSION"
singularity exec instance://"$ID"_"$VERSION" "shiny-server" &
So apps will be served if placed at ~/bettr_deployer/apps, i.e.:
/home/shiny/bettr_deployer/apps/omni_clustering/:
total 12
-rw-rw-r-- 1 shiny shiny 1614 Jul 27 13:28 app.R
drwxrwxr-x 2 shiny shiny 4096 Sep 1 2022 data
-rw-rw-r-- 1 shiny shiny 0 Sep 1 2022 restart.txt
/home/shiny/bettr_deployer/apps/omni_clustering/data:
total 340
-rw-rw-r-- 1 shiny shiny 347951 Jan 19 2023 summary.json
where app.R
contains
#!/usr/bin/env R
## Retrieve data
## make recognize the argument as the data that has been just downloaded, for FAIR
suppressPackageStartupMessages({
library("bettr")
})
resDir <- 'data'
bstheme <- 'darkly'
appTitle <- 'bettr'
metrics <- 'all'
res_files <- list.files(path = paste0(resDir), full.names = TRUE)
## Read result files
out <- jsonlite::read_json(res_files, simplifyVector = TRUE)
## reconverting true false to logical
colnames(out$metricInfo) <- c("Metric", "Group")
out$initialTransforms <- lapply(out$initialTransforms, function(x){
lapply(x, function(y){
as.logical(y)
})
})
# replacing na value
out$idInfo[is.na(out$idInfo)] <- "NaN"
# call bettr
bettr(
df = out$df,
idCol = if (is.null(out$idCol)) {
"Method"
} else {
out$idCol
},
metrics = if (is.null(out$metrics)){
setdiff(colnames(out$df), out$idCol)
} else {
out$metrics
},
initialTransforms = if (is.null(out$initialTransforms)) {
list()
} else {
out$initialTransforms
},
metricInfo = out$metricInfo,
metricColors = out$metricColors,
idInfo = out$idInfo,
idColors = out$idColors,
weightResolution = if (is.null(out$weightResolution)) {
0.05
} else {
out$weightResolution
},
bstheme = if (is.null(out$bstheme)) {
"darkly"
} else {
out$bstheme
},
appTitle = if (is.null(out$appTitle)) {
"bettr"
} else {
out$appTitle
And the data is either a fixed snapshot (or retrieved periodically via cron) of a suitably formated metrics file, like this one.
DMZ-related maintenance
firewall / shiny ports
Mind to open port 3840 to fit the docker container shiny-server's port, or update the Dockerfile or the singularity port mapping as needed.
cron to retrieve results
Using the clustering benchmark as an example:
cd /home/shiny/bettr_deployer/apps/omni_clustering/data
wget -q https://renkulab.io/gitlab/omnibenchmark/omni_clustering/omni_clustering_summary/-/raw/main/data/omni_clustering_summary/omni_clustering_summary.json -O summary.json
## to make sure the shiny app reloads
touch ../app.R
Tips and troubleshooting
- (internal) The unusual shiny's UID 998 avoids a collision with robinsonlab's 999, whic is the rstudio-server user.