Microservices deployment using multiple Docker containers
- Sharon Rajendra Manmothe

- 4 days ago
- 3 min read
1. Quick overview — what we’ll do and why
What we’ll build (high level)Two small microservices (Python + Flask) that run in separate Docker containers and communicate over Docker’s network.
user-service — serves user info at
order-service — calls user-service and returns user + order info
We orchestrate both with Docker Compose so they start together and can discover each other by service name.
Why this exercise matters
Demonstrates key microservices concepts: service isolation, inter-service communication, service discovery (via Docker Compose DNS), and reproducible deployments.
Shows how Docker networks enable containers to call each other by service name rather than IP.
Prepares students for real-world systems where services are independent, scalable, and managed via orchestration tools (Compose/Kubernetes).
Related real-world examples
E-commerce: auth-service, product-service, order-service, payment-service.
Social app: user-profile, feed, notification.
Monitoring: a service pushing metrics to a separate ingestion API.
2. Learning objectives (what students should learn)
By the end of the lab students will be able to:
Containerize a Python Flask app using a Dockerfile.
Write a docker-compose.yml to run multiple containers together.
Understand and test how containers communicate by service name.
Debug common container-networking and dependency issues.
Extend services (add DB, logging, scaling) as next steps.
3. Prerequisites & checklist (what must be installed)
Docker Desktop for Windows (or Docker Engine + docker-compose). If on Windows, enable WSL2 if prompted.
Basic familiarity with Python (creating a small Flask app).
A terminal (PowerShell or CMD).
Text editor (VS Code recommended).
4. Project structure (create this folder tree)
Create a folder C:\microservices-demo (or your preferred path) and inside create:
microservices-demo/
│
├── user-service/
│ ├── app.py
│ ├── requirements.txt
│ └── Dockerfile
│
├── order-service/
│ ├── app.py
│ ├── requirements.txt
│ └── Dockerfile
│
└── docker-compose.yml
You’ll paste the provided file contents below into these files.
5. File contents — copy these exactly
user-service/app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/user')
def get_user():
# Simple static data for the demo
return jsonify({"id": 1, "name": "Sharon", "role": "Developer"})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5001)
user-service/requirements.txt
flask==2.2.5
(pinning a minor version reduces differences during installs; not mandatory)
user-service/Dockerfile
# Use an official Python runtime as a parent image
FROM python:3.10-slim
# Set working directory
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy the app code
COPY . .
# Expose the port
EXPOSE 5001
# Start the app
CMD ["python", "app.py"]
order-service/app.py
from flask import Flask, jsonify
import requests
app = Flask(__name__)
@app.route('/order')
def get_order():
# Call the user-service using the Docker Compose service name
try:
user_response = requests.get('http://user-service:5001/user', timeout=5)
user = user_response.json()
except Exception as e:
# If user-service is not reachable, return an error message so students can debug
return jsonify({"error": "Could not reach user-service", "details": str(e)}), 503
order = {"order_id": 101, "item": "Laptop", "price": 55000}
return jsonify({"user": user, "order": order})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5002)
order-service/requirements.txt
flask==2.2.5
requests==2.31.0
order-service/Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5002
CMD ["python", "app.py"]
docker-compose.yml (root of project)
version: '3.8'
services:
user-service:
build: ./user-service
container_name: user-service
ports:
- "5001:5001"
restart: unless-stopped
order-service:
build: ./order-service
container_name: order-service
ports:
- "5002:5002"
depends_on:
- user-service
restart: unless-stopped
Notes:
depends_on ensures Docker Compose starts user-service first, but it does not wait for the service to be "ready" — only for the container to start. We'll mention how to handle readiness later.
container_name is optional — included here to make container names predictable in the lab.
6. Step-by-step commands (build, run, test)
Open a terminal at the project root (C:\microservices-demo).
Build containers
docker-compose build
Output: Docker will download base images and build both images. Look for Successfully built messages.

Start services (foreground logging)
docker-compose up
This will stream logs from both containers. You should see Flask starting messages for both services.
Press Ctrl+C to stop (or open a new terminal and run docker-compose down).
Start services (detached)
docker-compose up -d
Runs containers in background. Then check status:
docker-compose ps
You should see both user-service and order-service with STATE Up.
Test endpoints (use browser, curl, or Postman)
Test user-service:
Browser: http://localhost:5001/userExpected JSON: {"id":1,"name":"Sharon","role":"Developer"}
Or curl (PowerShell):
Test order-service (this will call user-service internally):
Browser: http://localhost:5002/orderExpected JSON:
{ "user": {"id":1,"name":"Sharon","role":"Developer"}, "order": {"order_id":101,"item":"Laptop","price":55000} }
View logs
docker-compose logs --tail=100 docker-compose logs order-service
Stop & remove containers
docker-compose down
This removes containers and network but keeps images locally.
7. Verify what happened
When order-service calls http://user-service:5001/user it uses the Compose service name (user-service) as a DNS name. Docker Compose creates an isolated network where service names resolve to container IPs.
This avoids hardcoding IP addresses and mirrors how service discovery works in production (DNS, Envoy, Kubernetes services, etc.).

$50
Product Title
Product Details goes here with the simple product description and more information can be seen by clicking the see more button. Product Details goes here with the simple product description and more information can be seen by clicking the see more button

$50
Product Title
Product Details goes here with the simple product description and more information can be seen by clicking the see more button. Product Details goes here with the simple product description and more information can be seen by clicking the see more button.

$50
Product Title
Product Details goes here with the simple product description and more information can be seen by clicking the see more button. Product Details goes here with the simple product description and more information can be seen by clicking the see more button.



Comments