Skip to main content

Overview

Wecode includes a Docker Compose configuration powered by Laravel Sail, which provides a complete development and production environment with all necessary services pre-configured.

Services Architecture

The compose.yaml file defines three main services:
laravel.test  → PHP 8.4 + Laravel application
mariadb       → MariaDB 11 database
redis         → Redis for caching and queues

compose.yaml Configuration

Service: laravel.test

The main application service running PHP and Laravel.

Build Configuration

build:
  context: './vendor/laravel/sail/runtimes/8.4'
  dockerfile: Dockerfile
  args:
    WWWGROUP: '${WWWGROUP}'
    MYSQL_CLIENT: mariadb-client
  • Context: Uses Laravel Sail’s PHP 8.4 runtime
  • Image: sail-8.4/app
  • MySQL Client: MariaDB client for database operations

Port Mappings

ports:
  - '${APP_PORT:-80}:80'
  - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
PortDefaultDescription
APP_PORT80Web application HTTP port
VITE_PORT5173Vite development server (for asset compilation)

Environment Variables

environment:
  WWWUSER: '${WWWUSER}'
  LARAVEL_SAIL: 1
  XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
  XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
  IGNITION_LOCAL_SITES_PATH: '${PWD}'
  • WWWUSER: User ID for file permissions
  • LARAVEL_SAIL: Indicates running in Sail environment
  • XDEBUG_MODE: PHP debugging (off by default)
  • XDEBUG_CONFIG: Xdebug connection settings

Volume Mounts

volumes:
  - '.:/var/www/html'
Mounts the current directory to /var/www/html in the container, allowing live code updates.

Service: mariadb

Database service using MariaDB 11.

Port Mapping

ports:
  - '${FORWARD_DB_PORT:-3306}:3306'
  • FORWARD_DB_PORT: Default 3306 (MySQL/MariaDB default)
  • Allows external connections to database (for management tools)

Environment Variables

environment:
  MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
  MYSQL_ROOT_HOST: '%'
  MYSQL_DATABASE: '${DB_DATABASE}'
  MYSQL_USER: '${DB_USERNAME}'
  MYSQL_PASSWORD: '${DB_PASSWORD}'
  MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
  • MYSQL_ROOT_PASSWORD: Root password from .env
  • MYSQL_ROOT_HOST: Allows connections from any host
  • MYSQL_DATABASE: Database name from .env
  • MYSQL_USER/PASSWORD: Application database credentials

Volume Mounts

volumes:
  - 'sail-mariadb:/var/lib/mysql'
  - './vendor/laravel/sail/database/mariadb/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
  • sail-mariadb: Persistent volume for database files
  • init script: Creates testing database on first startup

Health Check

healthcheck:
  test:
    - CMD
    - healthcheck.sh
    - '--connect'
    - '--innodb_initialized'
  retries: 3
  timeout: 5s
Ensures database is fully initialized before application starts.

Service: redis

Cache and queue backend using Redis.

Port Mapping

ports:
  - '${FORWARD_REDIS_PORT:-6379}:6379'
  • FORWARD_REDIS_PORT: Default 6379 (Redis default)

Volume Mounts

volumes:
  - 'sail-redis:/data'
Persistent storage for Redis data.

Health Check

healthcheck:
  test:
    - CMD
    - redis-cli
    - ping
  retries: 3
  timeout: 5s

Environment Configuration

Required .env Variables

Create or update your .env file with these Docker-specific settings:
# Application
APP_PORT=80
APP_URL=http://localhost

# Database
DB_CONNECTION=mysql
DB_HOST=mariadb
DB_PORT=3306
DB_DATABASE=wecode
DB_USERNAME=sail
DB_PASSWORD=password

# Redis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

# Queue
QUEUE_CONNECTION=redis

# Cache
CACHE_DRIVER=redis
SESSION_DRIVER=redis

# Docker Sail
WWWGROUP=1000
WWWUSER=1000
FORWARD_DB_PORT=3306
FORWARD_REDIS_PORT=6379

# Vite
VITE_PORT=5173

# Xdebug (optional, for debugging)
SAIL_XDEBUG_MODE=off

Port Customization

To avoid port conflicts, customize in .env:
APP_PORT=8080          # Use port 8080 instead of 80
FORWARD_DB_PORT=3307   # Use port 3307 for database
FORWARD_REDIS_PORT=6380 # Use port 6380 for Redis

Installation Steps

1. Prerequisites

# Install Docker Engine
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Add user to docker group
sudo usermod -aG docker $USER

# Install Docker Compose (if not included)
sudo apt-get install docker-compose-plugin

# Verify installation
docker --version
docker compose version

2. Clone and Configure

# Clone repository
git clone https://github.com/truongan/wecode.git
cd wecode

