How to Host Shiny Apps on the DigitalOcean App Platform
DigitalOcean announced the App Platform a year ago as the platform-as-a-service(PaaS) offering that automates infrastructure management. Developers can deploy their code to production in just a few clicks.
The App Platform can publish applications from your GitHub, GitLab or public Git repositories, or publish a container image you have already uploaded to a Docker registry. The platform supports GitOps (git push-based deployment), and vertical and horizontal scaling.
In spirit and most practical aspects, the platform is very similar to Heroku. You can use Buildpacks or Dockerfiles to build applications. There is no native Buildpack for R. But as we saw before, Shiny apps can be containerized. This gives us a way to deploy to the App Platform seamlessly.
This post focuses on how to deploy a Shiny app from an existing Docker image to the App Platform. This is a fully no-code experience because we already built and pushed the image. You will use the r-minimal
Alpine Linux-based COVID19 app that we build before.
Prerequisites
Visit the App Platform landing page and sign up for a DigitalOcean account:
Once have an account, log in and go to your dashboard. In the left drawer, click on 'Apps':
Launch your Shiny app from the dashboard
Deploy
Click on the 'Launch Your App' button:
The next screen will present your options. Select Docker Hub:
Next, type in the repository name (analythium/covidapp-shiny
) and the tag (minimal
), then click 'Next':
On the next screen, leave the Type as Web Services
, set the Run command to the CMD
command of the Dockerfile that you are deploying (without the square brackets), and change the port to the one exposed by Docker (3838):
On the next screen, you can edit the app's name your data region:
The last step is to select the plan. Non-static apps require a paid plan ($5 US/month and above):
This is where you can set the number of replicates (horizontal scaling). Finally, click the 'Launch' button:
Check the deployment
After a few seconds, you'll see the app deployed on a subdomain: app-name-hash.ondigitalocean.app
:
Visit the link to check the app:
Look around in the dashboard to inspect the deployment and runtime logs. You can even access the container through the console. Under the insights tab, you can check CPU and memory consumption:
Add a custom domain
You can add a custom domain using a CNAME record with your DNS provider. Go to your app's settings tab, find the 'Add Domain' button:
Follow the prompts and copy the app's current URL:
Go to your DNS provider (Google Domains shown here) and add a CNAME record, and save:
After some time the custom domain is live and listed under settings:
Visit the new link, note that it is served over secure HTTPS protocol:
Update the app image
You can edit the source image tag in your app's settings. Once the new version is tagged and pushed to the Docker registry, just edit the tag and the app will be redeployed to the App Platform.
Programmatic image deployment
Of course, you can use the doctl
command-line tool and a YAML-based app specification file format for deployment. You can find the app specification in the control panel, look under the Settings tab:
Most of the info in the spec file is self-explanatory and relates to all the settings we made manually. Let's grab the YAML file and use it as a starter.
To use the app spec from the command line you have to install the doctl
command-line tool and follow the steps described in the article to use the API token to grant doctl
access to your DigitalOcean account.
Deploy an app
We'll make some changes to the app specs and deploy a different app, the one that visualizes the correlation between 2 variables. This will use the analythium/correlation:v1
Docker image. Create an empty file called shiny-app.yml
and add the following content to it:
alerts:
- rule: DEPLOYMENT_FAILED
- rule: DOMAIN_FAILED
name: analythium-correlation-shiny
region: nyc
services:
- http_port: 3838
image:
registry: analythium
registry_type: DOCKER_HUB
repository: correlation
tag: v1
instance_count: 1
instance_size_slug: basic-xxs
name: shiny-app
routes:
- path: /
run_command: R -e "shiny::runApp('/home/app',port=3838,host='0.0.0.0')"
source_dir: /
Let's use some doctl apps
commands now (these are the commands specific to the App Platform). First, we validate the YAML specification:
doctl apps spec validate shiny-app.yml
We either get an error message or the file content. Once the app spec passed inspection, we can use it to create an app:
doctl apps create --spec shiny-app.yml
We'll see the newly created app info. Take note of the ID
. You can get the ID
later using the doctl apps list
command to list all the apps. This will give the ID
, and the Default Ingress, which is the assigned subdomain (https://analythium-correlation-shiny-vil3a.ondigitalocean.app in this case). If the ingress field is empty, it means the deployment is in progress or it has failed.
Use the app ID to see the deployment and runtime logs (edit the APP_ID
value according to your console output):
export APP_ID="5c187c9a-5d1a-4988-8848-82905d0f0302"
doctl apps logs $APP_ID --type deploy
doctl apps logs $APP_ID --type run
If all went well, you should see the app after visiting the ingress URL:
Update the app
You can change the YAML spec file, e.g. change the services.image.tag
property to tag: v2
and save the file. Then run the following command:
doctl apps update $APP_ID --spec shiny-app.yml
This will update the app in a few minutes:
Delete the apps
Once you are done playing with the new deployment and you don't need it anymore, just click the 'Actions' button, select 'Destroy' from the drop-down menu. Or use the app ID and doctl apps delete $APP_ID
to get rid of the apps. Also, remove the CNAME record from your DNS if you have set up a custom domain.
Conclusions
The DigitalOcean App Platform makes it straightforward to deploy Shiny apps without ever opening your terminal. But if you prefer, the command-line option only needs a YAML file and a single command.
Docker once again proved to be a really useful piece of technology. We saw how immutable container images can be moved around the internet without issues. We'll cover the GitHub and App Platform integration in some of the next posts.