This is part 1 of a 3 part series. Make sure to read through part 2 and part 3 next!
In this tutorial, we will be assuming the following: * You have a working Streamlit app ready to deploy - If you don’t, no worries! The streamlit docs have some great tutorials, but if you’d rather jump right in, you can go ahead and git clone
my small example here. * You have Docker installed * You have a working knowledge of the command line
Streamlit is the framework featured in this post as it is designed for data scientists and machine learning engineers to quickly elevate their analysis from their laptops to deployment. Building useful, aesthetically-pleasing web applications is a difficult thing to do and Streamlit has taken great strides in enabling analysts with little web development experience to “create beautiful data apps in hours, not weeks.” Additionally, Docker is a great tool for maintaining reproducible work and portability of your compute environment — two essential skills for professional data scientists. If you’re looking to read more on this topic, Hamel Husain’s article provides a compelling explanation for why the use of Docker fosters more effective data scientists.
Containerizing a Streamlit web app with Docker
So let’s say that you’ve got your streamlit web app prepared in a directory that looks like this:
├── app.py # streamlit code
├── content.py # textual content - imported into app
├── images # various images for your app
│ ├── logo.png
│ ├── background.png
├── requirements.txt # libraries used by your app
In order to containerize this application with Docker, the first step will be to add a Dockerfile
to the root of your directory. Your Dockerfile
acts as a set of instructions (more specifically, a set of commands that could equivalently be called from the command line) from which Docker will build an image for your app. The image is built by running each line in the Dockerfile
sequentially. Using this image, Docker will then create a container. If this is all new, I’d recommend taking a look at this Docker overview!
The Dockerfile
The Dockerfile
for my small example looks like this:
# base image
# a little overkill but need it to install dot cli for dtreeviz
FROM ubuntu:18.04
# ubuntu installing - python, pip, graphviz
RUN apt-get update &&\
apt-get install python3.7 -y &&\
apt-get install python3-pip -y &&\
apt-get install graphviz -y
# exposing default port for streamlit
EXPOSE 8501
# making directory of app
WORKDIR /streamlit-docker
# copy over requirements
COPY requirements.txt ./requirements.txt
# install pip then packages
RUN pip3 install -r requirements.txt
# copying all files over
COPY . .
# cmd to launch app when container is run
CMD streamlit run app.py
# streamlit-specific commands for config
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
RUN mkdir -p /root/.streamlit
RUN bash -c 'echo -e "\
[general]\n\
email = \"\"\n\
" > /root/.streamlit/credentials.toml'
RUN bash -c 'echo -e "\
[server]\n\
enableCORS = false\n\
" > /root/.streamlit/config.toml'
It is worth mentioning that building off the ubuntu
base image may be a little bit overkill for the scale of this small web app, however, I found it necessary to get a nice rendering of an svg file generated by the dtreeviz
package. This is also a great example of a simpler Dockerfile
on this blog. There is a lot to unpack here, so I’ll do so line by line.
Ubuntu commands
At the top, we build off the base ubuntu
image with the following line:
FROM ubuntu:18.04
This means that Docker pulls the ubuntu:18.04
image from DockerHub to begin with.
Next, we update and install a few things we’ll need for our web app.
RUN apt-get update &&\
apt-get install python3.7 -y &&\
apt-get install python3-pip -y &&\
apt-get install graphviz -y
Setting up the app
After that, we set up our app within the image. Since streamlit’s default port is 8501
, we open up that port.
EXPOSE 8501
From there, we (optionally) define a working directory within the image and copy over all of our files, then install the necessary python libraries (as defined in our requirements.txt
)
WORKDIR /streamlit-docker
COPY requirements.txt ./requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
{% include info.html text=“It is typically not recommended to copy all files to the image the way we’ve done above (particularly if you have large files). However, since this is a small example, it won’t cause any issues for us.” %}
Streamlit-specific commands
Finally, we must include a few commands to ensure that streamlist runs as expected. We define a command to launch our web app whenever our docker container gets launched,
CMD streamlit run app.py
and we finish by including a few commands to configure streamlit correctly.
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
RUN mkdir -p /root/.streamlit
RUN bash -c 'echo -e "\
[general]\n\
email = \"\"\n\
" > /root/.streamlit/credentials.toml'
RUN bash -c 'echo -e "\
[server]\n\
enableCORS = false\n\
" > /root/.streamlit/config.toml'
Building the docker image and running the container
Now that we have our web app and our Dockerfile
all set up, we’re ready to build the image. We can do so with a single command.
docker image build -t streamlit:app .
{% include info.html text=“Note: you must run this command from the same directory as your Dockerfile” %}
where -t
tags our image as streamlit:app
and .
references the directory with the Dockerfile. When you run this from the command line, you will see Docker moving through each step defined in the Dockerfile
and installing many packages to the image. Once it is finished (it may take a few minutes the first time), you should see a verification like Successfully tagged streamlit:app
, letting you know that the Docker image was successfully created. You can further verify that the image was created correctly by running docker image ls
, where you should see something like
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
streamlit app ecda3493de33 50 seconds ago 1.52GB
At this point, our image has been successfully built and we are ready to run it by way of container! (If the differences between an image and container are confusing, this short post provides some helpful distinctions). One command will do the trick,
$ docker container run -p 8501:8501 -d streamlit:app
where -p
allows you to publish a container’s port to the host’s port and -d
allows you to run it in the background. You can then verify that is is running with a command like this,
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
82ecab4abfb1 streamlit:app "/bin/sh -c 'streaml…" 22 seconds ago Up 21 seconds 0.0.0.0:8501->8501/tcp weird_name
Better yet, pop open a web browser and you can view your web app, running in a docker container, at http://localhost:8501/
. If you’re using my example, it should look something like this!
Now, checkout out part 2 to learn how to move this app off of your laptop and into the cloud!