Develop & Dockerize ML Microservices using FastAPI + Docker

Step by Step guide to develop and dockerize REST endpoint using FastAPI & Docker

ronilpatil
4 min readFeb 20, 2024

Repository

Overview

In this blog, we’ll explore the process of building machine learning microservices using FastAPI, combining the power of machine learning models with the simplicity and speed of FastAPI’s development workflow. Here I won’t go into detail, I’ll just give a basic understanding of “How can we create a simple API for our machine learning models?”

Create an API

Just initiate a FastAPI and OAuth2PasswordBearer class, which will help us to implement an authentication feature for our API.

Then I used the Pydantic module which is a data validation and settings management library. It is most commonly used with frameworks like FastAPI, it ensures that the data that the Python application receives is in the correct format, meets certain validation criteria, and has features like automatic data conversion and serialization & deserialization.

At #22, the class WineqIp is the Pydantic model, where each attribute represents a feature of wine quality such as acidity, sugar content, sulfur dioxide, etc. along with their acceptable range of values specified using the Field class.

Here’s a brief description of each attribute:

  • fixed_acidity: Represents the fixed acidity of the wine, with an acceptable range between 4.1 and 16.4.
  • volatile_acidity: Represents the volatile acidity of the wine, with an acceptable range between 0.5 and 1.98.
  • citric_acid: Represents the citric acid content of the wine, with an acceptable range between 0 and 1.5.
  • residual_sugar: Represents the residual sugar content of the wine, with an acceptable range between 0.5 and 16.
  • chlorides: Represents the chloride content of the wine, with an acceptable range between 0.008 and 0.7.
  • free_sulfur_dioxide: Represents the free sulfur dioxide content of the wine, with an acceptable range between 0.7 and 70.
  • total_sulfur_dioxide: Represents the total sulfur dioxide content of the wine, with an acceptable range between 5 and 290.
  • density: Represents the density of the wine, with an acceptable range between 0.85 and 1.5.
  • pH: Represents the pH level of the wine, with an acceptable range between 2.6 and 4.5.
  • sulphates: Represents the sulphate content of the wine, with an acceptable range between 0.2 and 2.5.
  • alcohol: Represents the alcohol content of the wine, with an acceptable range between 8 and 15.

See, by defining these attributes with Pydantic’s Field class, we’re enforcing data validation rules that ensure the incoming data adheres to the specified constraints, making it easier to handle and process the data effectively.

At #35, you’ll notice I perform some feature engineering. The same feature engineering I performed during model training hence I brought it here.

At #58, I defined a FastAPI endpoint that handles POST requests at the /predict route. In the FastAPI decorator, I defined an HTTP POST endpoint at the /predict URL path. That dependencies parameter specifies that the endpoint depends on the api_key_auth function for authentication. This means that before executing the endpoint function predict_wineq, FastAPI will first execute the api_key_auth function to authenticate the user's API key.

Once the user is authenticated, feature engineering will be performed, data will get fed into the ML model, and finally return the prediction. At the end, I added the small condition that would only provide a prediction in cases when our model’s confidence level would be above 70%.

The full codebase is available on GitHub.

Create client-side endpoint

Dockerize the Container

Docker makes it easy to package up the software and everything our application relies on, like code files, libraries, runtime env, configuration settings, and other dependencies into small containers. These containers are platform-neutral, they simplify the development, testing, and deployment of programs while ensuring consistent performance across platforms.

Steps to initialize a container :
Initialise the docker using docker init cmd & answer a few basic questions, that's it!
— Create a docker image using docker build -t img_name:version . cmd. You can give any name to an image and maintain a version that helps to track the updates.
— Now create a docker container using docker run -d -p 8081:5002 -ti --name container_name img_name:verison cmd.

Note :
Before creating or working with Docker containers, ensure the Docker engine is up & running on your system.
-p 8081:5002 - This option specifies that port 8081 on the host machine should be mapped to port 5002 inside the container. It allows traffic coming to port 8081 on the host to be forwarded to port 5002 inside the container. This is typically used when we want to access a service running inside the container from the host machine or from other machines on the network.
-d - This option runs the container in the background (detached mode), allowing us to continue using the terminal for other commands. Without this option, the container runs in the foreground, and we’ll see its output in the terminal.

Dockerfile

Added required comments for better understanding.

Now open the Docker Engine, go to your container, and click on Logs , your API will be in the up & running stage. Added the snapshot below for your reference.

Image by Author

Conclusion 🤔

That’s it guy’s, let’s wrap up our exploration of building and dockerizing the microservices using FastAPI & Docker, knowing that the journey of learning never ends. If this blog has sparked your curiosity or ignited new ideas, follow me on Medium, GitHub & connect on LinkedIn, and let’s keep the curiosity alive.

Your questions, feedback, and perspectives are not just welcomed but celebrated. Feel free to reach out with any queries or share your thoughts.

Thank you🙌

--

--