Skip to content

Docker Services Documentation

This document explains each Docker service in the AzharStack infrastructure, its purpose, configuration, and how to inspect its logs.

Service Overview

The docker-compose.yml defines four services:

  1. postgres - PostgreSQL 16 database
  2. redis - Redis 7 cache and event bus
  3. medusa - MedusaJS v2 backend
  4. store - React store frontend

PostgreSQL Service

Purpose

PostgreSQL stores all persistent application data including: - Products and variants - Categories - Customers and addresses - Orders and line items - Custom module data (advertisements, settings, translations)

Configuration

postgres:
  image: postgres:16-alpine
  container_name: azharstore-postgres
  environment:
    POSTGRES_USER: ${POSTGRES_USER:-medusa}
    POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-medusa}
    POSTGRES_DB: ${POSTGRES_DB:-azharstore}
  volumes:
    - postgres_data:/var/lib/postgresql/data
  ports:
    - "5432:5432"
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-medusa}"]
    interval: 10s
    timeout: 5s
    retries: 5
  restart: unless-stopped

Volume Mounts

  • postgres_data: Named volume for persistent database storage
  • Location: /var/lib/postgresql/data inside container

Port Mapping

  • Host: 5432 → Container: 5432
  • Allows direct PostgreSQL connection from host machine

Health Check

  • Runs pg_isready every 10 seconds
  • Accepts connections after 5 successful retries
  • Medusa service waits for this health check before starting

Inspecting Logs

View PostgreSQL logs:

docker compose logs -f postgres

View last 100 lines:

docker compose logs --tail=100 postgres

Direct Database Access

Connect to PostgreSQL using psql:

docker compose exec postgres psql -U medusa -d azharstore

Common psql commands:

\l                    -- List databases
\dt                   -- List tables
\d table_name         -- Describe table
\q                    -- Quit

Backup Database

Create a backup:

docker compose exec postgres pg_dump -U medusa azharstore > backup.sql

Restore from backup:

docker compose exec -T postgres psql -U medusa azharstore < backup.sql

Redis Service

Purpose

Redis serves two main functions: 1. Event Bus: Medusa uses Redis for pub/sub events (order created, inventory updated, etc.) 2. Caching: Optional caching layer for API responses

Configuration

redis:
  image: redis:7-alpine
  container_name: azharstore-redis
  volumes:
    - redis_data:/data
  ports:
    - "6379:6379"
  healthcheck:
    test: ["CMD", "redis-cli", "ping"]
    interval: 10s
    timeout: 5s
    retries: 5
  restart: unless-stopped

Volume Mounts

  • redis_data: Named volume for persistent Redis data
  • Location: /data inside container

Port Mapping

  • Host: 6379 → Container: 6379
  • Allows direct Redis connection from host machine

Health Check

  • Runs redis-cli ping every 10 seconds
  • Returns PONG when healthy
  • Medusa service waits for this health check before starting

Inspecting Logs

View Redis logs:

docker compose logs -f redis

Direct Redis Access

Connect to Redis CLI:

docker compose exec redis redis-cli

Common Redis commands:

PING                  -- Test connection
KEYS *                -- List all keys
FLUSHALL              -- Clear all data (use with caution)
QUIT                  -- Quit

Medusa Service

Purpose

Medusa is the core e-commerce backend that: - Provides REST API for store and admin - Manages products, orders, customers - Runs custom workflows - Serves the admin dashboard UI - Hosts custom modules

Configuration

