Docker Compose for the Whole System

Run ShopEase Locally with One Command

Docker Compose starts all services plus the infrastructure they need (databases, Kafka, Zipkin) on one Docker network. Containers find each other by service name (kafka:9092, postgres:5432).

x-service-env: &service-env              # shared variables, merged into each service below
  SPRING_PROFILES_ACTIVE: docker
  EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://discovery-server:8761/eureka
  SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092
  MANAGEMENT_ZIPKIN_TRACING_ENDPOINT: http://zipkin:9411/api/v2/spans
  SPRING_DATASOURCE_USERNAME: shopease
  SPRING_DATASOURCE_PASSWORD: shopease

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: shopease
      POSTGRES_PASSWORD: shopease          # local only; use secrets in real environments
    volumes:
      - ./infra/create-databases.sql:/docker-entrypoint-initdb.d/init.sql   # product_db, order_db, payment_db
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U shopease"]
      interval: 5s
      retries: 10

  kafka:
    image: apache/kafka:3.8.0               # KRaft mode, no ZooKeeper
    environment:
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: broker,controller
      KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
    healthcheck:
      test: ["CMD-SHELL", "/opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 > /dev/null"]
      interval: 10s
      retries: 10

  zipkin:
    image: openzipkin/zipkin
    ports: ["9411:9411"]

  discovery-server:
    build: ./discovery-server
    ports: ["8761:8761"]

  product-service:
    build: ./product-service
    environment:
      <<: *service-env
      SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/product_db
    depends_on:
      postgres: { condition: service_healthy }
      kafka: { condition: service_healthy }

  order-service:
    build: ./order-service
    environment:
      <<: *service-env
      SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/order_db
    depends_on:
      postgres: { condition: service_healthy }
      kafka: { condition: service_healthy }

  payment-service:
    build: ./payment-service
    environment:
      <<: *service-env
      SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/payment_db
    depends_on:
      postgres: { condition: service_healthy }
      kafka: { condition: service_healthy }

  api-gateway:
    build: ./api-gateway
    ports: ["8080:8080"]                   # the ONLY service port published to the host
    environment:
      EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://discovery-server:8761/eureka
    depends_on: [discovery-server]

volumes:
  pgdata:

Note: x-service-env: &service-env defines a YAML anchor (Compose ignores top-level keys starting with x-), and <<: *service-env merges it into each service, so shared variables are written once. Of the business services only the gateway publishes a port (plus the Zipkin and Eureka dashboards); product, order and payment are reachable only inside the Compose network.

Start, Inspect, Stop

Example

docker compose up -d --build
docker compose ps
docker compose logs -f order-service
docker compose up -d --scale payment-service=2     # two instances, Eureka balances between them
docker compose down                                # add -v to delete the database volume too

Example output

NAME                 IMAGE                     SERVICE            STATUS                   PORTS
shopease-api-gateway-1       shopease-api-gateway       api-gateway        Up 40 seconds            0.0.0.0:8080->8080/tcp
shopease-discovery-server-1  shopease-discovery-server  discovery-server   Up 41 seconds            0.0.0.0:8761->8761/tcp
shopease-kafka-1             apache/kafka:3.8.0         kafka              Up 52 seconds (healthy)  9092/tcp
shopease-order-service-1     shopease-order-service     order-service      Up 30 seconds            8082/tcp
shopease-payment-service-1   shopease-payment-service   payment-service    Up 30 seconds            8084/tcp
shopease-postgres-1          postgres:16                postgres           Up 52 seconds (healthy)  5432/tcp
shopease-product-service-1   shopease-product-service   product-service    Up 30 seconds            8081/tcp
shopease-zipkin-1            openzipkin/zipkin          zipkin             Up 52 seconds            0.0.0.0:9411->9411/tcp

Tip: For local development of one service, run only the infrastructure in Compose and the service in your IDE. Spring Boot 3.1+ can even start the Compose file for you with the spring-boot-docker-compose dependency.