---
title: "Shiny App"
author: "Mark Edmondson"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Shiny App}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

# Self-contained Shiny app

This creates a dedicated Docker container that has all the libraries, files and scripts necessary to run your Shiny app. 
This example uses a local `Dockerfile` to install the libraries you need, 
but in addition also copies your Shiny app scripts so its all self-contained and portable. 

The Shiny app can then be deployed on new instances.

In summary:

1. Create a Dockerfile including copying the Shiny app into the Docker image
2. Use build triggers or `docker_build()` to create and push your Shiny image to Google container registry
3. Start up a Shiny templated Google Compute Engine VM calling your custom Shiny image
5. Enjoy your Shiny app

Once built, you can deploy straight from the Container Registry, so not necessarily needing steps 1 and 2. 

### Google Container Registry - Build Triggers

You can use build triggers from [Google Container Registry](https://cloud.google.com/container-registry/) to build the docker image.  

This is typically done by pushing up to a GitHub repository with your Dockerfile, which [triggers a build](https://cloud.google.com/container-builder/docs/concepts/creating-build-triggers).  You can then construct the name of this docker image directly using `gce_tag_container`, for use in a Shiny templated `gce_vm` call. 

## Create a Dockerfile in build folder, including copying the Shiny app into the Docker image

The `Dockerfile` includes a `COPY` command to copy necessary Shiny files such as `ui.R` and `server.R` into the Docker image. 

The Shiny app example below is the [`googleAuthR` demo app](https://mark.shinyapps.io/googleAuthRexample/), and the build directory can be found via: `get_dockerfolder("shiny-googleAuthRdemo")`

```sh
FROM rocker/shiny
MAINTAINER Mark Edmondson (r@sunholo.com)

# install R package dependencies
RUN apt-get update && apt-get install -y \
    libssl-dev \
    ## clean up
    && apt-get clean \ 
    && rm -rf /var/lib/apt/lists/ \ 
    && rm -rf /tmp/downloaded_packages/ /tmp/*.rds
    
## Install packages from CRAN
RUN install2.r --error \ 
    -r 'http://cran.rstudio.com' \
    googleAuthR \
    && Rscript -e "devtools::install_github(c('MarkEdmondson1234/googleID')" \
    ## clean up
    && rm -rf /tmp/downloaded_packages/ /tmp/*.rds

## assume shiny app is in build folder /shiny
COPY ./shiny/ /srv/shiny-server/myapp/

```

The `COPY` command copies from a folder in the same location as the `Dockerfile`, and then places it within the `/srv/shiny-server/` folder which is the default location for Shiny apps.  This location means that the Shiny app will be avialable at `xxx.xxx.xxx.xxx/myapp/`

The example Dockerfile above installs `googleAuthR` from CRAN, `googleID` from GitHub and a Debian dependency for `googleAuthR` that is needed, `libssl-dev` via `apt-get`.  Modify this for your own needs. 

### Public Docker images

The `FROM` field could be a previously made image you or someone else has already created, allowing you to layer on top.  The above example is available via a public Google Continer Registry window, made for this purpose, which you can see here: `https://console.cloud.google.com/gcr/images/gcer-public?project=gcer-public`

The `shiny-googleauthrdemo` is the Dockerfile above - the name for this can be created via the `gce_tag_container()` function:

```r
library(googleComputeEngineR)
gce_tag_container("shiny-googleauthrdemo", project = "gcer-public")
```

This can then be added to your Dockerfile:

```sh
FROM gcr.io/gcer-public/shiny-googleauthrdemo
MAINTAINER Mark Edmondson (r@sunholo.com)

# install R package dependencies
RUN apt-get update && apt-get install -y \
    ##### ADD YOUR DEPENDENCIES
    ## clean up
    && apt-get clean \ 
    && rm -rf /var/lib/apt/lists/ \ 
    && rm -rf /tmp/downloaded_packages/ /tmp/*.rds
    
## Install packages from CRAN
RUN install2.r --error \ 
    -r 'http://cran.rstudio.com' \
    ##### ADD YOUR CRAN PACKAGES
    ##### && Rscript -e "devtools::install_github( ## ADD YOUR GITHUB PACKAGES )" \
    ## clean up
    && rm -rf /tmp/downloaded_packages/ /tmp/*.rds

## copy your shiny app folder below
COPY ./shiny/ /srv/shiny-server/myapp/
```

Hopefully more images can be added in the future, along with community contributions.  They are rebuilt every commit to the `googleComputeEngineR` GitHub repo. 

### Create your Shiny app and place in subfolder of your build folder

Once you have the Dockerfile, place it into a folder with this structure alongside your Shiny app:

```
|
|- /appname/
   |
   |- ui.R
   |- server.R
| Dockerfile

```

The file structure for this build is then:
```r
list.files(get_dockerfolder("shiny-googleAuthRdemo"), recursive = TRUE)
# "Dockerfile"        "shiny/DESCRIPTION" "shiny/readme.md"   "shiny/server.R"    "shiny/ui.R"
```

## Build your Shiny app Docker image

You have a few options here:

* Build the Dockerfile image by pushing up to a GitHub repo with a set up [build trigger](https://cloud.google.com/container-builder/docs/concepts/creating-build-triggers)
* Build locally or within a custom GCE image using `docker_build`
* Use a premade Shiny app that someone else has created

Building images may take 10mins or so, especially if its the first layer of the image. 

## Start up a Shiny templated Google Compute Engine VM with your custom image

Start up a Shiny templated image, which makes sure the right ports are open etc. but also supply the `dynamic_image` argument pointing at the Docker image you have built in previous step.

```r
## make new Shiny template VM for your self-contained Shiny app
vm <- gce_vm("myapp", 
             template = "shiny",
             predefined_type = "n1-standard-2",
             dynamic_image = gce_tag_container("custom-shiny-app", "your-project"))
```

### Re-deploy already built Shiny app to another VM

Now you have a built app, you can deploy it to other instances simply by specifying the build shiny image.  If using the recommended Build trigger method, you can specify development or production folders in your GitHub repository.  You will need to restart a Shiny VM to load the latest build. 

## Tidy up

Clean up the VMs to avoid unnecessary costs:

```r
# delete build VM
gce_vm_delete(vm)
```
