Hackforge Academy

Category: python

Introduction to Python Microservices with Docker Compose

Published on 22 Aug 2026

Explanation

Docker Compose allows multiple containers to be defined and managed using a single YAML configuration file. In a Python microservices application, each service can run in its own container. For example, a Product Service and Order Service can be developed independently while Docker Compose manages their networking, ports, environment variables, and startup. This makes it easier to run an entire microservices application locally.

Code:

services:
  product-service:
    build: ./product-service
    ports:
      - '8001:8000'

  order-service:
    build: ./order-service
    ports:
      - '8002:8000'

# Start all services:
# docker compose up --build

Explanation

Each Python microservice should have its own application code, dependencies, and Dockerfile. The Product Service can expose REST endpoints using FastAPI. Its Dockerfile creates an isolated environment containing Python, the required packages, and the application code. Docker Compose can then build and start this service automatically.

Code:

# product-service/app/main.py

from fastapi import FastAPI

app = FastAPI(title='Product Service')


@app.get('/products')
def get_products():
    return [
        {'id': 1, 'name': 'Laptop', 'price': 65000},
        {'id': 2, 'name': 'Mouse', 'price': 750}
    ]


# product-service/requirements.txt
# fastapi
# uvicorn


# product-service/Dockerfile
FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app ./app

EXPOSE 8000

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Explanation

The Order Service can run in a separate container from the Product Service. It can communicate with the Product Service using its Docker Compose service name. Inside a Docker network, containers should not use localhost to communicate with each other because localhost refers to the current container. Docker Compose provides DNS-based service discovery, allowing the Order Service to call Product Service using a URL such as http://product-service:8000.

Code:

# order-service/app/main.py

from fastapi import FastAPI
import httpx
import os

app = FastAPI(title='Order Service')

PRODUCT_SERVICE_URL = os.getenv(
    'PRODUCT_SERVICE_URL',
    'http://product-service:8000'
)


@app.get('/orders/{product_id}')
async def create_order(product_id: int):
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f'{PRODUCT_SERVICE_URL}/products',
            timeout=5.0
        )

    products = response.json()

    return {
        'product_id': product_id,
        'products': products,
        'message': 'Order service received product data'
    }

Explanation

Docker Compose automatically creates a network for services defined in the Compose file. Services can communicate with each other using their service names. In this example, the Order Service uses product-service as the hostname instead of localhost. This allows the same Compose configuration to work even though containers may receive different IP addresses when they are recreated.

Code:

services:
  product-service:
    build: ./product-service
    ports:
      - '8001:8000'

  order-service:
    build: ./order-service
    ports:
      - '8002:8000'
    environment:
      PRODUCT_SERVICE_URL: http://product-service:8000
    depends_on:
      - product-service

# Communication:
#
# Browser
#    |
#    +--> localhost:8001 -> Product Service
#    |
#    +--> localhost:8002 -> Order Service
#                         |
#                         v
#                 product-service:8000
#                         |
#                         v
#                  Product Service

Explanation

Once the Dockerfiles and Compose configuration are created, the complete microservices application can be started using Docker Compose. The docker compose up --build command builds the images and starts the containers. docker compose ps shows the running services, while docker compose logs can be used to inspect application logs. The application can then be tested through the exposed FastAPI endpoints and Swagger documentation.

Code:

# Build and start all services
docker compose up --build

# Run in background
docker compose up -d --build

# Check services
docker compose ps

# View logs
docker compose logs

# View only Order Service logs
docker compose logs order-service

# Stop services
docker compose down

# APIs:
# Product Service -> http://localhost:8001/docs
# Order Service   -> http://localhost:8002/docs

πŸš€ Learn Spring Boot with real-world projects

πŸ’‘ Build REST APIs step by step

🧠 Improve backend development skills

🎯 Get career-ready practical training

Join Our Free WhatsApp Community

Direct access to niche-specific mentors and peers on WhatsApp.

🐍

Python Community

Discuss Django, FastAPI, AI integration, and automation scripts with 15k+ developers.

Join Python Community
βš›οΈ

React Community

Master Next.js, Framer Motion, and State Management. Share your latest UI components.

Join React Community
β˜•

Java Community

Deep dives into Spring Boot, Microservices architecture, and high-performance backend ops.

Join Java Community