Skip to content

ShinyProxy in a Container

Why?

ShinyProxy uses containers to achieve scalability and security when launching multiple Shiny apps for multiple users. Each user runs a Shiny app in an isolated container, and there is no risk of apps interfering with each other, or users getting hold of other users' data.

From an infrastructure point of view, there are also great advantages to be gained. Containers are much easier to manage and scale than a series of system processes or services.

So if ShinyProxy uses containers to run Shiny apps, why not run ShinyProxy itself in a container? This would offer several additional advantages:

  • No need to install a Java runtime on the host. The docker image will take care of that.

  • Many container managers can be set up to automatically restart crashed containers. If the ShinyProxy container crashes, it can recover without requiring manual intervention.

  • It becomes much easier to deploy multiple ShinyProxy containers, and many clustered container managers (such as Kubernetes) allow you to deploy load balancers in front of those containers.

  • If you have multiple ShinyProxy containers and want to put a new configuration online, you can perform a 'rolling update' without causing any downtime for your users.

Configuration

To run ShinyProxy in a container, several steps must be taken:

  1. A docker image must be built, containing ShinyProxy, an application.yml configuration file, and a Java runtime. An example for this can be found here.

  2. Since ShinyProxy is now listening on a container address and port, an additional mapping must be made to ensure that ShinyProxy is also accessible on an external interface. This is done differently for different container managers:

  3. For docker, the port must be published, which means the host will allocate a port that forwards traffic to the container port.

  4. For docker swarm, you can define a service that publishes a port on the ingress overlay network to make it accessible from any node.

  5. For Kubernetes, the port can also be published via a service that automatically allocates the port on all nodes and takes care of routing the traffic to the appropriate pod.

  6. If ShinyProxy is running inside the same container manager as the Shiny containers it launches, it also becomes easier to communicate with those containers:

  7. It is no longer necessary for each Shiny container to publish a port on the host using port-range-start: simply exposing the Shiny port (3838) on the container is enough.

  8. Instead of constructing a URL from the docker hostname, ShinyProxy can now use the container ID to access it.

For this to work, a setting must be enabled in the application.yml file: shiny.proxy.docker.internal-networking: true or shiny.proxy.kubernetes.internal-networking: true.

Examples

The shinyproxy-config-examples repository contains several examples on how to set up a 'containerized' ShinyProxy.