DEV Community

Cover image for My First MLOps Project: From Model Training to Kubernetes Deployment πŸš€
Aman Nikhare
Aman Nikhare

Posted on

My First MLOps Project: From Model Training to Kubernetes Deployment πŸš€

🎯 Introduction

As someone diving into the world of MLOps and DevOps, I recently completed my first end-to-end machine learning operations project. This project took me through the complete journey of building a diabetes prediction model and deploying it to Kubernetes. Here's what I learned and the best practices I followed along the way!

GitHub Repository: https://github.com/amco-f22/first-mlops-project


πŸ“‹ Project Overview

This project implements a complete MLOps pipeline for a diabetes prediction model using:

  • Machine Learning: Random Forest Classifier on the Pima Indians Diabetes Dataset
  • API Framework: FastAPI for creating REST endpoints
  • Containerization: Docker for packaging the application
  • Orchestration: Kubernetes for deployment and scaling

The model predicts diabetes risk based on five key health metrics: Pregnancies, Glucose levels, Blood Pressure, BMI, and Age.


πŸ—οΈ Project Structure and Best Practices

1. Clean Code Organization

The project follows a simple, modular structure:

first-mlops-project/
β”œβ”€β”€ train.py              # Model training script
β”œβ”€β”€ main.py               # FastAPI application
β”œβ”€β”€ requirements.txt      # Python dependencies
β”œβ”€β”€ Dockerfile           # Container configuration
β”œβ”€β”€ k8s-deploy.yml       # Kubernetes deployment manifest
└── diabetes_model.pkl   # Trained model (generated)
Enter fullscreen mode Exit fullscreen mode

Best Practice: Keeping training and inference code separate makes the codebase maintainable and allows independent updates to each component.


πŸ”¬ Model Training (train.py)

What I Implemented:

# Load dataset from a reliable source
url = "https://raw.githubusercontent.com/plotly/datasets/master/diabetes.csv"
df = pd.read_csv(url)

# Feature selection
X = df[["Pregnancies", "Glucose", "BloodPressure", "BMI", "Age"]]
y = df["Outcome"]

# Train-test split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# Model training
model = RandomForestClassifier()
model.fit(X_train, y_train)

# Model persistence
joblib.dump(model, "diabetes_model.pkl")
Enter fullscreen mode Exit fullscreen mode

Key Learnings:

βœ… Reproducibility: Using a fixed random_state=42 ensures consistent results across runs

βœ… Model Serialization: joblib is efficient for saving scikit-learn models, preserving the entire model state

βœ… Feature Engineering: Selected only relevant features to keep the model simple and interpretable

βœ… Data Source Management: Using a hosted dataset URL makes the project portable and easy to reproduce


πŸš€ API Development (main.py)

FastAPI Implementation:

from fastapi import FastAPI
from pydantic import BaseModel
import joblib
import numpy as np

app = FastAPI()
model = joblib.load("diabetes_model.pkl")

class DiabetesInput(BaseModel):
    Pregnancies: int
    Glucose: float
    BloodPressure: float
    BMI: float
    Age: int

@app.get("/")
def read_root():
    return {"message": "Diabetes Prediction API is live"}

@app.post("/predict")
def predict(data: DiabetesInput):
    input_data = np.array([[
        data.Pregnancies, 
        data.Glucose, 
        data.BloodPressure, 
        data.BMI, 
        data.Age
    ]])
    prediction = model.predict(input_data)[0]
    return {"diabetic": bool(prediction)}
Enter fullscreen mode Exit fullscreen mode

Best Practices Followed:

βœ… Input Validation: Pydantic models automatically validate request data and provide clear error messages

βœ… Type Safety: Explicit type hints improve code readability and catch errors early

βœ… RESTful Design: Separate endpoints for health checks (/) and predictions (/predict)

βœ… Auto-Documentation: FastAPI generates interactive API docs at /docs automatically


🐳 Containerization (Dockerfile)

Docker Configuration:

FROM python:3.10
WORKDIR /app
COPY . /app
RUN pip install -r requirements.txt
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Enter fullscreen mode Exit fullscreen mode

Key Best Practices:

βœ… Minimal Base Image: Using python:3.10 provides a balance between size and functionality

βœ… Working Directory: WORKDIR keeps the container filesystem organized

βœ… Port Exposure: Binding to 0.0.0.0 makes the API accessible outside the container

βœ… Layer Optimization: Copying requirements first would enable better caching (future improvement!)

Commands Used:

# Build the image
docker build -t diabetes-prediction-model .

# Run locally
docker run -p 8000:8000 diabetes-prediction-model

# Test the API
curl http://localhost:8000/
Enter fullscreen mode Exit fullscreen mode


