Dockerizing your shiny app

Phil Chapman

2019/05/19

Introduction

This is the second post in a series about turning data science products written in R into products that can be consumed by technical and non-technical colleagues who don’t use R, without any significant additional infrastructure. As I discussed in more detail in the first post, this requires taking advantage of common DevOps workflows and approaches involving Docker.

Why Shiny?

Most R users will have heard of Shiny, it is an R package that makes it exceptionally easy to turn some R code into an interactive web application. If you haven’t heard of it then take a look at the Shiny Gallery for some examples.

How are Shiny apps typically deployed and used?

Shiny apps are initially developed and used interactively within an RStudio session, and the code can be shared between R users relatively easily. If there is a requirement for a non-R user to use a Shiny application, then RStudio’s Shiny Server can host apps on a central server and has an open source and Pro version available. A Software-as-a-service option version of Shiny Server is also available called ShinyApps.io, whilst RStudio Connect offers even more functionality including hosting Shiny apps.

Why Dockerize then?

Given all of these options for hosting Shiny apps, what role does Docker play? As I explained in my first post, assuming that you don’t want to host your Shiny app in the public domain then you either have to rely on your collaborator to be able to know enough about R to run your app in RStudio, or to have some secure hosting infrastructure available. Dockerizing a Shiny app gives the option that your collaborator only needs to know the basics of git, the command line, and Docker, and nothing about R or Shiny.

An example

As in the first post, we are using the famous gapminder dataset. The scenario is that we have written a very simple shiny app to interactively explore the data via some basic plots, and we want to share that app with someone who isn’t familiar with R but has got at least a basic understanding of Docker and Git.

The git repo

Running instructions

The code for these blog posts is on GitHub - https://github.com/chapmandu2/gapminder-pipeline/. In this post we are considering the code in the directory 02-shiny-app. Within this repo there are three files in the top directory and a further file in the plot-app subdirectory:

These four files contain all of the information needed to run the Shiny app.

To run the app:

The Dockerfile

The Dockerfile builds on that used in the first post by installing and configuring Shiny Server:

FROM rocker/verse:3.5.2

# add shiny server
RUN export ADD=shiny && bash /etc/cont-init.d/add

################
#install linux deps
################

RUN apt-get update -y && \
	apt-get install -y \ 
		curl

################
#install R packages
################

RUN R -e "install.packages(c('gapminder'))"

################
# configure shiny server
################

COPY ./shiny-server.conf /etc/shiny-server/shiny-server.conf
COPY ./plot-app /home/rstudio/ShinyApps/plot-app/
RUN chown -hR rstudio:rstudio /home/rstudio/ShinyApps

The base image is rocker/verse from the Rocker project, but this Dockerfile takes advantage of the functionality provided with the Rocker images to add Shiny Server as well as RStudio Server. It then runs the commands to install linux utilities and the gapminder R package. Finally it configures Shiny Server by copying a shiny-server configuration file shiny-server.conf into the image, as well as the contents of the plot-app directory. Finally it sets the appropriate owner permissions for the newly created ShinyApps directory.

The Makefile

The Makefile provides the user with an easy way to execute the Docker commands required to build the Docker image and run the Docker containers. The make run command is below:

run: build
	docker run -d -p 8787:8787 -p 3838:3838 \
		-e DISABLE_AUTH=true \
		--name='gapminder-02-ct' \
		-v ${HOME}:/home/rstudio/hostdata \
		gapminder-02;

	sleep 3;
	firefox 127.0.0.1:8787;
	firefox 127.0.0.1:3838/users/rstudio;

The other commands in the Makefile are convenience commands to start, stop and delete containers.

This approach of exposing both RStudio Server and Shiny Server allows a user to not only view the Shiny App, but to also use RStudio to explore the code in more detail and potentially make changes.

Deploying a Shiny app

There is also a make deploy command:

deploy: build
	docker run -d -p 9001:3838 \
		-e DISABLE_AUTH=true \
		--name='gapminder-02-deploy' \
		gapminder-02;

	sleep 3;
	firefox 127.0.0.1:9001/users/rstudio/plot-app/;

This command only exposes the Shiny Server endpoint on port 9001 also jumps straight to the plot-app Shiny app. This command could also be used to deploy the Docker image as a service, for example using MS Azure App Services or on a Kubernetes cluster.

Conclusions

This blog post has provided a basic template for Dockerizing a shiny app so that it is portable and relatively reproducible. This approach allows a Shiny app and its dependencies (and an RStudio Server to modify the app) to be shared between colleagues with only a minimal understanding of Docker and the command line required. It also sets the foundation for the Shiny app to be deployed as a Docker container service, for example using MS Azure App Services or equivalent services from Amazon Web Services or Google Cloud Platform.