R Shiny and Google Cloud Run
Dashboards are useful when you want your audience to be able to explore data without asking them to read through static tables or code. In R, Shiny provides a simple framework for turning your analysis into an interactive web application.
A Shiny app still needs an environment in which to run. It needs R, the required packages, the data files, and system libraries. On a local machine, those pieces are provided by your own computer. On a managed service such as Posit Connect, they are provided by the hosting platform. However, for projects that require more control over memory, processing power, package versions, system dependencies, access rules, logs, or deployment settings, Google Cloud Run is a useful option.
Cloud Run runs containerized applications on Google Cloud without requiring you to manage the underlying server directly, which makes it a practical way to deploy a Shiny app once your app has been packaged with Docker.
Start with a Working Shiny App
The first step is to have a functional app or dashboard. In simple terms, a Shiny app has two main parts. The user interface defines what the user sees, while the server defines what R does when the user changes an input. The input object stores user choices, and the output object stores the tables, plots, text, or other objects sent back to the interface.
Below is a short introduction to R Shiny.
The rest of the tutorial assumes that this local app already runs without errors.
Once the app runs locally, the next step is deployment. A cloud version of the app needs a compatible environment with the required R version, packages, files, and system dependencies. Docker is useful because it describes that environment in a reproducible way.
Building the Docker Image
Running a Shiny app on Cloud Run requires packaging the app with Docker. For a Shiny app, the Dockerfile says which R image to start from, which R packages to install, where to copy the app files, which port the app should use, and which command should run when the container starts.
A minimal version looks something like this:
FROM rocker/shiny:4.4.0
USER root
RUN install2.r --error --skipinstalled --ncpus -1 \
palmerpenguins \
dplyr \
ggplot2
WORKDIR /srv/shiny-server
COPY . /srv/shiny-server
RUN chown -R shiny:shiny /srv/shiny-server
ENV PORT=8080
EXPOSE 8080
USER shiny
CMD ["R", "-e", "shiny::runApp('/srv/shiny-server', host='0.0.0.0', port=as.numeric(Sys.getenv('PORT', '8080')))"]Here we are using rocker/shiny:4.4.0, a prebuilt Docker image from the Rocker project that already includes R 4.4.0, Shiny Server, and the basic Linux setup needed to run a Shiny app. This lets the Dockerfile start from an existing R and Shiny environment instead of building everything from zero.
The Dockerfile also installs the R packages needed by the app. In this example, it installs palmerpenguins, dplyr, and ggplot2. Other apps will need different packages, depending on what they use.
Cloud Run expects the container to listen for requests on the correct port. By default, that is port 8080, and Cloud Run provides the PORT environment variable to the container.
Once the app.R file and the Dockerfile are in a GitHub repository, Cloud Run can be connected to that repository. Google then uses Cloud Build to create the Docker image from the Dockerfile and deploys that image as a Cloud Run service. This means the repository becomes the source for future deployments, so changes to the app can be pushed to GitHub and rebuilt through the same Cloud Run setup.
Setting up Google Cloud
Google Cloud is Google’s platform for renting computing infrastructure over the internet. It is similar to Amazon Web Services (AWS) or Microsoft Azure.
Cloud Run is a service within Google Cloud that lets you run an application online without managing the server yourself. You provide the app as a container, and Cloud Run handles starting it, keeping it available on the internet, scaling it when people use it, and shutting it down when it is idle.
The basic setup has the following steps:
Create a Google Cloud account and enable billing. Billing means adding a payment method so the project can use Google Cloud services beyond the free tier or free credits.
Create a new Google Cloud project. A project is the workspace where the app, settings, permissions, billing, and Cloud Run service are grouped.
Open Cloud Run inside the project. This is where the Shiny app will be deployed once it has been packaged with Docker.
Choose the option to deploy from source or connect a repository. This allows Cloud Run to use a GitHub repository as the source for the app.
Select the GitHub repository, branch, and Dockerfile, then choose the basic Cloud Run settings such as region, memory, CPU, and maximum instances.
Maximum instances sets the highest number of running copies Cloud Run can create for the app. For a small Shiny app, keeping this number low at first can help control costs. Minimum instances sets the number of copies that stay running even when nobody is using the app. Setting the minimum to zero keeps costs lower when the app is idle, although the next first user may experience a cold start —delay— while Cloud Run starts the app again.
Cloud Run can be cheap for small apps, but costs depend on traffic, memory, CPU, build time, logs, and any storage services used by the app. During setup, Cloud Run will also ask whether the service should allow unauthenticated access. Enable this if the app should be accessible without a Google login.
Connecting Google Cloud to GitHub is the easiest way to deploy and maintain the app through the browser. Cloud Run can create a build trigger linked to the selected branch, usually main. When changes are pushed to that branch, Google Cloud can rebuild the Docker image and redeploy the Cloud Run service.
This workflow can be done with terminal commands, but it can also be completed through the Google Cloud Console and the GitHub interface. The screencast below shows the point-and-click version.
You can find the example repository here and live app (hosted on Cloud Run) here.
Is Cloud Run for You?
Cloud Run adds an extra layer to a Shiny workflow. The app has to be packaged with Docker, connected to a Google Cloud project, and deployed through Cloud Run.
The tradeoff is control. With Cloud Run, you can define memory and CPU settings, inspect logs, keep track of revisions, connect the app to other Google Cloud services, and manage how the app scales when more users arrive.
This is overkill for small projects, quick prototypes, or dashboards with limited traffic. However, for a complex dashboard that will be shared publicly, updated over time, or integrated with a larger project website, Cloud Run shines.