5

I am looking into docker to distribute a shiny application that also requires RStudio. The primary goal is easy installation at hospitals under Windows. Everything that requires character input into black boxes will certainly fail during installation by non-IT people.

My previous attempts used vagrant, but installing vagrant alone proved to be a hurdle.

The rocker repository, has an RStudio and a Shiny , and for my own installation both work together. However, I would like to create a combined application for easier installation.

What is the recommended workflow? Start with RStudio, and manually add Shiny? Or merge the dockerfiles code from both Rockers, starting with r-base? Or use compose tool?

Dieter Menne
  • 10,076
  • 44
  • 67
  • Do in your Dockerfile the same thing you do when logged on your server, install various software, put specific configuration, start some executables... And if some things are not so easy to automate, you can use `docker commit` after some specific configuration – user2915097 Mar 23 '15 at 20:21
  • I wouldn't try to do this in one Dockerfile unless you have a compelling reason to do so (ie, you have some packages that have many additional requirements). You're better off using docker-compose for this situation. – Brandon Bertelsen Oct 28 '16 at 14:34
  • Related: https://github.com/mikkelkrogsholm/encrypted_dashboard – Brandon Bertelsen Aug 27 '17 at 16:20

4 Answers4

7

The point of Docker, in general, is isolation of services so that they can be updated/changed without effecting others. My recommendation would be to use docker-compose, instead. Below is an example docker-compose yaml file that serves both rstudio and shiny on the same server at different subdomains using the incredibly useful docker-gen by Jason Wilder. All R docker images used below are courtesy of Rocker or more directly Rocker Docker Hub. These are very very reliable because, well, Dirk Eddelbeutel and Carl Boettiger made them. In this example I've also included some options for RStudio such as setting a user/pass and whether or not the user has root access. There are more instructions on using the Rocker RStudio image available on this wiki page:

Change the following:

  • your_user to your username on the server
  • SOME_USER to your desired RStudio username
  • SOME_PASS to your desired Rstudio password
  • *.DOMAIN.tld to your domain, don't forget to add A records for your subdomains.

nginx1:
  image: nginx
  container_name: nginx
  ports:
  - "80:80"
  - "443:443"
  volumes:
    - /etc/nginx/conf.d
    - /etc/nginx/vhost.d
    - /usr/share/nginx/html
    - /home/your_user/services/volumes/proxy/certs:/etc/nginx/certs:ro

nginx-gen:
  links:
    - "nginx1"
  image: jwilder/docker-gen
  container_name: nginx-gen
  volumes:
    - /var/run/docker.sock:/tmp/docker.sock:ro
    - /home/your_user/services/volumes/proxy/templates/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro
  volumes_from:
    - nginx1
  entrypoint: /usr/local/bin/docker-gen -notify-sighup nginx -watch -only-exposed -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf

rstudio:
  links:
    - "nginx1"
  image: rocker/hadleyverse
  container_name: rstudio
  ports:
    - "8787:8787"
  environment:
    - VIRTUAL_PORT=8787
    - ROOT=TRUE
    - VIRTUAL_HOST=rstudio.DOMAIN.tld
    - USER=SOME_USER
    - PASSWORD=SOME_PASS

shiny:
  links:
    - "nginx1"
  image: rocker/shiny
  container_name: shiny
  environment:
    - VIRTUAL_HOST=shiny.DOMAIN.tld
  volumes:
    - /home/your_user/services/volumes/shiny/apps:/srv/shiny-server/
    - /home/your_user/services/volumes/shiny/logs:/var/log/
    - /home/your_user/services/volumes/shiny/packages:/home/shiny/

It's trivial to add more services like a blog, for example, just follow the pattern or search the internet for a docker-compose version of your service and add it.

Brandon Bertelsen
  • 43,807
  • 34
  • 160
  • 255
3

Interesting question, but I'm not sure I understand the advantage of having the shiny-server and the rstudio-server instances served from the same container.

