R Shiny Containerized

One of the technologies that I am happy to have found out in the previous years has been Docker. In a nutshell, it avoid the it works in my computer moment that we have all experienced.

By harnessing Docker’s containerization capabilities, we can encapsulate our R Shiny applications and their dependencies, ensuring consistency and easy portability across various environments.

But I was wondering how to create my own containerized R Shiny App and the R-Stocks projec presented me the perfect opportunity.

Building R Shiny Apps in Docker

  • Docker plays a pivotal role in enabling reproducible work by providing a consistent and isolated environment for software development and deployment.
    • Dependency Management: Docker allows you to define and package all the dependencies required for your project within a container. By encapsulating the necessary libraries, frameworks, and tools, you ensure that the exact same environment is replicated across different systems, eliminating compatibility issues and ensuring consistent behavior.
    • Portability: Docker containers are highly portable, enabling you to run the same software stack on different machines, operating systems, or cloud platforms. This eliminates platform-specific discrepancies and ensures that your work can be replicated regardless of the underlying infrastructure.
    • Collaboration: With Docker, you can easily share your project as a self-contained container. This simplifies collaboration by allowing others to quickly spin up the same environment, work on the project, and reproduce your results without the need for complex setup or configuration.

Pre-Requisites

  • Have Docker installed
  • Have clear which functions/packages your code depends on
    • Make sure that the FROM image that you are using contains a R version that supports all the necessary packages.
    • For example yfR. as of today needs R with at least version 4.
  • Better if you also know the specific versions of the packages that make your code work

R Shiny Apps for X86

Let’s start from something simpler, a regular X86 computer. And for this architecture flavour, I could easily find few ways to create our R Shiny App Docker images:

We will use the build command, together with any of the following Dockerfiles:

docker build --no-cache --progress=plain -t r_stocks
#DOCKER_BUILDKIT=1 docker build --no-cache --progress=plain -t r_stocks:V1-amd64 --build-arg ARCH=arm64 .

From R-Base

FROM r-base:latest
LABEL maintainer "JAlcocerT <jalcocert@fossengineer.com>"
RUN apt-get update && apt-get install -y --no-install-recommends \
   sudo \
   libcurl4-gnutls-dev \
   libcairo2-dev \
   libxt-dev \
   libssl-dev \
   libssh2-1-dev \
   && rm -rf /var/lib/apt/lists/*


# Install remotes package
RUN R -e 'install.packages("remotes")'


RUN R -e 'install.packages(c("shiny", "plotly", "dplyr","viridis", "tidyr","lubridate","shinythemes","shinyWidgets","DT","bslib","priceR","quantmod"))'
RUN R -e 'install.packages("yfR", dependencies = TRUE)'

# Install specific versions of Shiny and Plotly, along with their dependencies
# RUN R -e 'remotes::install_version("shiny", version = "1.6.0", dependencies = TRUE)'
# RUN R -e 'remotes::install_version("plotly", version = "4.9.3", dependencies = TRUE)'

# Copy app.R to the container
COPY app.R /srv/shiny-server/app.R


# Expose the required port
EXPOSE 3838

# Set the CMD to run the Shiny app
CMD ["R", "-e", "shiny::runApp('/srv/shiny-server/app.R', host = '0.0.0.0', port = 3838)"]

R Shiny App in Docker - with rocker/Shiny Image

FROM rocker/shiny:3.6.1
LABEL maintainer "JAlcocerT <jalcocert@fossengineer.com>"

WORKDIR /srv/shiny-serverRUN apt-get update \
   && apt-get install -y libsasl2-dev libssl-devRUN echo \
 'options(repos=list(CRAN="https://cloud.r-project.org/"))' > \
 ".Rprofile"

RUN R -e 'install.packages(c("shiny", "plotly", "dplyr","viridis", "tidyr","lubridate","shinythemes","shinyWidgets","DT","bslib","priceR","quantmod"))'


RUN R -e 'install.packages("yfR", dependencies = TRUE)'

ADD https://raw.githubusercontent.com/rocker-org/shiny/master/shiny-server.sh /usr/bin/

COPY ./ ./
EXPOSE 3838
RUN chmod a+w .
RUN chmod +x /usr/bin/shiny-server.sh
CMD /usr/bin/shiny-server.sh

R Shiny App in Docker - with rocker/Tideverse Image

Instead of using rocker/shiny:3.6.1, you can use rocker/tidyverse:3.6.1 and install the shiny package separately.

This will make your app available on port 3838 without the need for Shiny Server!

FROM rocker/tidyverse:4
LABEL maintainer "JAlcocerT <jalcocert@fossengineer.com>"

RUN R -e 'install.packages(c("shiny", "plotly","viridis", "dplyr", "tidyr","lubridate","shinythemes","shinyWidgets","DT","bslib","priceR","quantmod"))'


RUN R -e 'install.packages("yfR", dependencies = TRUE)'


COPY app.R /app.R


EXPOSE 3838


CMD R -e 'shiny::runApp("app.R", port = 3838, host = "0.0.0.0")'

Running & Pushing the Docker Image

Once the build completes, you can run it with:

docker run --name r_stocksshiny -p 3838:3838 --restart unless-stopped -d r_stocks

And push it to DockerHub with (use your username):

docker tag r_stocks docker.io/fossengineer/r_stocks:v1-amd64
#docker login
docker push fossengineer/r_stocks:v1-amd64

R Shiny Apps for ARM86

Any of the tidyverse docker images is available for ARM at this moment. This is a good chance to learn how to install our packages, but starting from an R Base image with ARM.

I have found this one to be working for ARM86. And had to take use of webtops to discover that it was the libxml2-dev the one missing to allow the installation of the yfR package.

FROM r-base:latest
LABEL maintainer "JAlcocerT <jalcocert@fossengineer.com>"
RUN apt-get update && apt-get install -y --no-install-recommends \
   sudo \
   libcurl4-gnutls-dev \
   libcairo2-dev \
   libxt-dev \
   libssl-dev \
   libssh2-1-dev \
   libxml2-dev \
   && rm -rf /var/lib/apt/lists/*

# Install remotes package
RUN R -e 'install.packages("remotes")'

RUN R -e 'install.packages(c("shiny", "plotly","viridis" ,"dplyr", "tidyr","lubridate","shinythemes","shinyWidgets","DT","bslib","priceR","quantmod"))'
RUN R -e 'install.packages("yfR", dependencies = TRUE)'

# Install specific versions of Shiny and Plotly, along with their dependencies
# RUN R -e 'remotes::install_version("shiny", version = "1.6.0", dependencies = TRUE)'
# RUN R -e 'remotes::install_version("plotly", version = "4.9.3", dependencies = TRUE)'

# Copy app.R to the container
COPY app.R /srv/shiny-server/app.R

# Expose the required port
EXPOSE 3838

# Set the CMD to run the Shiny app
CMD ["R", "-e", "shiny::runApp('/srv/shiny-server/app.R', host = '0.0.0.0', port = 3838)"]

To build it, we can use:

#DOCKER_BUILDKIT=0 docker build -t my-image .
#DOCKER_BUILDKIT=1 docker build --no-cache --progress=plain -t r_stocks_arm64 .
DOCKER_BUILDKIT=1 docker build --no-cache --progress=plain -t r_stocks:V1-arm64 .