Home Wiki Networks & Communications Docker Compose: Running a Complete Industrial System With One Command
Networks & Communications

Docker Compose: Running a Complete Industrial System With One Command

Why Docker Compose?

Running a single container is straightforward. But industrial applications rarely work alone. A typical SCADA monitoring system needs an application server, a database, and a visualization dashboard — three separate containers that must communicate, share data, and start in the correct order.

Docker Compose defines all your services in a single YAML file. One command starts everything, connects the networks, and mounts the volumes. One command tears it all down.

For factory deployments, this means reproducing the entire stack on a test server before pushing to production, onboarding new engineers with a single docker compose up, and version-controlling your infrastructure alongside your application code.

The docker-compose.yml File: Basic Structure

Every Compose file follows the same skeleton:

services:
  app:
    image: factory-monitor:v1
    ports:
      - "8080:8080"
  database:
    image: surrealdb/surrealdb:latest
    ports:
      - "8000:8000"
  dashboard:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"

Key Commands

docker compose up -d          # Start all services in background
docker compose logs -f        # View logs from all services
docker compose down           # Stop and remove everything
docker compose up -d --build  # Rebuild after code changes

Services: App + Database + Dashboard

Here is a complete Compose file for an industrial monitoring stack:

services:
  factory-app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - DATABASE_URL=ws://surrealdb:8000
      - RUST_LOG=info
    depends_on:
      surrealdb:
        condition: service_healthy
    restart: unless-stopped

  surrealdb:
    image: surrealdb/surrealdb:v2.1.4
    command: start --user root --pass factory123 surrealkv://data/factory.db
    ports:
      - "8000:8000"
    volumes:
      - surreal-data:/data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 10s
      timeout: 5s
      retries: 3
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=monitor2025
    restart: unless-stopped

volumes:
  surreal-data:
  grafana-data:

The depends_on with condition: service_healthy ensures the application waits until the database is ready.

Networks: Isolating and Connecting Services

By default, Compose creates a single network for all services. For better security, isolate groups:

services:
  factory-app:
    networks: [frontend, backend]
  surrealdb:
    networks: [backend]
  grafana:
    networks: [frontend]

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true

With internal: true, the database cannot be reached from outside. Only the application, belonging to both networks, can talk to the database.

Volumes: Persisting Data Across Restarts

Without volumes, all data inside a container is lost when it stops. Use bind mounts for configuration files with :ro for read-only access:

services:
  grafana:
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/dashboards:/etc/grafana/provisioning/dashboards:ro

Managing Volumes

docker volume ls                                    # List all volumes
docker volume inspect factory-monitor_surreal-data  # Inspect a volume
docker volume prune                                 # Remove unused volumes

Environment Variables and the .env File

Hard-coding passwords in docker-compose.yml is a security risk. Use a .env file:

SURREAL_USER=root
SURREAL_PASS=secure_factory_password_2025
SURREAL_PORT=8000
APP_PORT=8080
RUST_LOG=info
GF_ADMIN_PASS=dashboard_secure_2025

Referencing in docker-compose.yml

services:
  surrealdb:
    command: start --user ${SURREAL_USER} --pass ${SURREAL_PASS} surrealkv://data/factory.db
    ports:
      - "${SURREAL_PORT}:8000"
  factory-app:
    environment:
      - DATABASE_URL=ws://surrealdb:${SURREAL_PORT}
      - RUST_LOG=${RUST_LOG}
    ports:
      - "${APP_PORT}:8080"

Add .env to .gitignore and distribute a .env.example with placeholder values so team members know which variables to set.

Summary

Docker Compose transforms multi-container deployments from a series of manual commands into a single declarative file. Services define what runs, networks control communication boundaries, volumes persist critical data, and environment variables keep secrets out of version control. In the next lesson, you will learn Linux system administration fundamentals needed to manage the servers where these containers run.

docker-compose multi-container volumes networks services YAML دوكر كومبوز عدة حاويات الأحجام الشبكات الخدمات التنسيق