Skip to content

Docker Setup

Comprehensive Docker configuration for the WDG AI Development Environment, including service orchestration, networking, and container management.

Service Architecture

Core Services

yaml
services:
  # Nginx Proxy - Routes traffic to projects
  nginx:
    image: nginx:alpine
    ports:
      - "8880:80"    # HTTP
      - "8443:443"   # HTTPS
    volumes:
      - ./services/nginx:/etc/nginx
      - ./ssl:/etc/nginx/ssl

  # MySQL - Shared database for all projects
  mysql:
    image: mysql:8.0
    ports:
      - "3307:3306"
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    volumes:
      - mysql-data:/var/lib/mysql

  # Qdrant - Vector database for AI search
  qdrant:
    image: qdrant/qdrant:latest
    ports:
      - "6333:6333"  # REST API
      - "6334:6334"  # gRPC
    volumes:
      - qdrant-data:/qdrant/storage

  # MCP Server - AI assistant integration
  mcp-server:
    build: ./mcp-server
    ports:
      - "8765:8765"
    depends_on:
      - qdrant

  # WordPress Projects - Dynamic per project
  wordpress-{project}:
    build: ./services/wordpress
    environment:
      PHP_VERSION: ${PHP_VERSION:-8.2}
    volumes:
      - wordpress-{project}:/var/www/html

Project-Specific Services

Each project creates its own WordPress container:

yaml
# projects/my-site/docker-compose.yml
services:
  wdg-wp-my-site:
    build:
      context: ../../services/wordpress
      args:
        PHP_VERSION: "8.2"
    container_name: wdg-wp-my-site
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_NAME: wp_my_site
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
    volumes:
      - wordpress-my-site:/var/www/html
      - ./repositories/my-site:/var/www/html/wp-content
    networks:
      - wdg-network

Docker Compose Files

Main docker-compose.yml

Located at project root, manages core services:

yaml
version: '3.8'

networks:
  wdg-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.25.0.0/16

volumes:
  mysql-data:
  qdrant-data:

services:
  nginx:
    image: nginx:alpine
    container_name: wdg-nginx
    ports:
      - "8880:80"
      - "8443:443"
    volumes:
      - ./services/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./services/nginx/sites-enabled:/etc/nginx/sites-enabled:ro
      - ./ssl:/etc/nginx/ssl:ro
    networks:
      - wdg-network
    restart: unless-stopped

  mysql:
    image: mysql:8.0
    container_name: wdg-mysql
    ports:
      - "3307:3306"
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    volumes:
      - mysql-data:/var/lib/mysql
      - ./services/mysql/my.cnf:/etc/mysql/conf.d/custom.cnf:ro
    networks:
      - wdg-network
    restart: unless-stopped
    command: --default-authentication-plugin=mysql_native_password

  qdrant:
    image: qdrant/qdrant:latest
    container_name: wdg-qdrant
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant-data:/qdrant/storage
    environment:
      QDRANT__LOG_LEVEL: INFO
    networks:
      - wdg-network
    restart: unless-stopped

  mcp-server:
    build: ./mcp-server
    container_name: wdg-mcp-server
    ports:
      - "8765:8765"
    environment:
      MCP_HOST: 0.0.0.0
      MCP_PORT: 8765
      VECTOR_DB_HOST: qdrant
      VECTOR_DB_PORT: 6333
    volumes:
      - ./repositories:/repositories:ro
      - ./projects:/projects:ro
    networks:
      - wdg-network
    depends_on:
      - qdrant
    restart: unless-stopped

  phpmyadmin:
    image: phpmyadmin:latest
    container_name: wdg-phpmyadmin
    ports:
      - "8081:80"
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    networks:
      - wdg-network
    depends_on:
      - mysql
    restart: unless-stopped

Dockerfile Configurations

WordPress Dockerfile

services/wordpress/Dockerfile:

