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}'
| Port | Default | Description |
|---|
APP_PORT | 80 | Web application HTTP port |
VITE_PORT | 5173 | Vite 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
# 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
# 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