Is the purpose so that the two containers share the same R libraries (e.g. so a package doesn't need to be installed separately on each) or merely to have one docker container instead of two? Just having to run two docker commands instead of one doesn't seem that onerous, but maybe I'm underestimating.

Sharing the underlying libraries seems like a valid objective though, and I don't think there's an ideal solution available yet.

I feel the most docker-esque solution would be to do this via container orchestration/compose tool as you mention. This is the usual way to combine separate services (e.g. web server and database) without building one on top of the other.

Unfortunately, the tooling for orchestration based on mapping volumes is not nearly as well developed as it is for mapping ports.

Imagine running the rstudio as a volume container:

docker run --name rstudio -v /usr/local/lib/R/site.library rocker/rstudio true

(If you wanted RStudio access at the same time, one could instead run this as:)

docker run --name rstudio -dP -v /usr/local/lib/R/site.library rocker/rstudio

You can then use the the site.library from the rstudio container in place of that on the shiny container with a command like:

docker run --volumes-from rstudio -dP rocker/shiny

Unfortunately, this clobbers the site.library of the shiny container. To work around this, you'd want to mount the library of the rstudio container in a different place, but there's no easy syntax for this like we already have with port links. It can be done though, see:

How to map volume paths using Docker's --volumes-from?

There's an open thread on this issue in the rocker repo too.

Community
  • 1
  • 1
cboettig
  • 12,377
  • 13
  • 70
  • 113
  • Thanks for your comments and the link to the open thread which was new to me. I need RStudio and Shiny in one box because the users should have some way to make simple changes in the shiny program without too much distracting installation stuff. I had already noted that the library sharing is one of the nasty problems. Ouff... looks like there is no easy solution to shrink-wrapped shiny programs. – Dieter Menne Mar 24 '15 at 17:17
  • 1
    makes sense. maybe rocker should consider a kitchen-sink style container just in case, but would need a better maintenance workflow. Do you see users using `docker commit` to preserve those simple changes then? – cboettig Mar 24 '15 at 17:49
2

I have developed a working single docker for

  • R
  • RStudio (server)
  • Shiny Server (free edition)

I built it exactly for the same reasons mentioned by @Dieter Menne. It may be not ideal for ops, but it great for dev (especially if the team members all use different envs. like mac, windows etc.).

It is on Centos 6 as this is the env. I use at work.

This is the dockerfile:

FROM centos:centos6.7
MAINTAINER enzo smartinsightsfromdata 

RUN yum -y install epel-release
RUN yum update -y && yum clean all
# RUN yum reinstall -y glibc-common
RUN yum install -y locales java-1.7.0-openjdk-devel tar

# Misc packages

RUN yum groupinstall -y "Development Tools" 

# R devtools pre-requisites:
RUN yum install -y wget git xml2 libxml2-devel curl curl-devel openssl-devel


WORKDIR /home/root
RUN yum install -y R

RUN wget http://cran.r-project.org/src/contrib/rJava_0.9-7.tar.gz
RUN R CMD INSTALL rJava_0.9-7.tar.gz
RUN R CMD javareconf \
    && rm -rf rJava_0.9-7.tar.gz

#-----------------------

# Add RStudio binaries to PATH
# export PATH="/usr/lib/rstudio-server/bin/:$PATH"
ENV PATH /usr/lib/rstudio-server/bin/:$PATH 
ENV LANG en_US.UTF-8

RUN yum install -y openssl098e supervisor passwd pandoc

# RUN wget http://download2.rstudio.org/rstudio-server-rhel-0.99.484-x86_64.rpm
# Go for the bleading edge:
RUN wget https://s3.amazonaws.com/rstudio-dailybuilds/rstudio-server-rhel-0.99.697-x86_64.rpm
RUN yum -y install --nogpgcheck rstudio-server-rhel-0.99.697-x86_64.rpm \
    && rm -rf rstudio-server-rhel-0.99.484-x86_64.rpm

RUN groupadd rstudio \
    && useradd -g rstudio rstudio \
    && echo rstudio | passwd rstudio --stdin 

RUN R -e "install.packages(c('shiny', 'rmarkdown'), repos='http://cran.r-project.org', INSTALL_opts='--no-html')"
RUN wget https://download3.rstudio.org/centos5.9/x86_64/shiny-server-1.4.0.756-rh5-x86_64.rpm
RUN yum -y install --nogpgcheck shiny-server-1.4.0.756-rh5-x86_64.rpm \
    && rm -rf shiny-server-1.4.0.756-rh5-x86_64.rpm

RUN mkdir -p /var/log/shiny-server \
    && chown shiny:shiny /var/log/shiny-server \
    && chown shiny:shiny -R /srv/shiny-server \
    && chmod 777 -R /srv/shiny-server \
    && chown shiny:shiny -R /opt/shiny-server/samples/sample-apps \
    && chmod 777 -R /opt/shiny-server/samples/sample-apps 

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
RUN mkdir -p /var/log/supervisor \
    && chmod 777 -R /var/log/supervisor


EXPOSE 8787 3838

CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] 

This is how the supervisord.conf file looks like:

[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisord.log
pidfile = /tmp/supervisord.pid


[program:rserver]
user=root
command=/usr/lib/rstudio-server/bin/rserver
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
startsecs=0
autorestart=false

[program:shinyserver]
user=root
command=/usr/bin/shiny-server
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=false

It is available at my github page: smartinsightsfromdata

I have also developed a working docker for shiny server pro on centos (using shiny server pro temporary edition, valid 45 days only).

Enzo
  • 2,543
  • 1
  • 25
  • 38
1

Somewhat unfortunately, there is no definite answer, it all depends on how much reusability you would be looking for and whether an upstream base image is well maintained. The is also images size tradeoff, more layers there are, bigger the resulting image gets.

errordeveloper
  • 6,716
  • 6
  • 41
  • 54