How to run R Shiny App in Docker Container
Asked Answered
A

3

7

I built a Docker Image for an R Shiny App and ran the corresponding container with Docker Toolbox on Windows 10 Home. When trying to open the App with my web browser, only the index is shown. I don't know why the app isn't executed.

The log shows me this:

*** warning - no files are being watched ***
[2019-08-12T15:34:42.688] [INFO] shiny-server - Shiny Server v1.5.12.1 (Node.js v10.15.3)
[2019-08-12T15:34:42.704] [INFO] shiny-server - Using config file "/etc/shiny-server/shiny-server.conf"
[2019-08-12T15:34:43.100] [INFO] shiny-server - Starting listener on http://[::]:3838

I already specified the app host-to-container path by executing the following command which refers to a docker hub image:

docker run --rm -p 3838:3838 -v /C/Docker/App/:/srv/shinyserver/ -v /C/Docker/shinylog:/var/log/shiny-server/  didsh123/ps_app:heatmap

My Docker File looks like the following:

# get shiny serves plus tidyverse packages image
FROM rocker/shiny-verse:latest

# system libraries of general use
RUN apt-get update && apt-get install -y \
    sudo \
    pandoc \
    pandoc-citeproc \
    libcurl4-gnutls-dev \
    libcairo2-dev \
    libxt-dev \
    libssl-dev \
    libssh2-1-dev

##Install R packages that are required--> were already succesfull
RUN R -e "install.packages(c('shinydashboard','shiny', 'plotly', 'dplyr', 'magrittr'))"

#Heatmap related packages
RUN R -e "install.packages('gpclib', type='source')"
RUN R -e "install.packages('rgeos', type='source')"
RUN R -e "install.packages('rgdal', type='source')"

# copy app to image
COPY ./App /srv/shiny-server/App

# add .conf file to image/container to preserve log file
COPY ./shiny-server.conf  /etc/shiny-server/shiny-server.conf


##When run image and create a container, this container will listen on port 3838
EXPOSE 3838

###Avoiding running as root --> run container as user instead
# allow permission
RUN sudo chown -R shiny:shiny /srv/shiny-server
# execute in the following as user --> imortant to give permission before that step
USER shiny

##run app
CMD ["/usr/bin/shiny-server.sh"]

So when I address the docker ip and the assessed port in the browser, the app should run there, but only the index is displayed. I use the following line:

http://192.168.99.100:3838/App/

I'm glad for every hint or advice. I'm new to Docker, so I'm also happy for detailed explanations.

Antonyantonym answered 8/8, 2019 at 22:51 Comment(0)
A
10

To use shiny with docker, I suggest you use the golem package. golem provides a framework for builing shiny apps. If you have an app developed according to their framework, the function golem::add_dockerfile() can be used to create dockerfiles automatically.

If you are not interested in a framework, You can still have a look at the source for add_dockerfile() to see how they manage the deployment. Their strategy is to use shiny::runApp() with the port argument. Therefore, shiny-server is not necessary in this case.

The Dockerfile in golem looks roughly like this

FROM rocker/tidyverse:3.6.1
RUN R -e 'install.packages("shiny")'
COPY app.R /app.R
EXPOSE 3838
CMD R -e 'shiny::runApp("app.R", port = 3838, host = "0.0.0.0")'

This will make the app available on port 3838. Of course, you will have to install any other R packages and system dependencies.

Additional tips

  • To increase reproducibility, I would suggest you use remotes::install_version() instead of install.packages().
  • If you are going to deploy several applications with similar dependencies (for example shinydashboard), it makes sense to write your own base image that can be used in place of rocker/tidyverse:3.6.1. This way, your builds will be much quicker.
Armchair answered 10/8, 2019 at 14:25 Comment(0)
S
4

Minimal Reproducible Example

  1. Create an empty directory (can be called anything you want)

  2. Inside it, create two things:

    i. A file called Dockerfile

    ii. An empty directory called app

  3. Place your shiny app inside the directory called app.

    • Your shiny app can be a single app.R file, or, for older shiny apps, ui.R and server.R. Either way is fine (see here for more on that).
  • If unsure about any of the above, just copy the files found here.

Place this in Dockerfile

FROM rocker/shiny:latest

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

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

In the terminal, cd to the root of the empty directory you created in step 1, and build the image with

docker build -t shinyimage . 

Run the container with

docker run -p 3838:3838 shinyimage

Finally, visit this url to see your shiny app: http://localhost:3838/

Here's a copy of all of the above in case anything's unclear.

enter image description here

Salamone answered 11/4, 2022 at 9:14 Comment(0)
S
0

Check the logs for any useful information? And exec into the container to verify if the App content is copied to the correct location.

Because the way /App content is copied looks incorrect

The content of /App is copied into the image to /srv/shiny-server/App during the build phase and you are trying to override /srv/shiny-server content using -v option when running the container.

Looks like during runtime the App data copied is being overwritten.

Try without -v /C/Docker/App/:/srv/shinyserver/ or use -v /C/Docker/App/:/srv/shinyserver/App/

docker run --rm -p 3838:3838 -v /C/Docker/shinylog:/var/log/shiny-server/ didsh123/ps_app:heatmap

Samuels answered 9/8, 2019 at 3:44 Comment(6)
Thank you for the advice concerning the /App content. I fixed this. But since I'm new to Docker, I did not work with log files yet. I attached the lines I received when executing the log command to my question above. Could you have a look at them, too? Furthermore, I executed the container as you suggested, it worked.Antonyantonym
@Antonyantonym Good to know it worked. Based on the logs the app is using the config file /etc/shiny-server/shiny-server.conf, but when you are copying COPY ./shiny-server.conf.txt /etc/shiny-server/ - .txt file is copied. That means your app is using default config instead of the file you copied into the image.Samuels
You can also add USER appuser to dockerfile to mitigate the security risk warning from the logs. Ref: medium.com/@mccode/…Samuels
The container is not running as root anymore, but as user instead (see edits in question). So this is fixed, but still the same issue. Could it have something to do with the config file? What would be the correct command inside the docker file to copy my own config file from the github repository to which it is related instead of the default one you mentioned?Antonyantonym
@Antonyantonym - Use this COPY ./shiny-server.conf /etc/shiny-server/. Your are trying to copy a .txt file into /etc/shiny-server - check the file extension in the local directory.Samuels
Now I'm using a slightly adjusted file from a tutorial and also modified the Dockerfile as you suggested, but it seems like the COPY command doesn't work properly. I defined the shiny User inside the Dockerfile as well as in the config file, but as soon as I comment that line in the Dockerfile out, the log shows me the 'running as root' warning again. Do you have an idea here?Antonyantonym

© 2022 - 2024 — McMap. All rights reserved.