Building and Deploying a Machine Learning-Powered Air Passenger Prediction App to Azure App Service
Introduction
As a machine learning enthusiast, I recently worked on deploying a machine learning model as a web application. The goal was simple: take a trained model and serve predictions via a FastAPI-based backend hosted on Azure App Service using a Dockerized container. While the task sounds straightforward, it came with its fair share of challenges, which I’ll share in this post.
This article will walk you through my journey step-by-step, including setting up the app locally, containerizing it, deploying to Azure, and debugging some unexpected roadblocks along the way.
What We’ll Cover
1. Preparing the application locally.
2. Building and pushing the Docker image.
3. Deploying the app to Azure App Service.
4. Testing the app.
5. Challenges I faced and how I resolved them.
Step 1: Preparing the Application Locally
Setting Up the App
I built the application using FastAPI, a Python-based web framework, to expose a machine-learning model. Below is the core structure of my app.py file:
from fastapi import FastAPI
from pydantic import BaseModel
import joblib
import pandas as pd
# Define the input schema using Pydantic
class PredictionRequest(BaseModel):
DISTANCE: float
TOTAL_CARGO: float
CARRIER_GROUP_NEW: int
UNIQUE_CARRIER_encoded: int
Org_Dest_Country_FE: float
MONTH_SIN: float
MONTH_COS: float
CLASS_F: int
CLASS_G: int
CLASS_L: int
CLASS_P: int
REGION_A: int
REGION_D: int
REGION_I: int
REGION_L: int
REGION_P: int
REGION_S: int
IS_PEAK_SEASON: int
app = FastAPI()
# Load the trained model
model = joblib.load('best_model.pkl')
@app.get("/")
async def health_check():
return {"message": "Passenger Prediction App is running!"}
@app.post("/predict")
async def predict(request: PredictionRequest):
input_data = pd.DataFrame([request.dict()])
prediction = model.predict(input_data)
return {"prediction": prediction.tolist()}
Testing the App Locally
Before deployment, I tested the app on my local machine using Uvicorn, a lightning-fast ASGI server.
uvicorn app:app --reload --host 0.0.0.0 --port 8000
I then sent test requests using Python’s requests library:
import requests
url = "http://localhost:8000/predict"
payload = {
"DISTANCE": 500000.0,
"TOTAL_CARGO": 200000.0,
"CARRIER_GROUP_NEW": 1,
"UNIQUE_CARRIER_encoded": 15,
"Org_Dest_Country_FE": 0.75,
"MONTH_SIN": 0.5,
"MONTH_COS": 0.866,
"CLASS_F": 0,
"CLASS_G": 1,
"CLASS_L": 0,
"CLASS_P": 0,
"REGION_A": 1,
"REGION_D": 0,
"REGION_I": 0,
"REGION_L": 0,
"REGION_P": 0,
"REGION_S": 0,
"IS_PEAK_SEASON": 1
}
response = requests.post(url, json=payload)
print("Prediction:", response.json())
Step 2: Building the Docker Image
To containerize the app, I created a Dockerfile:
FROM python:3.9-slim
# Set working directory
WORKDIR /app
# Copy files
COPY . /app
# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Expose the app port
EXPOSE 8000
# Start the FastAPI app
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Building the Image:
docker buildx build --platform linux/amd64 -t passengerprediction.azurecr.io/passenger_prediction:v1 .
Pushing the Image to Azure Container Registry:
docker push passengerprediction.azurecr.io/passenger_prediction:v1
Step 3: Deploying to Azure App Service
Set Up the Azure App
- Log in to Azure CLI:
az login
2. Create an App Service plan:
az appservice plan create \
--name passenger_prediction_service \
--resource-group passenger_prediction \
--sku F1 --is-linux
3. Create the web app:
az webapp create \
--name passenger-prediction-app \
--resource-group passenger_prediction \
--plan passenger_prediction_service \
--deployment-container-image-name passengerprediction.azurecr.io/passenger_prediction:v1
4. Configure the container registry:
az webapp config container set \
--name passenger-prediction-app \
--resource-group passenger_prediction \
--container-image-name passengerprediction.azurecr.io/passenger_prediction:v1 \
--container-registry-url https://passengerprediction.azurecr.io \
--container-registry-user passengerprediction \
--container-registry-password <acr-password>
Step 4: Testing the Deployed App
After deployment, I tested the app using curl:
curl -X POST https://passenger-prediction-app.azurewebsites.net/predict \
-H "Content-Type: application/json" \
-d '{
"DISTANCE": 500000.0,
"TOTAL_CARGO": 200000.0,
"CARRIER_GROUP_NEW": 1,
"UNIQUE_CARRIER_encoded": 15,
"Org_Dest_Country_FE": 0.75,
"MONTH_SIN": 0.5,
"MONTH_COS": 0.866,
"CLASS_F": 0,
"CLASS_G": 1,
"CLASS_L": 0,
"CLASS_P": 0,
"REGION_A": 1,
"REGION_D": 0,
"REGION_I": 0,
"REGION_L": 0,
"REGION_P": 0,
"REGION_S": 0,
"IS_PEAK_SEASON": 1
}'
Challenges Faced
1. Mismatch in Environment Versions:
The Python version and library versions in the local environment were different from those in Azure. Updating the Dockerfile to use the same versions as my local environment fixed this issue.
2. Unauthorized Access to Azure Container Registry:
Initially, the app couldn’t pull the image from Azure Container Registry due to authentication issues. Enabling admin access and providing the registry credentials resolved this:
az acr credential show --name passengerprediction
3. Model Compatibility:
A ValueError occurred when loading the model due to incompatible library versions. Updating scikit-learn and joblib to match the versions used during training resolved this.
Conclusion
Deploying this app taught me the importance of aligning local and deployment environments. Azure App Service proved to be a robust hosting solution, and containerization simplified the deployment process. While there were challenges, the result — a fully functional machine learning-powered web app — was well worth the effort.
If you’re working on a similar project, I hope this guide helps streamline your journey. Feel free to reach out with any questions or suggestions!