Deploy Zoo Arcadia in containerized environments using Docker for consistent development and production setups.
Prerequisites
Ensure you have Docker and Docker Compose installed:
Docker Version 20.10 or higher
Docker Compose Version 2.0 or higher
Verify installation:
docker --version
docker compose version
Architecture Overview
The Docker setup consists of three services:
Docker Compose Configuration
The docker-compose.yml defines the complete stack:
version : '3.8'
services :
# PHP + Apache Web Server
web :
build :
context : .
dockerfile : Dockerfile
container_name : zoo-arcadia-web
ports :
- "8080:80"
volumes :
- ./public:/var/www/html/public
- ./App:/var/www/html/App
- ./includes:/var/www/html/includes
- ./config.php:/var/www/html/config.php
- ./.env:/var/www/html/.env
depends_on :
- db
environment :
- DB_HOST=db
- DB_NAME=zoo_arcadia
- DB_USER=zoo_user
- DB_PASS=zoo_password
networks :
- zoo-network
# MariaDB Database
db :
image : mariadb:11.4
container_name : zoo-arcadia-db
ports :
- "3306:3306"
environment :
MYSQL_ROOT_PASSWORD : root_password
MYSQL_DATABASE : zoo_arcadia
MYSQL_USER : zoo_user
MYSQL_PASSWORD : zoo_password
volumes :
- mysql_data:/var/lib/mysql
- ./database:/docker-entrypoint-initdb.d
networks :
- zoo-network
command : --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes :
mysql_data :
networks :
zoo-network :
driver : bridge
Service Breakdown
Web Service
Database Service
Network
Container : zoo-arcadia-web
Base Image : Custom Dockerfile (PHP 8.2 + Apache)
Port : 8080 (host) → 80 (container)
Volumes : Code directories mounted for live editing
Environment : Database credentials
The web container includes:
PHP extensions (GD, PDO MySQL, Zip)
Apache with mod_rewrite enabled
Composer dependencies
Node.js 18 for asset compilation
Container : zoo-arcadia-db
Image : MariaDB 11.4 (official)
Port : 3306 (both host and container)
Persistent Storage : mysql_data volume
Auto-initialization : SQL scripts in database/ directory
Features:
UTF-8mb4 character set (emoji support)
MySQL native password authentication
Auto-runs migration scripts on first start
Network : zoo-network
Driver : Bridge
Purpose : Internal service communication
Services communicate using container names:
Dockerfile
The custom Dockerfile builds the web application container:
# Base image: PHP 8.2 with Apache
FROM php:8.2-apache
# Install PHP extensions
RUN apt-get update && apt-get install -y \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libzip-dev \
unzip \
git \
curl \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd pdo pdo_mysql zip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js 18
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y nodejs
# Enable Apache modules
RUN a2enmod rewrite headers
# Copy Apache configuration
COPY docker/apache-config.conf /etc/apache2/sites-available/000-default.conf
# Set working directory
WORKDIR /var/www/html
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Install PHP dependencies
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction
# Install Node.js dependencies
COPY package.json package-lock.json ./
RUN npm ci --production=false
# Copy application files
COPY . .
# Build assets (CSS and JS)
RUN npx gulp buildCss || (npm run css || echo "Warning: CSS compilation failed" ) \
&& npx gulp buildJs || echo "Warning: JS build failed"
# Set permissions
RUN chown -R www-data:www-data /var/www/html \
&& chmod -R 755 /var/www/html
EXPOSE 80
CMD [ "apache2-foreground" ]
Getting Started with Docker
Configure Environment
Ensure you have the Docker-specific .env file: Or use the helper script (Windows): Key settings for Docker: DB_HOST = db # Container name, not localhost
DB_NAME = zoo_arcadia
DB_USER = zoo_user
DB_PASS = zoo_password
Build Containers
Build the Docker images: First build may take 5-10 minutes as it downloads base images and compiles assets.
Start Services
Start all containers: The -d flag runs containers in detached mode (background).
Verify Services
Check container status: You should see: NAME STATUS PORTS
zoo-arcadia-web Up 0.0.0.0:8080->80/tcp
zoo-arcadia-db Up 0.0.0.0:3306->3306/tcp
Access the Application
Open your browser to: The application should be running with a fully initialized database.
Accessing Services
Web Application
Database Connection
Connect to MariaDB from your host machine:
mysql -h 127.0.0.1 -P 3306 -u zoo_user -p
# Password: zoo_password
Container Logs
View real-time logs:
All Services
Web Only
Database Only
Volume Management
Docker uses volumes for persistent data and development:
Development Volumes (Bind Mounts)
These directories are mounted from your host machine for live editing:
Host Path Container Path Purpose ./public/var/www/html/publicFrontend assets ./App/var/www/html/AppPHP application code ./includes/var/www/html/includesShared PHP includes ./config.php/var/www/html/config.phpConfiguration ./.env/var/www/html/.envEnvironment variables
Changes to these files on your host are immediately reflected in the container.
Persistent Volume
The database uses a Docker volume for data persistence:
# List volumes
docker volume ls
# Inspect the database volume
docker volume inspect zoo-arcadia_mysql_data
# Remove volume (⚠️ destroys all data)
docker volume rm zoo-arcadia_mysql_data
Database Migrations in Docker
The database is automatically initialized on first run using the /docker-entrypoint-initdb.d directory.
Auto-initialization
SQL scripts in database/ are executed in alphabetical order:
01_init.sql - Create database and users
02_tables.sql - Create all tables
03_constraints.sql - Add foreign keys
04_indexes.sql - Create indexes (if exists)
05_procedures.sql - Stored procedures (if exists)
06_seed_data.sql - Initial data
07_cleanup.sql - Cleanup tasks (if exists)
Manual Migration
To re-run migrations:
Remove Database Volume
docker volume rm zoo-arcadia_mysql_data
Restart Services
The database will be recreated automatically.
Execute SQL Scripts Manually
# Copy SQL file into container
docker compose cp database/02_tables.sql db:/tmp/
# Execute the script
docker compose exec db mysql -u root -proot_password zoo_arcadia < /tmp/02_tables.sql
Common Docker Commands
Start/Stop
Build/Rebuild
Execute Commands
Inspect/Debug
# Start all services
docker compose up -d
# Stop all services
docker compose down
# Stop and remove volumes
docker compose down -v
# Restart a specific service
docker compose restart web
# Build images
docker compose build
# Rebuild without cache
docker compose build --no-cache
# Build and start
docker compose up -d --build
# Shell into web container
docker compose exec web bash
# Shell into database container
docker compose exec db bash
# Run Composer
docker compose exec web composer install
# Run Gulp tasks
docker compose exec web npx gulp buildCss
# View logs
docker compose logs -f
# Check resource usage
docker stats
# List containers
docker compose ps
# Inspect a container
docker inspect zoo-arcadia-web
Troubleshooting
Check logs :docker compose logs web
docker compose logs db
Common causes :
Port already in use (change ports in docker-compose.yml)
Insufficient disk space
Missing .env file
Database Connection Failed
Verify database is running :Check credentials :
Ensure .env has DB_HOST=db (not localhost)
Verify credentials match docker-compose.yml
Test connection :docker compose exec web php -r "echo new PDO('mysql:host=db;dbname=zoo_arcadia', 'zoo_user', 'zoo_password');"
Rebuild with fresh dependencies :docker compose down
docker compose build --no-cache
docker compose up -d
Check Node.js installation :docker compose exec web node --version
docker compose exec web npm --version
For code changes : Should be immediate (using bind mounts)For config changes : Restart the web servicedocker compose restart web
For Dockerfile changes : Rebuilddocker compose up -d --build
Change the host port in docker-compose.yml:services :
web :
ports :
- "8081:80" # Changed from 8080
Then restart: docker compose down
docker compose up -d
Production Deployment
For production deployments, consider these best practices:
Use Production Environment
Update .env for production: APP_ENV = production
DB_PASS =< strong-password >
Remove Development Volumes
Don’t mount source code in production. Remove bind mounts from docker-compose.yml: # Remove these lines:
volumes :
- ./public:/var/www/html/public
- ./App:/var/www/html/App
Use Docker Secrets
For sensitive data, use Docker secrets instead of environment variables.
Enable HTTPS
Use a reverse proxy (Nginx, Traefik) with SSL certificates.
Set Resource Limits
Add resource constraints: services :
web :
deploy :
resources :
limits :
cpus : '2'
memory : 1G
Never expose the database port (3306) to the internet in production.
Next Steps
Database Schema Explore the database structure
Environment Setup Configure local development without Docker
Asset Pipeline Learn about asset compilation
Environment Setup Set up local development environment