dockerfile
ARG PHP_VERSION=8.2
FROM wordpress:php${PHP_VERSION}-apache

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    unzip \
    libzip-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    && rm -rf /var/lib/apt/lists/*

# Configure PHP extensions
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) \
        gd \
        mysqli \
        pdo \
        pdo_mysql \
        zip \
        opcache

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Install WP-CLI
RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar \
    && chmod +x wp-cli.phar \
    && mv wp-cli.phar /usr/local/bin/wp

# Configure PHP
COPY php.ini /usr/local/etc/php/conf.d/custom.ini
COPY php-error-logging.ini /usr/local/etc/php/conf.d/error-logging.ini

# Configure Apache
RUN a2enmod rewrite headers expires

# Set proper permissions
RUN chown -R www-data:www-data /var/www/html

# Custom entrypoint
COPY docker-entrypoint-wrapper.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint-wrapper.sh

ENTRYPOINT ["docker-entrypoint-wrapper.sh"]
CMD ["apache2-foreground"]

MCP Server Dockerfile

mcp-server/Dockerfile:

dockerfile
FROM python:3.11-slim

WORKDIR /app

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

# Copy application
COPY server.py .
COPY tools/ ./tools/

# Create non-root user
RUN useradd -m -u 1000 mcp && chown -R mcp:mcp /app
USER mcp

EXPOSE 8765

CMD ["python", "server.py"]

Volume Management

Named Volumes

bash
# List volumes
docker volume ls | grep wdg

# Inspect volume
docker volume inspect wdg_mysql-data

# Backup volume
docker run --rm \
    -v wdg_mysql-data:/data \
    -v $(pwd)/backups:/backup \
    alpine tar czf /backup/mysql-data.tar.gz /data

# Restore volume
docker run --rm \
    -v wdg_mysql-data:/data \
    -v $(pwd)/backups:/backup \
    alpine sh -c "cd /data && tar xzf /backup/mysql-data.tar.gz --strip 1"

Bind Mounts

Project-specific directories are bind-mounted:

yaml
volumes:
  # WordPress core (named volume)
  - wordpress-my-site:/var/www/html

  # wp-content (bind mount)
  - ./repositories/my-site:/var/www/html/wp-content

  # Additional mounts
  - ./config/php.ini:/usr/local/etc/php/conf.d/custom.ini:ro
  - ./logs/my-site:/var/log/apache2

Networks

WDG Network

All services communicate via wdg-network:

yaml
networks:
  wdg-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.25.0.0/16
          gateway: 172.25.0.1

Network Inspection

bash
# View network
docker network inspect wdg-network

# List connected containers
docker network inspect wdg-network --format='{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'

Resource Limits

Container Limits

Set limits in project docker-compose.yml:

yaml
services:
  wordpress:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M

Global Daemon Configuration

/etc/docker/daemon.json:

json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 64000,
      "Soft": 64000
    }
  }
}

Build Optimization

Multi-Stage Builds

For production-optimized images:

dockerfile
# Build stage
FROM node:18 AS builder
WORKDIR /build
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM nginx:alpine
COPY --from=builder /build/dist /usr/share/nginx/html

Layer Caching

Optimize Dockerfile layer caching:

dockerfile
# Install dependencies first (cached layer)
COPY package*.json ./
RUN npm install

# Copy source (changes frequently)
COPY . .
RUN npm run build

Container Management

Start/Stop Services

bash
# Start all services
docker-compose up -d

# Start specific service
docker-compose up -d mysql qdrant

# Stop all services
docker-compose down

# Stop and remove volumes
docker-compose down -v

View Logs

bash
# All services
docker-compose logs -f

# Specific service
docker-compose logs -f mysql

# Last 100 lines
docker-compose logs --tail=100 nginx

Execute Commands

bash
# Enter container shell
docker exec -it wdg-mysql bash

# Run command
docker exec wdg-mysql mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "SHOW DATABASES;"

# WordPress WP-CLI
docker exec wdg-wp-my-site wp plugin list

Health Checks

Service Health Checks

yaml
services:
  mysql:
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  wordpress:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/"]
      interval: 30s
      timeout: 3s
      retries: 3

Check Health Status

bash
# View health status
docker ps --format "table {{.Names}}\t{{.Status}}"

# Wait for healthy
docker-compose up -d && docker-compose ps

# Check specific service
docker inspect --format='{{.State.Health.Status}}' wdg-mysql

Troubleshooting

Container Won't Start

bash
# View logs
docker logs wdg-wp-my-site

# Check for port conflicts
lsof -i :8443

# Verify configuration
docker-compose config

Permission Issues

bash
# Fix WordPress permissions
docker exec wdg-wp-my-site chown -R www-data:www-data /var/www/html/wp-content

# Fix from host
sudo chown -R $(id -u):$(id -g) projects/my-site

Network Issues

bash
# Recreate network
docker network rm wdg-network
docker network create wdg-network

# Reset DNS
docker-compose down && docker-compose up -d

See Also:

Released under the MIT License.