Site icon R-bloggers

Running Shiny Server in Docker

[This article was first published on R - Hosting Data Apps, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

We looked at best practices for R with Docker where we compared four commonly used parent images. It was common in these images that these all contained a "local" Shiny app using shiny::runApp(). A special breed of dockerized Shiny apps is when the Shiny Server is running inside the Docker container. In this post, we'll explore this "dockerized Shiny Server" setup and discuss the pros and cons.

The files from this post can be found in the analythium/covidapp-shiny GitHub repository, inside the 99-images folder.

analythium/covidapp-shiny
A simple Shiny app to display and forecast COVID-19 daily cases – analythium/covidapp-shiny
GitHubanalythium

The Dockerfile

The parent image of the Dockerfile is rocker/shiny. This image is part of the Rocker project and is based on the versioned Ubuntu line of R images. It contains a versioned R installation, Shiny Server Open Source. It already has the shiny user defined and port 3838 exposed.

Shiny Server running inside a Docker container

On top of the parent image, you can follow the same pattern that we used for other base images: install system dependencies, install R packages, copy files for the Shiny app. The Shiny app goes inside the /srv/shiny-server/ folder where you can have more than one shiny app in different folders. You may also copy HTML files to provide navigation for your users.

We'll copy the files for the COVID-19 app, change the user to shiny (the EXPOSE directive is not needed but I left it there as a reminder). Finally, we define the command as /usr/bin/shiny-server to start the Shiny Server:

FROM rocker/shiny:4.0.5

# Install system requirements for index.R as needed
RUN apt-get update && apt-get install -y \
    --no-install-recommends \
    git-core \
    libssl-dev \
    libcurl4-gnutls-dev \
    curl \
    libsodium-dev \
    libxml2-dev \
    libicu-dev \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

ENV _R_SHLIB_STRIP_=true
COPY Rprofile.site /etc/R
RUN install2.r --error --skipinstalled \
    shiny \
    forecast \
    jsonlite \
    ggplot2 \
    htmltools \
    plotly

COPY ./app/* /srv/shiny-server/

USER shiny

EXPOSE 3838

CMD ["/usr/bin/shiny-server"]

The Docker image

I used the Docker BuildKit as explained before, then tested the image. Here is the script for your to replicate:

export IMAGE="analythium/covidapp-shiny:shiny"
export FILE="Dockerfile.shiny"
DOCKER_BUILDKIT=1 docker build --no-cache -f $FILE -t $IMAGE .
docker run -p 8080:3838 $IMAGE

Here is how build times and image sizes compare across the five images:

< !--kg-card-begin: markdown-->
Parent image Parent size (GB) Final size (GB) Bild time (min)
rhub/r-minimal 0.035 0.222 27.0
rocker/r-base 0.761 1.050 2.9
rocker/r-ubuntu 0.673 1.220 3.1
rstudio/r-base 0.894 1.380 3.1
rocker/shiny 1.380 1.610 2.3
< !--kg-card-end: markdown-->

Build time was comparably small for all the other non-Alpine images, however, the size of the parent and the final images were the largest among the 5 different options.

Here are some thoughts to consider when using the rocker/shiny parent image to host a containerized Shiny applications.

You can run multiple Shiny apps over the same port exposed by Docker. The Shiny Server configuration allows you to disable the websocket protocol, this way you can host your apps in Container-as-a-Service environments, like Google Cloud Run, etc.

However, the image size is the largest among the comparable options. If the image includes multiple apps, those apps are not isolated, and managing their dependencies might become problematic over time.

An alternative use case for the rocker/shiny image is to host Shiny apps that are not copied into the image. This is done by mounting the app folder as a volume to the container (that is a live instance of the image) as explained on the Docker Hub page.

The next command adds two volumes, one with the apps and one for the Shiny Server logs in a -v host:container  fashion. The directories on the host will be created if those don't already exist.

docker run -d -p 8080:3838 \
    -v /srv/shinyapps/:/srv/shiny-server/ \
    -v /srv/shinylog/:/var/log/shiny-server/ \
    rocker/shiny

This setup can be especially useful for hosting Shiny Apps in a Windows environment. You will need to add dependencies using the RUN directive.

Summary

The dockerized Shiny Server is a heavyweight option for hosting a single app, but it plays an important role in the Shiny hosting landscape. It allows you to run Shiny apps in unusual situations, like on Windows, or hosted container platforms.

Further reading

To leave a comment for the author, please follow the link and comment on their blog: R - Hosting Data Apps.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.