A Code Walk Through to Deploying a Container on Heroku Platform
A machine learning model is intended to solve a real-world problem and the solution as a service must reach the consumer who can use it easily. This is the essence of putting your model into production. As such, the model deployment becomes an integral part of the ML life cycle. In this article, we shall walk through a model deployment process to deploy a container containing a simple flask app on the cloud platform Heroku. I have attempted to keep the process simple so as provide a fundamental understanding of the sequence involved.
The scope of the article is broadly categorized into ;
- Develop a simple API using Flask microframework for python
- Containerize the API into a microservice using Docker
- Deploy the container into cloud viz, Heroku
Develop a Flask App
Flask is a web framework for python. A web framework is a collection of libraries and modules that enables web application developers to write applications without worrying about low-level intricacies such as protocol, thread management etc. Often flask is preferred because it is very pythonic and has an easy learning curve.
To get started with the project, it is good to choose a working environment to develop your project. Visual Studio Code provides an excellent platform to meaningfully interact and develop the application. There are many alternatives and feel free to choose one that you are comfortable with. It is a good practice to develop our application in a virtual environment. Say we are concurrently working on two projects, one requiring TensorFlow v1.5 and another requiring TensorFlow v2.0. The virtual environment provides us with a tool to keep the project and its dependencies isolated from each other. It is recommended that Virtual Environment should be used whenever you work on any Python-based project. virtualenv, pipenv , poetry, etc are some of the popular tools for creating a virtual environment. To get started I have used WSL(windows subsystem for Linux) with ubuntu 18.04 as my environment for the project. I found the Linux environment in WSL a good and easy interface to develop the intended application. Following code will get a virtual environment for our project going,
$ pip install virtualenv
$ mkdir demo
$ virtualenv demo
$ source activate demo/bin/activate
$ which python
The above code creates a virtual environment called demo and command which python shows we are using python from the virtual environment. (it will show current directory plus /demo/bin/python). To deactivate the env type deactivate We can write our simple flask app now and call it main.py.
The code main.py imports the Flask object from the Flask package and creates an instance of the Flask application called app and passes variable (__name__) to it. The @app.route(‘/) is a python decorator which turns the python function into a view function that converts the function return value to HTTP response which can be displayed by a web browser. “/” indicates the function will respond at the main URL. Our index function returns a string “Hello World”. By default, main.py runs on localhost, host= ‘0.0.0.0’ tells to run on all your machine’s IP addresses and port tell the app will run port 5000 of the machine. Let’s run this app on the local machine,
$ pip install flask $ python3 main.py
we see an output that looks like this.
we can see the output of main.py by going to the browser and typing the IP address shown or using the command $ curl localhost:5000 on terminal
Our app seems running on the local machine. The terminal threw a warning “WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. “. Let’s understand what this means…
In a nutshell, if we want to get our app to production, we should go for a production server like unicorn, waitress etc. As stated in Flask documentation, “While lightweight and easy to use, Flask’s built-in server is not suitable for production as it doesn’t scale well and by default serves only one request at a time.”. We will use gunicorn, the WSGI production server to deploy our app and if you are using windows gunicorn may not work and the waitress is a go-to choice. Use control+C to stop earlier running app and Execute following commands on the terminal,
$ pip install gunicorn $ gunicorn --bind 0.0.0.0:5000 main:app
This says our app is running and we can check like the way we did before by using browser or the curl command. Great! Let’s move ahead.
Our App in a Heroku Container
Let’s move to containerizing our app. While Docker containers are a subject on their own, I would limit my words to a brief introduction. Docker is one of the sought-after Dev-Ops tools for deploying applications. We can package the container with the application and all its dependencies and ship it without worrying about compatibility issues or machine dependency. Using Docker, the applications can run no matter where they are.
A docker image is like a blueprint to a container. The above diagram depicts our process, we write a Docker file to create a custom image and run our app with the help of a container. Docker was first developed in a Linux environment but subsequently was made available for windows and mac machines. We need WSL2 to use docker on windows and there are numerous resources online to help you download the docker environment for your machine. Assuming we have a docker environment in our machine, let’s move ahead.
$ docker --version
This will tell us docker is correctly installed or not. Prior to building our image and running our container create requirements.txt.
$ pip freeze > requirements.txt
This creates a text file with packages required in the current directory. Make a file with the following content in the current directory and name it Dockerfile,
FROM docker.io/python:3.7 WORKDIR /app COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt COPY . . ENTRYPOINT ["gunicorn",""--bind","0.0.0.0:5000",main:app"]
The file uses a python 3.7 image as a base image for building our application. The commands to be executed are WORKDIR, COPY, RUN create a working directory, copy files and run pip install the packages in requirements.txt. I specifically used gunicorn==19.9.0 in requirements.txt as higher versions were giving errors. In the end, ENTRYPOINT tells us how the container will run, here the will run the app in gunicorn server on localhost at port 5000. Once Dockerfile is ready, we can build and run our container,(be sure you are in the project directory!)
$ docker build -t demo-app .
This should get the image building process going and the following command should show our image,
$ docker images
Run the container in localhost with the following commands in sequence,
$ docker run -dit -p 5000:5000 demo-app
$ docker ps
The above commands should show our container successfully running,
Docker assigns container ID and name(if we did not explicitly name it) and we have mapped container port 5000 to machine port 5000 during run command. Now our container is running and can again be verified by using browser or by curl command.
After successfully running our application on localhost, let’s deploy it on a cloud for others to use it. I have used Heroku to deploy my application. Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud. They also offer a free account to host a couple of applications. So sign for an account and also download Heroku CLI for deployment.
This will confirm Heroku CLI installation. The following sequence of commands will build the container on the Heroku cloud platform.
$ heroku login
This will give a “Logging in… done” message
$ heroku container:login
$ heroku create
This will create an app and Heroku will give a name (if we don’t specify a particular name) and corresponding link for the app. Note this app name for further commands,
$ heroku container:push web --app
This builds the container and pushes it to the cloud and gives a message “Your image has been successfully pushed. You can now release it with the ‘container: release’ command.”
$ heroku container:release web --app
On successful release, a message “Releasing images web to … done” is displayed.
let’s check our application is up and running by visiting the link provided by Heroku …
Voila! Congrats! our app has been deployed on the cloud …
This article was an attempt to walk through the development of a simple flask app and containerize the app in a docker container and finally deploy it on the cloud using the services of the platform Heroku. After deploying a very basic application next logical step, I guess is to scale up the flask application say for the deployment of a machine learning model. To be honest, while building the application I had stumbled upon numerous errors and resources from the online community was instrumental in resolving the errors and deploying the application.
“You don’t learn to walk by following rules. You learn by doing, and by falling over.” ― Richard Branson
About the Author
Subramanian Hariharan is a Marine Engineer with more than 30 years of experience is passionate about leveraging data for Business Solutions.