Streamlit is a great tool to create beautiful data applications quite easily but when it comes to deploying them and making them accessible, it can be more complicated for non-specialists. In this article we aim at presenting our journey to deploying our application on GCP ensuring a restricted access to specific people. We implemented two solutions: one with Cloud Run, the other with App Engine and we chose to keep App Engine for its ease of securing the application with IAP (Identity-Aware Proxy).
In this article, we will take the example of the Text Data Explorer, a Streamlit application that we have developed aiming to provide insights on raw text data in few minutes and few clicks. This application will be presented in a future article.
There are two main options to launch this application and this process:
- Either the user clones the GitHub repository on his computer, installs all the dependencies and launches the application on a local environment.
- Or the user has direct access to the application using a dedicated URL without any prior installation.
In order to make the application available to the largest number of people within our company, and therefore people who are not necessarily used to dealing with GitHub, we have decided to deploy the application on GCP (Google Cloud Platform) and make it accessible via a single URL in a secure environment.
Step-by-step deployment on GCP
Two different approaches have been tested to deploy the application on GCP:
- Using Cloud Run
- Using App Engine
However, there is a preliminary common step that concerns both of these approaches which consists in the “dockerization” of our application.
Dockerizing the application
If you are not familiar with Docker, here is a small introduction but do not hesitate to check out the documentation or more specific articles for further details.
What is docker?
Docker is an open platform for developing, shipping, and running applications. It allows you to package an application with all of its dependencies into a standardized unit for software development. In practice, this involves building what is called a Docker image, i.e. the blueprints of the application which form the basis of Docker containers, the content at rest. In order to build this image, we need to define a Dockerfile, i.e. a simple text-file that contains a list of commands that the Docker client calls while creating an image. Once built, the image is stored in a registry (e.g. Container Registry on GCP) and can be deployed on a dedicated instance, via Cloud Run or App Engine for example.
Therefore in our case we have to:
- Create a Dockerfile
- Build our application image
- Store the image on a registry
Let’s start with the creation of the Dockerfile. As mentioned before, this consists in a succession of commands used to create the Docker image. In the case of a Streamlit application, the Dockerfile can be divided into several blocks:
- Define the runtime environment: in our case python 3.7
- Define the port on which the application will run
- Install the needed libraries and their dependencies using a requirements.txt file
- Copy the code of your application and define the working directory from where the application will be launched
- Define the command to run the application
Our code is organized in the following way:
├── app.py <- Main script to launch the Streamlit app
├── text_explorer <- Folder gathering all the functions and code
├── requirements.txt <- File listing needed libraries to install
└── references <- Folder containing logos and images
With this structure, here is an example of the Dockerfile we used for our application:
Once the Dockerfile is created, we can build our image, following a GCP-friendly naming convention that will be helpful for the deployment later on. This is done via the following command:
docker build -t eu.gcr.io/gcp_project_name/app_name:v1 .
To adapt it to your own application, replace the ‘gcp_project_name’ by your own GCP project name and the ‘app_name’ by your own application name. You can also update the version number as your application evolves by modifying the ‘v1’ suffix with your current version.
From there, with our application packaged in a docker image, we can deploy it on GCP to make it accessible to our teammates.
Deploy your app with Cloud Run
Cloud Run is a GCP serverless cloud service used to easily deploy pre-built applications. One of its main advantages is that it automates most of the resources management process. Therefore, all you have to do is to tell Cloud Run where your Docker image is, and then Cloud Run will deploy it on a serverless environment without needing to specify the optimal number of resources for example.
In order to do that, you can follow the steps listed below:
- Initialize gcloud module on the right GCP project with the following command:
- Push the docker to the GCP Container Registry with the following command:
docker push eu.gcr.io/gcp_project_name/app_name:v1
- Go on your GCP project, on the Cloud run section. Click on “Create service”, choose the region and define your service name. Then, select the Docker image that corresponds to your Streamlit app and update the port with the one you defined in your Dockerfile
- Finally, you can test your app by following the URL linked to the newly created Cloud Run service
As you can see, the deployment is done in just a few steps and is quite easy, even for newcomers to application deployment. However, in our case, on top of the deployment, we also wanted to secure our application so that it would only be accessible within our company and at that time, we did not find any “easy” solution that would fit with Cloud Run. That is why we decided to look for an alternative solution that would allow us to have this security layer without too much difficulty and we finally ended up with App Engine.
Deploy your app with App Engine
App Engine is a cloud-based computing service used to host web apps that are already in the Google infrastructure. In a nutshell, it allows you to do the same thing as Cloud Run in the sense that they are both Google cloud services that allow you to deploy applications. However, unlike Cloud Run where you only pay for the requests that come in, on App Engine you pay for the entire run time, whether there are requests or not. Thus at the end, App Engine may be a more expensive solution. Despite this, we still decided to go for this solution because App Engine has the advantage of having a native integration with IAP (Identity-Aware Proxy) that allows to easily secure your application.
The steps to achieve a deployment on App Engine are not more numerous nor more complicated than for Cloud Run, here is what you need to do:
- Check the port specified in your Dockefile, it has to be 8080 to be compatible with App Engine
- Initialize gcloud module on the right GCP project with the following command:
- Create a YAML file for your app (named app.yaml) at the root of your project (i.e. at the same level as your main script and your Dockerfile) with the following template:
Update the service name with your own application service name
Here we defined the runtime: custom option because custom runtimes let you build apps that run in an environment defined by a Dockerfile as it is the case for us. The env:flex option means that our application will be run in the flexible environment (by opposition to the standard environment). This choice was made because the flexible environment runs the application in Docker containers on Google Compute Engine virtual machines (VMs), which have fewer restrictions than in the standard environment (e.g. your app cannot write to disk). More details about the key differences are available in the Google documentation.
You can also include more detailed network, resources and scaling settings within the YAML file such as the minimum number of instances given to your service or the number of CPUs for example. You can also define some environment variables in that file to make them accessible to your application.
- Run the following command (this could take several minutes):
gcloud app deploy app.yaml
- Once done with the deploy command, the app will be available on App Engine and you will find its dedicated URL directly on GCP
If you want to secure your app and give a restricted access to some people, go to your GCP project, in the “IAM & Admin” / “Identity-Aware Proxy” section:
- In “All Web Services” you should see an “App Engine app” section. If IAP is off, turn it on and click on your Streamlit service.
- On the right, click on “Add member”, enter all the email addresses you want (or an alias linked to a mailing list) and select the “IAP-secured Web App User” role.
And you’re done. Your application is now deployed and secured.
Tips if you have trouble with images display in your deployed app
When using st.pyplot() or st.image(), you may encounter some display troubles when looking at your deployed application (i.e. “0” displayed instead of your plot or image). We recommend to use st.plotly_chart() whenever you can to avoid that and to use HTML code snippets otherwise. For example, in our case, we wanted to display some wordclouds and that could not be done with Plotly. Thus we decided to save the wordcloud image as PNG in a dedicated GCS bucket, download it as bytes and display it with some HTML code like this:
In that example, the variable “image” is a bytes object coming from the method .dowload_as_bytes() of Google cloud storage python package.
The purpose of this article was to give you some tips and examples of cloud services that can be used for deploying Streamlit applications. In our experience, if you need a security layer to ensure restricted access to some people, App Engine will be the appropriate solution. Otherwise, Cloud Run remains an easy way to deploy a Streamlit application.
Thanks a lot for reading up to now, do not hesitate to reach out if you have any questions. You can find more about our projects by visiting our blog.
Credits: Paul Devienne, Amale El Hamri