DEV Community

Cover image for OpenTelemetry in Action on Kubernetes: Part 1 - Building a Simple ML App with FastAPI
Kartik Dudeja
Kartik Dudeja

Posted on • Edited on

OpenTelemetry in Action on Kubernetes: Part 1 - Building a Simple ML App with FastAPI

Introduction to the Series

Welcome to “The Observability Blueprint: Instrument, Deploy, Observe — OpenTelemetry in Action on Kubernetes” – where we take a humble machine learning application and give it superpowers: observability across metrics, logs, and traces using open-source tools like OpenTelemetry, Prometheus, Jaeger, Loki, and Grafana.

In this blog series, we’ll:

  • Build a simple ML app using FastAPI
  • Instrument it using OpenTelemetry
  • Containerize it with Docker
  • Deploy it to Kubernetes
  • Collect and visualize observability data like a pro

Goal: show how to fully observe a production-ish ML app from every angle using only open-source tools.

OTel-k8s


Part 1: Building a Simple ML App with FastAPI

Prerequisites:
Before we start, make sure you have:

  • Python 3.8+
  • pip
  • Basic familiarity with Python and REST APIs (we promise to keep it friendly)

Step 0: Set Up a Virtual Environment
Let’s avoid polluting your global Python setup. Run the following:

python3 -m venv venv
source venv/bin/activate    # On Windows: venv\Scripts\activate
pip3 install --upgrade pip
Enter fullscreen mode Exit fullscreen mode

Create a requirements.txt:

fastapi==0.110.0
pydantic==1.10.14
uvicorn==0.29.0
scikit-learn==1.4.2
numpy==1.26.4
Enter fullscreen mode Exit fullscreen mode

Then Install:

pip3 install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Step 1: What’s Machine Learning? And Why Linear Regression?
Machine Learning is the art (and science) of teaching computers to learn patterns from data instead of writing rule-based code.

In this part, we’ll use Linear Regression, the "hello world" of ML models. It assumes there’s a straight-line relationship between input and output — in our case, the bigger the house, the higher the price. (Groundbreaking stuff, we know.)

linear-regression

Here’s the model training code:

# train_model.py

import numpy as np
import pickle
from sklearn.linear_model import LinearRegression

# Sample dataset: house sizes in sq ft and corresponding prices in dollars
# Data: [size (sq ft)], [price ($)]
X = np.array([[500], [1000], [1500], [2000], [2500]])
y = np.array([100000, 150000, 200000, 250000, 300000])

# Train the model
model = LinearRegression()
model.fit(X, y)

# Save the model to a file
with open("house_price_model.pkl", "wb") as f:
    pickle.dump(model, f)

print("Model trained and saved as 'house_price_model.pkl'")
Enter fullscreen mode Exit fullscreen mode

This generates a .pkl file — a serialized version of our model we’ll later load inside an Application.

Step 2: Serve It via FastAPI
Let’s make it accessible to the outside world.

Why FastAPI?

FastAPI is a modern Python web framework built for speed (thanks to Starlette & Pydantic), great dev experience, and automatic documentation. It’s a joy to use — kind of like Flask, but with type hints and Swagger included.

Let’s write our app:

# app.py

from fastapi import FastAPI, Request
from pydantic import BaseModel
import pickle
import numpy as np

# --------------------------
# FastAPI App Setup
# --------------------------
app = FastAPI()

# Load the model
with open("house_price_model.pkl", "rb") as f:
    model = pickle.load(f)

# --------------------------
# Healthcheck endpoint
# --------------------------
@app.get("/")
def read_root(request: Request):
        return {"message": "House Price Prediction API is live!"}

# --------------------------
# Define the request schema
# --------------------------
class HouseFeatures(BaseModel):
    features: list[float]

# --------------------------
# Prediction endpoint
# --------------------------
@app.post("/predict/")
def predict(data: HouseFeatures, request: Request):
        prediction = model.predict(np.array(data.features).reshape(1, -1))
        logger.info(f"Prediction made: {prediction[0]}")
        return {"predicted_price": prediction[0]}
Enter fullscreen mode Exit fullscreen mode

Run it with:

uvicorn app:app --reload
Enter fullscreen mode Exit fullscreen mode

Try It Out

curl -i 'http://127.0.0.1:8000/'
Enter fullscreen mode Exit fullscreen mode

POST to /predict/ with:

curl -i -X POST 'http://127.0.0.1:8000/predict/' -H "Content-Type: application/json" -d '{"features": [1500]}'
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "predicted_price": 200000.0
}
Enter fullscreen mode Exit fullscreen mode

Congratulations, you just served your first ML model!


What’s Next?

In Part 2, we’ll dockerize the app so it's ready for deployment in the wild. We’ll also start thinking about instrumenting the app — because what’s an API without observability metrics to brag about?


{
    "author"   :  "Kartik Dudeja",
    "email"    :  "kartikdudeja21@gmail.com",
    "linkedin" :  "https://linkedin.com/in/kartik-dudeja",
    "github"   :  "https://github.com/Kartikdudeja"
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)