☸️ Kubernetes Deployment

Deployment Manifest (k8s-deploy.yml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: diabetes-api
  labels:
    app: diabetes-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: diabetes-api
  template:
    metadata:
      labels:
        app: diabetes-api
    spec:
      containers:
      - name: diabetes-api
        image: aman202004/diabetes-api:latest
        ports:
        - containerPort: 8000
        imagePullPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: diabetes-api-service
spec:
  selector:
    app: diabetes-api
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8000
  type: LoadBalancer
Enter fullscreen mode Exit fullscreen mode

MLOps Best Practices:

βœ… High Availability: replicas: 2 ensures the service stays available if one pod fails

βœ… Label Management: Consistent labels connect Deployments, Pods, and Services

βœ… Service Abstraction: LoadBalancer Service provides a stable endpoint for clients

βœ… Image Policy: imagePullPolicy: Always ensures latest version is deployed

βœ… Port Mapping: Clear separation between service port (80) and container port (8000)

Deployment Commands:

# Deploy to Kubernetes
kubectl apply -f k8s-deploy.yml

# Check deployment status
kubectl get deployments
kubectl get pods
kubectl get services

# Test the API (after getting external IP)
kubectl port-forward service/diabetes-api-service 8000:80
Enter fullscreen mode Exit fullscreen mode


πŸ§ͺ Testing the API

Sample Request:

curl -X POST "http://localhost:8000/predict" \
  -H "Content-Type: application/json" \
  -d '{
    "Pregnancies": 2,
    "Glucose": 130,
    "BloodPressure": 70,
    "BMI": 28.5,
    "Age": 45
  }'
Enter fullscreen mode Exit fullscreen mode

Response:

{
  "diabetic": true
}
Enter fullscreen mode Exit fullscreen mode

πŸ“š What I Learned

Technical Skills:

  1. End-to-End MLOps Workflow: Understanding the complete pipeline from training to deployment
  2. API Development: Creating production-ready REST APIs with FastAPI
  3. Containerization: Packaging ML applications for consistent environments
  4. Kubernetes Fundamentals: Deploying and managing containerized applications
  5. Model Serialization: Properly saving and loading ML models for production

DevOps Practices:

  • Reproducibility: Using virtual environments and requirements.txt
  • Version Control: Tracking all code and configurations in Git
  • Documentation: Writing clear README files and inline comments
  • Infrastructure as Code: Defining infrastructure in YAML manifests
  • Container Orchestration: Understanding pods, services, and deployments

Best Practices:

  • Separation of Concerns: Keeping training, serving, and deployment separate
  • Input Validation: Using Pydantic for robust API contracts
  • Health Checks: Implementing basic health endpoints
  • Scalability: Using Kubernetes for easy horizontal scaling
  • Portability: Docker ensures the application runs anywhere

πŸŽ“ Key Takeaways

What Worked Well:

βœ… FastAPI's automatic documentation saved significant development time
βœ… Docker eliminated "works on my machine" problems
βœ… Kubernetes simplified scaling from 1 to N replicas
βœ… Using a public dataset made the project easily reproducible
βœ… Simple project structure kept complexity manageable

Areas for Future Improvement:

πŸ”„ Add CI/CD pipeline with GitHub Actions
πŸ”„ Implement model versioning and A/B testing
πŸ”„ Add monitoring with Prometheus and Grafana
πŸ”„ Include automated testing (unit and integration tests)
πŸ”„ Optimize Docker image size using multi-stage builds
πŸ”„ Add model performance metrics endpoint
πŸ”„ Implement proper logging with structured logs
πŸ”„ Add authentication and rate limiting


πŸ› οΈ Tools & Technologies Used

Category Technology
Language Python 3.10
ML Framework scikit-learn
API Framework FastAPI, Uvicorn
Containerization Docker
Orchestration Kubernetes
Data Handling pandas, numpy
Model Persistence joblib
Validation Pydantic

🎯 Conclusion

This project gave me hands-on experience with the complete MLOps lifecycle. Moving from a Jupyter notebook to a production-ready Kubernetes deployment taught me that MLOps is as much about software engineering practices as it is about machine learning.

For anyone starting their MLOps journey, I highly recommend building a similar end-to-end project. The practical experience of connecting all these tools together is invaluable.

GitHub Repository: https://github.com/amco-f22/first-mlops-project

Feel free to clone, experiment, and extend this project! I'm always open to feedback and suggestions.


πŸ“– Resources


What's your experience with MLOps? Have you built similar projects? Share your thoughts in the comments! πŸ’¬

MLOps #Kubernetes #Docker #MachineLearning #DevOps #FastAPI #DataScience

Top comments (0)