# Copy environment file
cp .env.example .env

# Edit .env file
nano .env

3. Build and Start Services

# Build containers (first time only)
docker compose build

# Start all services
docker compose up -d

# Check status
docker compose ps
Expected output:
NAME                IMAGE           STATUS          PORTS
wecode-laravel.test-1  sail-8.4/app    Up 30 seconds   0.0.0.0:80->80/tcp
wecode-mariadb-1       mariadb:11      Up 30 seconds   0.0.0.0:3306->3306/tcp
wecode-redis-1         redis:alpine    Up 30 seconds   0.0.0.0:6379->6379/tcp

4. Initialize Application

# Install dependencies
docker compose exec laravel.test composer install

# Generate application key
docker compose exec laravel.test php artisan key:generate

# Run migrations
docker compose exec laravel.test php artisan migrate:refresh

# Seed database
docker compose exec laravel.test php artisan db:seed --class=installation_seeding

# Create admin user
docker compose exec laravel.test php artisan add_admin admin [email protected] password123

5. Set Up Docker for Code Execution

Wecode needs Docker-in-Docker (DinD) access to execute student code in isolated containers.
# Mount Docker socket (development only)
docker compose down
Add to laravel.test service in compose.yaml:
volumes:
  - '.:/var/www/html'
  - '/var/run/docker.sock:/var/run/docker.sock'  # Add this line
# Restart services
docker compose up -d

# Verify Docker access from container
docker compose exec laravel.test docker ps

Using Laravel Sail

Laravel Sail provides a convenient CLI for Docker Compose operations.

Sail Alias Setup

# Add to ~/.bashrc or ~/.zshrc
alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail'

# Reload shell
source ~/.bashrc

Common Sail Commands

# Start services
sail up -d

# Stop services
sail down

# View logs
sail logs -f

# Run artisan commands
sail artisan migrate
sail artisan queue:work

# Run composer commands
sail composer install
sail composer update

# Access shell
sail shell

# Run tests
sail test

# Access database
sail mariadb

Managing Services

Start/Stop Services

# Start all services
docker compose up -d

# Start specific service
docker compose up -d mariadb

# Stop all services
docker compose down

# Stop and remove volumes (WARNING: deletes data)
docker compose down -v

View Logs

# All services
docker compose logs -f

# Specific service
docker compose logs -f laravel.test
docker compose logs -f mariadb

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

Execute Commands

# Run command in container
docker compose exec laravel.test php artisan migrate

# Access bash shell
docker compose exec laravel.test bash

# Run as specific user
docker compose exec --user sail laravel.test bash

Restart Services

# Restart all services
docker compose restart

# Restart specific service
docker compose restart laravel.test

Production Deployment

Security Hardening

Do not mount Docker socket in production. Use Docker API with proper authentication instead.
# Remove or comment out in production
volumes:
  # - '/var/run/docker.sock:/var/run/docker.sock'  # DEVELOPMENT ONLY

Performance Optimization

# Build optimized containers
docker compose build --no-cache

# Use production environment
APP_ENV=production
APP_DEBUG=false
Optimize Laravel:
docker compose exec laravel.test php artisan config:cache
docker compose exec laravel.test php artisan route:cache
docker compose exec laravel.test php artisan view:cache

Resource Limits

Add resource limits in compose.yaml:
laravel.test:
  deploy:
    resources:
      limits:
        cpus: '2.0'
        memory: 2G
      reservations:
        cpus: '1.0'
        memory: 1G

Backup and Persistence

Volume Backup

# Backup database volume
docker run --rm \
  -v wecode_sail-mariadb:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/mariadb-backup.tar.gz /data

# Backup Redis volume
docker run --rm \
  -v wecode_sail-redis:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/redis-backup.tar.gz /data

Database Dump

# Export database
docker compose exec mariadb mysqldump -u sail -p wecode > backup.sql

# Import database
docker compose exec -T mariadb mysql -u sail -p wecode < backup.sql

Troubleshooting

Container Won’t Start

# Check logs
docker compose logs laravel.test

# Rebuild container
docker compose build --no-cache laravel.test
docker compose up -d

Port Already in Use

# Find process using port
sudo lsof -i :80

# Change port in .env
APP_PORT=8080

# Restart services
docker compose down
docker compose up -d

Permission Errors

# Fix file ownership
sudo chown -R $USER:$USER .

# Set WWWUSER in .env
WWWUSER=$(id -u)
WWWGROUP=$(id -g)

Database Connection Failed

# Check if MariaDB is healthy
docker compose ps mariadb

# Test connection
docker compose exec laravel.test php artisan migrate:status

# Verify DB_HOST in .env
DB_HOST=mariadb  # Must be service name

Next Steps

Build docs developers (and LLMs) love