medusa:
  build:
    context: ./backend
    dockerfile: Dockerfile
  container_name: azharstore-medusa
  environment:
    NODE_ENV: ${NODE_ENV:-production}
    PORT: ${PORT:-9000}
    DATABASE_URL: postgresql://${POSTGRES_USER:-medusa}:${POSTGRES_PASSWORD:-medusa}@postgres:5432/${POSTGRES_DB:-azharstore}
    REDIS_URL: redis://redis:6379
    JWT_SECRET: ${JWT_SECRET}
    COOKIE_SECRET: ${COOKIE_SECRET}
    STORE_CORS: ${STORE_CORS:-http://localhost:8080}
    ADMIN_CORS: ${ADMIN_CORS:-http://localhost:9000}
    AUTH_CORS: ${AUTH_CORS:-http://localhost:9000}
    MEDUSA_ADMIN_EMAIL: ${MEDUSA_ADMIN_EMAIL}
    MEDUSA_ADMIN_PASSWORD: ${MEDUSA_ADMIN_PASSWORD}
  ports:
    - "9000:9000"
  depends_on:
    postgres:
      condition: service_healthy
    redis:
      condition: service_healthy
  restart: always
  volumes:
    - ./backend/uploads:/app/uploads

Build Configuration

  • Context: ./backend directory
  • Dockerfile: Multi-stage build (builder + production)
  • Builder stage: Installs dependencies, builds TypeScript, runs migrations
  • Production stage: Runs compiled output with non-root user

Environment Variables

All environment variables are passed from the host .env file: - DATABASE_URL: PostgreSQL connection string - REDIS_URL: Redis connection string - JWT_SECRET: Secret for JWT token signing - COOKIE_SECRET: Secret for session cookies - STORE_CORS: Allowed origins for store API - ADMIN_CORS: Allowed origins for admin API - MEDUSA_ADMIN_EMAIL: Admin user email - MEDUSA_ADMIN_PASSWORD: Admin user password

Volume Mounts

  • ./backend/uploads:/app/uploads: Persistent storage for uploaded files (product images, etc.)

Port Mapping

  • Host: 9000 → Container: 9000
  • Exposes Medusa API and admin dashboard

Dependencies

  • Waits for PostgreSQL to be healthy
  • Waits for Redis to be healthy
  • Uses restart: always to auto-recover from crashes

Inspecting Logs

View Medusa logs:

docker compose logs -f medusa

View logs with timestamps:

docker compose logs -t -f medusa

Container Shell Access

Access the Medusa container:

docker compose exec medusa sh

Run Medusa CLI commands inside container:

docker compose exec medusa npx medusa --help

Store Service

Purpose

The store service serves the React frontend: - Provides customer-facing storefront - Handles client-side routing - Proxies API requests to Medusa backend

Configuration

store:
  build:
    context: ./frontend/store
    dockerfile: Dockerfile
  container_name: azharstore-frontend
  ports:
    - "8080:80"
  depends_on:
    - medusa
  restart: unless-stopped

Build Configuration

  • Context: ./frontend/store directory
  • Dockerfile: Multi-stage build (Vite build + Nginx serve)
  • Builder stage: Installs dependencies, builds with Vite
  • Production stage: Serves static files with Nginx

Port Mapping

  • Host: 8080 → Container: 80
  • Nginx serves on port 80 inside container

Dependencies

  • Depends on Medusa service for API proxying

Inspecting Logs

View store logs:

docker compose logs -f store

Volumes

Named Volumes

volumes:
  postgres_data:
    name: azharstore_postgres_data
  redis_data:
    name: azharstore_redis_data
  • azharstore_postgres_data: Persistent PostgreSQL data
  • azharstore_redis_data: Persistent Redis data

These volumes survive container restarts and recreations, ensuring data persistence.

Managing Volumes

List all volumes:

docker volume ls

Inspect a volume:

docker volume inspect azharstore_postgres_data

Remove a volume (⚠️ deletes data):

docker volume rm azharstore_postgres_data

Networks

Network Configuration

networks:
  azharstore-network:
    driver: bridge

All services are connected to the azharstore-network bridge network, allowing them to communicate by container name (e.g., postgres, redis, medusa).

Inspecting Network

List networks:

docker network ls

Inspect network details:

docker network inspect az-main_azharstore-network

Health Checks

All services include health checks to ensure they're ready before dependent services start:

  • PostgreSQL: pg_isready - Checks database accepts connections
  • Redis: redis-cli ping - Checks Redis responds to PING
  • Medusa: No explicit health check (relies on process health)
  • Store: No explicit health check (relies on process health)

View health status:

docker compose ps

Resource Limits

For production, consider adding resource limits to docker-compose.yml:

medusa:
  deploy:
    resources:
      limits:
        cpus: '2'
        memory: 2G
      reservations:
        cpus: '1'
        memory: 1G

Security Considerations

  1. Non-root user: Medusa container runs as non-root user medusa
  2. Secrets management: All secrets in .env file (not in git)
  3. Network isolation: Services on internal bridge network
  4. Minimal images: Using Alpine variants for smaller attack surface
  5. Volume permissions: Uploads directory properly owned by medusa user