Modern applications are rapidly shifting to microservices architectures, where loosely coupled services interact over well-defined APIs. To support agile deployment and scalability, teams increasingly use Docker to containerize and run these microservices.

This blog explores how to build and deploy REST APIs using Docker within microservices environments. We’ll walk through Dockerfile creation, environment variable injection, networking, and strategies for seamless deployment in production.


Why Use Docker for REST APIs?

Docker simplifies the REST API lifecycle by offering:

  • Consistent environments across dev, test, and production
  • Isolation for each microservice
  • Lightweight, portable containers
  • Seamless CI/CD integration
  • Compatibility with orchestration tools like Kubernetes and Docker Swarm

This allows independent development and deployment of services while minimizing conflicts and downtime.


Project Structure for a Sample API

Here’s a typical layout for a REST API project (e.g., using Spring Boot, Flask, or Express):

/user-service
├── app/
│   └── api.py
├── requirements.txt
├── Dockerfile
└── .env

Let’s create a Dockerfile for this service.


Creating a Dockerfile

Example: Flask-based Python REST API

FROM python:3.10-slim

WORKDIR /app

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

COPY . .

EXPOSE 5000

CMD ["python", "app/api.py"]

Best practices:

  • Use a slim base image
  • Install only what you need
  • Avoid using latest tags for reproducibility

Building and Running the Container

docker build -t user-service .
docker run -d -p 5000:5000 --env-file .env user-service

Use --env-file to inject environment variables like DB credentials or API tokens.


Docker Networking Between Services

In a microservices setup, services must talk to each other. Docker Compose simplifies this:

docker-compose.yml:

version: '3'
services:
user-service:
build: ./user-service
ports:
- "5000:5000"
environment:
- DB_HOST=db
depends_on:
- db

db:
image: postgres:13
environment:
- POSTGRES_PASSWORD=secret

Now user-service can access Postgres at hostname db.


Handling API Configuration

Avoid hardcoding config. Use .env files or secrets management:

PORT=5000
DB_HOST=db
DB_USER=admin
DB_PASSWORD=supersecure

Access in your code via environment variables:

Python:

import os
db_host = os.getenv("DB_HOST")

Java (Spring Boot):

spring.datasource.url=jdbc:postgresql://${DB_HOST}:${DB_PORT}/mydb

Deploying with Orchestration (Docker Swarm / Kubernetes)

For scalability and fault tolerance, use orchestration:

  • Docker Swarm:
    docker swarm init
    docker stack deploy -c docker-compose.yml microservice-stack
    
  • Kubernetes: Convert your Dockerized app to a deployment + service using Helm or YAML:
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:latest
ports:
- containerPort: 5000
envFrom:
- configMapRef:
name: user-service-config

Monitoring and Logging

Use Docker logging drivers or forward logs to ELK stack:

docker logs user-service

Best practices:

  • Implement structured logging (JSON format)
  • Use sidecars or exporters (e.g., Prometheus + Grafana) for metrics

Best Practices Summary

Practice Benefit
Minimal base image Reduces image size and attack surface
Multi-stage builds Speeds up CI and reduces final image size
Environment configs Decouples code from deployment settings
Health checks Ensures service readiness for orchestration
Volume mounts (for dev) Speeds up local iteration

Conclusion

Docker is a powerful enabler for building, deploying, and scaling REST APIs in microservices architectures. It simplifies dependency management, improves deployment velocity, and integrates seamlessly with modern DevOps tools.

By following containerization best practices and leveraging Docker Compose or Kubernetes, you can confidently deploy APIs that are resilient, portable, and production-ready.