DEV Community

cypher682
cypher682

Posted on

Complete Beginner's Guide to Building a Microservices TODO Application with Docker and Traefik

Introduction

Welcome! This guide will walk you through a real-world microservices application - a TODO app that demonstrates how different services written in different programming languages can work together seamlessly. If you're new to DevOps or microservices, don't worry - I'll explain everything step by step!

Repository: HNG DevOps on GitHub

What You'll Learn:

  • How microservices architecture works in practice
  • How to use Docker to containerize multiple services
  • How to set up Traefik as a reverse proxy
  • How different programming languages work together
  • How services communicate with each other
  • How to implement authentication across microservices

What is a Microservices Architecture?

The Traditional Way (Monolithic)

Imagine building a house where everything - kitchen, bedroom, bathroom - is one giant room. If you want to renovate the kitchen, you might affect the bedroom too. That's a monolithic application.

The Microservices Way

Now imagine a house where each room is a separate, self-contained unit. You can renovate the kitchen without touching the bedroom. Each room has its own entrance and can be accessed independently. That's microservices architecture.

Why Microservices?

Independent Development: Different teams can work on different services

Technology Flexibility: Use the best language/framework for each service

Scalability: Scale only the services that need it

Fault Isolation: If one service fails, others keep running

Easier Maintenance: Smaller codebases are easier to understand


Project Overview

This project is a TODO application that allows users to:

  • Register and log in (Authentication)
  • Create, read, update, and delete TODO items
  • View user profiles
  • Track operations through logging

The Magic Behind It

The application is split into 5 independent microservices:

  1. Frontend (Vue.js) - The user interface
  2. Auth API (Go) - Handles user authentication
  3. TODOs API (Node.js) - Manages TODO items
  4. Users API (Java/Spring Boot) - Manages user profiles
  5. Log Message Processor (Python) - Processes and logs operations

Understanding the Components

Let's break down each component in simple terms:

1. Frontend (Vue.js - JavaScript)

What it does: This is what users see and interact with - the web interface.

Think of it as: The cashier at a restaurant who takes your order and brings you food.

Why Vue.js? It's a modern, lightweight JavaScript framework perfect for building interactive user interfaces.


2. Auth API (Go)

What it does: Handles user authentication and generates JWT (JSON Web Tokens) for secure access.

Think of it as: The security guard who checks your ID and gives you a badge to enter the building.

How JWT Works:

1. User logs in with username/password
2. Auth API verifies credentials
3. Auth API generates a JWT token (like a temporary pass)
4. User includes this token in future requests
5. Other services verify the token to confirm identity
Enter fullscreen mode Exit fullscreen mode

Why Go? Go is fast, efficient, and excellent for building high-performance APIs.


3. TODOs API (Node.js)

What it does: Manages all TODO operations - create, read, update, delete.

Think of it as: The kitchen that prepares your food orders.

Redis Integration:
When you create or delete a TODO, the API sends a message to Redis (a message queue), which the Log Message Processor picks up and logs.

Why Node.js? Node.js is great for I/O-heavy operations and has a rich ecosystem of packages.


4. Users API (Java/Spring Boot)

What it does: Manages user profile information.

Think of it as: The HR department that maintains employee records.

Why Java/Spring Boot? Spring Boot is enterprise-grade, robust, and widely used in production environments.


5. Log Message Processor (Python)

What it does: Listens to Redis queue and logs TODO operations.

Think of it as: The security camera system that records all activities.

Why Python? Python is simple, readable, and perfect for quick scripting tasks.


6. Traefik (Reverse Proxy)

What it does: Routes incoming requests to the correct service and handles SSL/TLS certificates.

Think of it as: The receptionist who directs visitors to the right department.

