A fully functional RESTful Account Microservice built with Flask and PostgreSQL, containerized with Docker, and deployed to Kubernetes. This project is the capstone of the IBM DevOps and Software Engineering Professional Certificate.
- Project Structure
- API Endpoints
- Prerequisites
- Option 1: Run Locally (Python)
- Option 2: Run with Kubernetes (Kind - Local)
- Option 3: Deploy to OpenShift (IBM Cloud)
- Testing the API
- Changes Made
devops-capstone/
βββ service/ β The Flask microservice package
β βββ common/ β Shared log and error handlers
β βββ config.py β Flask + SQLAlchemy configuration
β βββ models.py β Account database model (SQLAlchemy)
β βββ routes.py β All REST API route handlers β MAIN CHANGES HERE
β
βββ deploy/ β OpenShift (IBM Cloud) manifests β ORIGINAL
β βββ postgresql-ephemeral-template.json
β βββ deployment.yaml
β βββ service.yaml
β
βββ deploy-local/ β Kind (Local) manifests β NEW
β βββ postgresql.yaml β PostgreSQL Deployment + Service
β βββ deployment.yaml β Account Service Deployment
β βββ service.yaml β NodePort Service to expose the app
β
βββ tests/ β Unit and integration tests
β βββ factories.py
β βββ test_models.py
β βββ test_routes.py
β
βββ Dockerfile β Docker image definition β NEW
βββ Makefile β Dev commands (run, db, build, push)
βββ Procfile β gunicorn startup config
βββ requirements.txt β Python dependencies
βββ .flaskenv β Flask environment variables
Base URL (local): http://localhost:5005 or http://localhost:8085 (Kubernetes)
| Method | Endpoint | Description | Request Body |
|---|---|---|---|
GET |
/ |
Service info | β |
GET |
/health |
Health check | β |
GET |
/accounts |
List all accounts | β |
POST |
/accounts |
Create a new account | JSON body (see below) |
GET |
/accounts/<id> |
Get account by ID | β |
PUT |
/accounts/<id> |
Update an account | JSON body (see below) |
DELETE |
/accounts/<id> |
Delete an account | β |
{
"name": "John Doe",
"email": "john@example.com",
"address": "123 Main Street",
"phone_number": "555-1234"
}
phone_numberis optional. All other fields are required.
Make sure you have the following installed:
| Tool | Purpose | Install |
|---|---|---|
| Python 3.9 | Run the service locally | brew install python@3.9 |
| Docker Desktop | Run PostgreSQL + build images | docker.com |
| kind | Local Kubernetes cluster | brew install kind |
| kubectl | Kubernetes CLI | brew install kubectl |
| oc | OpenShift CLI (for Option 3) | OpenShift CLI |
This runs the service directly on your Mac using a Python virtual environment.
/opt/homebrew/opt/python@3.9/bin/python3.9 -m venv ~/venv39
source ~/venv39/bin/activate
pip install -r requirements.txtmake dbThis starts a PostgreSQL container on port 5432.
PORT=5005 make runOpen your browser or use curl:
http://localhost:5005
Expected output:
{"name": "Account REST API Service", "version": "1.0"}This runs the service inside a local Kubernetes cluster using Kind.
make clustermake buildkind load docker-image accounts:1.0 --name mlops-localkubectl apply -f deploy-local/This creates:
- A
postgresqlDeployment + ClusterIP Service - An
account-serviceDeployment - A
NodePortService for the account service
kubectl get podsExpected output:
NAME READY STATUS RESTARTS AGE
account-service-xxx 1/1 Running 0 30s
postgresql-xxx 1/1 Running 0 30s
kubectl port-forward svc/account-service 8085:8080http://localhost:8085
Expected output:
{"name": "Account REST API Service", "version": "1.0"}make build
kind load docker-image accounts:1.0 --name mlops-local
kubectl rollout restart deployment/account-service
kubectl rollout status deployment/account-serviceThis deploys the service to OpenShift on IBM Cloud using the original lab instructions.
oc login <your-openshift-cluster-url>oc create -f deploy/postgresql-ephemeral-template.json
oc new-app postgresql-ephemeraloc create -f deploy/deployment.yaml
oc create -f deploy/service.yamloc expose service accounts --name=accounts --edge-terminationoc get routesOpen the route URL in your browser or use curl:
curl <route-url>Expected output:
{"name": "Account REST API Service", "version": "1.0"}You can test all endpoints using curl:
curl -X POST http://localhost:8085/accounts \
-H "Content-Type: application/json" \
-d '{"name":"John Doe","email":"john@example.com","address":"123 Main St","phone_number":"555-1234"}'curl http://localhost:8085/accountscurl http://localhost:8085/accounts/1curl -X PUT http://localhost:8085/accounts/1 \
-H "Content-Type: application/json" \
-d '{"name":"Jane Doe","email":"jane@example.com","address":"456 Oak Ave","phone_number":"555-9999"}'curl -X DELETE http://localhost:8085/accounts/1
# Returns: HTTP 204 No Content (success, no body)curl http://localhost:8085/health
# Returns: {"status": "OK"}Implemented by mrdinhdinh and @sathvikvelapaka as part of the IBM DevOps Capstone Project.
Original template by John Rofrano, IBM Research.
Licensed under the Apache License 2.0. See LICENSE for details.