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
The parent image of the
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.
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
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:
|Parent image||Parent size (GB)||Final size (GB)||Bild time (min)|
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
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.