Key Features:

  • Automatic service discovery
  • SSL/TLS certificate management (Let's Encrypt)
  • HTTP to HTTPS redirection
  • Path-based routing

Technology Stack

Here's a summary of all technologies used:

Component Technology Purpose
Frontend Vue.js User interface
Auth API Go Authentication service
TODOs API Node.js TODO management
Users API Java/Spring Boot User profile management
Log Processor Python Logging service
Message Queue Redis Inter-service communication
Reverse Proxy Traefik Request routing & SSL
Containerization Docker Package services
Orchestration Docker Compose Manage multiple containers

Architecture Overview

Visual Architecture

                    Internet
                       |
                       v
              +----------------+
              |    Traefik     |
              | (Port 80/443)  |
              +----------------+
                       |
    +------------------+------------------+
    |                  |                  |
    v                  v                  v
+----------+    +----------+    +----------+
| Frontend |    | Auth API |    |TODOs API |
| (Vue.js) |    |   (Go)   |    | (Node.js)|
+----------+    +----------+    +----------+
    |                  |                  |
    |                  v                  |
    |          +-------------+            |
    +--------->|  Users API  |<-----------+
               | (Java)      |
               +-------------+


+-------------+              +-------------+
| Log Message |<--Redis------|  TODOs API  |
| Processor   |              +-------------+
| (Python)    |
+-------------+
Enter fullscreen mode Exit fullscreen mode

Request Flow Example

Let's trace what happens when a user creates a TODO:

  1. User Action: User fills out TODO form and clicks "Create"
  2. Frontend: Sends POST request to https://example.com/api/todos
  3. Traefik: Receives request, checks routing rules, forwards to TODOs API
  4. TODOs API:
    • Validates JWT token
    • Creates TODO in database
    • Publishes "TODO created" message to Redis
    • Returns success response
  5. Redis: Stores message in queue
  6. Log Message Processor:
    • Reads message from Redis
    • Logs the operation
  7. Frontend: Receives success response, updates UI

Setting Up the Project

Prerequisites

Before you start, make sure you have:

  • Docker installed (Download here)
  • Docker Compose installed (usually comes with Docker Desktop)
  • Basic command line knowledge
  • A text editor (VS Code, Sublime, etc.)

Step 1: Clone the Repository

git clone https://github.com/cypher682/hng13-stage-3-devops.git
cd DevOps-Stage-6
Enter fullscreen mode Exit fullscreen mode

Step 2: Understand the Project Structure

DevOps-Stage-6/
├── frontend/              # Vue.js application
│   ├── Dockerfile        # Instructions to build frontend container
│   └── src/              # Source code
├── auth-api/             # Go authentication service
│   ├── Dockerfile
│   └── main.go
├── todos-api/            # Node.js TODO service
│   ├── Dockerfile
│   └── server.js
├── users-api/            # Java Spring Boot service
│   ├── Dockerfile
│   └── src/
├── log-message-processor/ # Python logging service
│   ├── Dockerfile
│   └── processor.py
├── docker-compose.yml    # Orchestration configuration
└── .env                  # Environment variables
Enter fullscreen mode Exit fullscreen mode

Step 3: Configure Environment Variables

The .env file contains configuration for all services:

# User credentials (for testing)
USER1_USERNAME=user1
USER1_PASSWORD=password1

# JWT Secret (for token generation)
JWT_SECRET=myfancysecret

# Redis Configuration
REDIS_HOST=redis-queue
REDIS_PORT=6379
REDIS_CHANNEL=log_channel
Enter fullscreen mode Exit fullscreen mode

Important: In production, never commit .env files with real credentials!

Step 4: Build and Run

# Build all services
docker compose build

# Start all services
docker compose up -d

# Check if all services are running
docker compose ps
Enter fullscreen mode Exit fullscreen mode

What -d means: Runs containers in "detached" mode (in the background).

Step 5: Verify Services

Check that all containers are running:

docker compose ps
Enter fullscreen mode Exit fullscreen mode

You should see all services with status "Up" or "Running":

  • traefik
  • frontend
  • auth-api
  • todos-api
  • users-api
  • log-message-processor
  • redis-queue

Understanding Docker Compose

What is Docker Compose?

Docker Compose is a tool for defining and running multi-container Docker applications. Instead of running each container manually, you define everything in a docker-compose.yml file.

Key Sections Explained

1. Services Definition

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • services: - Defines all containers
  • traefik: - Service name
  • image: - Docker image to use
  • container_name: - Name for the container
  • restart: - Restart policy

2. Port Mapping

ports:
  - "80:80"
  - "443:443"
Enter fullscreen mode Exit fullscreen mode

Format: HOST_PORT:CONTAINER_PORT

Explanation:

  • Maps port 80 on your computer to port 80 in the container
  • Allows you to access services from your browser

3. Networks

networks:
  - app-network
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • All services on the same network can communicate with each other
  • Services can reference each other by service name (e.g., http://auth-api:8081)

4. Traefik Labels (Routing)

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.frontend.rule=Host(`example.com`)"
  - "traefik.http.routers.frontend.entrypoints=websecure"
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Tells Traefik to route requests for example.com to this service
  • Enables HTTPS with automatic certificate generation

How Services Communicate

Internal Communication (Service-to-Service)

Services communicate using service names as hostnames:

// In Frontend (Vue.js)
const AUTH_API_ADDRESS = 'http://auth-api:8081';
const TODOS_API_ADDRESS = 'http://todos-api:8082';
Enter fullscreen mode Exit fullscreen mode

Why this works:

  • Docker Compose creates a network where services can find each other by name
  • No need for IP addresses

External Communication (User-to-Service)

Users access services through Traefik:

User → https://example.com → Traefik → Frontend
User → https://example.com/api/auth → Traefik → Auth API
User → https://example.com/api/todos → Traefik → TODOs API
Enter fullscreen mode Exit fullscreen mode

Authentication Flow

1. User submits login form
   ↓
2. Frontend sends credentials to Auth API
   ↓
3. Auth API verifies with Users API
   ↓
4. Auth API generates JWT token
   ↓
5. Frontend stores token
   ↓
6. Frontend includes token in all future requests
   ↓
7. Each API validates token before processing
Enter fullscreen mode Exit fullscreen mode

Testing the Application

1. Access the Frontend

Open your browser and navigate to:

http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

2. Test Authentication

Login with test credentials:

Username: user1
Password: password1
Enter fullscreen mode Exit fullscreen mode

3. Create a TODO

  1. Click "Add TODO"
  2. Enter a title and description
  3. Click "Save"
  4. Check that the TODO appears in the list

4. Check Logs

View logs from the Log Message Processor:

docker compose logs -f log-message-processor
Enter fullscreen mode Exit fullscreen mode

You should see log entries for TODO creation.

5. Test API Endpoints Directly

Get all users:

curl http://localhost:8080/api/users
Enter fullscreen mode Exit fullscreen mode

Login (get JWT token):

curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"user1","password":"password1"}'
Enter fullscreen mode Exit fullscreen mode

Common Issues and Troubleshooting

Issue 1: Containers Won't Start

Symptoms: Containers show as "Exited" or "Restarting"

Solutions:

# Check logs for specific service
docker compose logs auth-api

# Rebuild containers
docker compose down
docker compose build --no-cache
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Issue 2: Port Already in Use

Error: bind: address already in use

Solutions:

# Find what's using the port (Windows)
netstat -ano | findstr :80

# Change port in docker-compose.yml
ports:
  - "8000:80"  # Use port 8000 instead
Enter fullscreen mode Exit fullscreen mode

Issue 3: Services Can't Communicate

Symptoms: Frontend can't reach APIs

Solutions:

# Verify all services are on the same network
docker network inspect devops-stage-6_app-network

# Restart networking
docker compose down
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Debugging Commands Cheat Sheet

# View all running containers
docker compose ps

# View logs for all services
docker compose logs

# View logs for specific service
docker compose logs -f frontend

# Restart specific service
docker compose restart todos-api

# Stop all services
docker compose down

# View resource usage
docker stats
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

What You've Learned

  1. Microservices Architecture

    • How to split an application into independent services
    • Benefits of using different languages for different services
    • How services communicate with each other
  2. Docker & Containerization

    • How to containerize applications
    • How to use Docker Compose for multi-container applications
    • How to manage container networking
  3. Reverse Proxy with Traefik

    • How to route requests to different services
    • How to automatically manage SSL certificates
    • How to use labels for service discovery
  4. Inter-Service Communication

    • Synchronous communication (HTTP/REST)
    • Asynchronous communication (Message Queues)
    • Authentication across services (JWT)

Real-World Applications

This architecture pattern is used by companies like:

  • Netflix - Hundreds of microservices
  • Amazon - Service-oriented architecture
  • Uber - Microservices for different features
  • Spotify - Independent teams, independent services

Next Steps

To deepen your understanding:

  1. Modify the Application

    • Add a new microservice (e.g., Comments API)
    • Implement a database for persistent storage
    • Add user registration functionality
  2. Improve the Infrastructure

    • Add monitoring with Prometheus and Grafana
    • Implement centralized logging
    • Add CI/CD pipeline with GitHub Actions
  3. Security Enhancements

    • Implement rate limiting
    • Add API gateway
    • Use secrets management

Additional Resources

Documentation

Tools


Conclusion

Congratulations! You've just learned how to build, deploy, and manage a complete microservices application. This project demonstrates real-world DevOps practices used by major tech companies.

Remember:

  • Start small - Don't try to build everything at once
  • Understand each component - Know what each service does
  • Experiment - Break things and fix them (that's how you learn!)
  • Read logs - They're your best friend when debugging
  • Keep learning - DevOps is constantly evolving

The skills you've gained here - Docker, microservices, reverse proxies, and service orchestration - are highly valuable in the industry. Keep practicing, keep building, and most importantly, keep learning!

Full Project Repository: HNG DevOps on GitHub

Top comments (0)