Set up docker for local and production
This commit is contained in:
parent
dac8fb4f2c
commit
a2f5a112d3
21 changed files with 426 additions and 0 deletions
41
.env.local
Normal file
41
.env.local
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Application
|
||||||
|
APP_NAME="Trip Planner"
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=base64:0YqH2qbjRZYGieiv8EiDVGUqEKLxT5Zwmv3nY9S75cc=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost:8000
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DB_CONNECTION=mysql
|
||||||
|
DB_HOST=database
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=trip_planner
|
||||||
|
DB_USERNAME=trip_user
|
||||||
|
DB_PASSWORD=secret
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
# Cache & Session
|
||||||
|
CACHE_DRIVER=redis
|
||||||
|
SESSION_DRIVER=redis
|
||||||
|
QUEUE_CONNECTION=redis
|
||||||
|
|
||||||
|
# Mail (using Mailpit for local development)
|
||||||
|
MAIL_MAILER=smtp
|
||||||
|
MAIL_HOST=mailpit
|
||||||
|
MAIL_PORT=1025
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDRESS="hello@tripplanner.local"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
# Frontend URL for CORS
|
||||||
|
FRONTEND_URL=http://localhost:5173
|
||||||
|
|
||||||
|
# API Settings
|
||||||
|
API_PREFIX=api
|
||||||
|
SANCTUM_STATEFUL_DOMAINS=localhost:5173
|
||||||
0
backend/bootstrap/cache/.gitignore
vendored
Normal file → Executable file
0
backend/bootstrap/cache/.gitignore
vendored
Normal file → Executable file
0
backend/storage/app/.gitignore
vendored
Normal file → Executable file
0
backend/storage/app/.gitignore
vendored
Normal file → Executable file
0
backend/storage/app/private/.gitignore
vendored
Normal file → Executable file
0
backend/storage/app/private/.gitignore
vendored
Normal file → Executable file
0
backend/storage/app/public/.gitignore
vendored
Normal file → Executable file
0
backend/storage/app/public/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/cache/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/cache/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/cache/data/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/cache/data/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/sessions/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/sessions/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/testing/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/testing/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/views/.gitignore
vendored
Normal file → Executable file
0
backend/storage/framework/views/.gitignore
vendored
Normal file → Executable file
0
backend/storage/logs/.gitignore
vendored
Normal file → Executable file
0
backend/storage/logs/.gitignore
vendored
Normal file → Executable file
79
docker-compose.dev.yml
Normal file
79
docker-compose.dev.yml
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ./frontend
|
||||||
|
dockerfile: ../docker/frontend/Dockerfile.dev
|
||||||
|
container_name: trip-planner-frontend-dev
|
||||||
|
ports:
|
||||||
|
- "5173:5173"
|
||||||
|
volumes:
|
||||||
|
- ./frontend:/app:Z
|
||||||
|
- node_modules:/app/node_modules
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
networks:
|
||||||
|
- trip-planner-network
|
||||||
|
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: ../docker/backend/Dockerfile.dev
|
||||||
|
container_name: trip-planner-backend-dev
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
volumes:
|
||||||
|
- ./backend:/var/www/html:Z
|
||||||
|
- vendor:/var/www/html/vendor
|
||||||
|
env_file:
|
||||||
|
- .env.local
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
- redis
|
||||||
|
networks:
|
||||||
|
- trip-planner-network
|
||||||
|
|
||||||
|
database:
|
||||||
|
image: docker.io/library/mariadb:11
|
||||||
|
container_name: trip-planner-db-dev
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-secret}
|
||||||
|
MYSQL_DATABASE: ${DB_DATABASE:-trip_planner}
|
||||||
|
MYSQL_USER: ${DB_USERNAME:-trip_user}
|
||||||
|
MYSQL_PASSWORD: ${DB_PASSWORD:-secret}
|
||||||
|
volumes:
|
||||||
|
- db-data:/var/lib/mysql
|
||||||
|
networks:
|
||||||
|
- trip-planner-network
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: docker.io/library/redis:alpine
|
||||||
|
container_name: trip-planner-redis-dev
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
networks:
|
||||||
|
- trip-planner-network
|
||||||
|
|
||||||
|
mailpit:
|
||||||
|
image: docker.io/axllent/mailpit:latest
|
||||||
|
container_name: trip-planner-mailpit-dev
|
||||||
|
ports:
|
||||||
|
- "1025:1025"
|
||||||
|
- "8025:8025"
|
||||||
|
networks:
|
||||||
|
- trip-planner-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
trip-planner-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db-data:
|
||||||
|
redis-data:
|
||||||
|
node_modules:
|
||||||
|
vendor:
|
||||||
58
docker-compose.prod.yml
Normal file
58
docker-compose.prod.yml
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ./frontend
|
||||||
|
dockerfile: ../docker/frontend/Dockerfile.prod
|
||||||
|
container_name: trip-planner-frontend
|
||||||
|
ports:
|
||||||
|
- "${FRONTEND_PORT:-80}:80"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- trip-planner-network
|
||||||
|
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: ../docker/backend/Dockerfile.prod
|
||||||
|
container_name: trip-planner-backend
|
||||||
|
ports:
|
||||||
|
- "${BACKEND_PORT:-8080}:80"
|
||||||
|
environment:
|
||||||
|
APP_ENV: production
|
||||||
|
APP_DEBUG: false
|
||||||
|
APP_URL: ${APP_URL}
|
||||||
|
DB_CONNECTION: mysql
|
||||||
|
DB_HOST: ${DB_HOST}
|
||||||
|
DB_PORT: ${DB_PORT:-3306}
|
||||||
|
DB_DATABASE: ${DB_DATABASE}
|
||||||
|
DB_USERNAME: ${DB_USERNAME}
|
||||||
|
DB_PASSWORD: ${DB_PASSWORD}
|
||||||
|
REDIS_HOST: redis
|
||||||
|
REDIS_PORT: 6379
|
||||||
|
CACHE_DRIVER: redis
|
||||||
|
QUEUE_CONNECTION: redis
|
||||||
|
SESSION_DRIVER: redis
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- trip-planner-network
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: docker.io/library/redis:alpine
|
||||||
|
container_name: trip-planner-redis
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
command: redis-server --appendonly yes
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- trip-planner-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
trip-planner-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redis-data:
|
||||||
43
docker/backend/Dockerfile.dev
Normal file
43
docker/backend/Dockerfile.dev
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
FROM php:8.3-fpm-alpine
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
git \
|
||||||
|
curl \
|
||||||
|
libpng-dev \
|
||||||
|
oniguruma-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
zip \
|
||||||
|
unzip \
|
||||||
|
nodejs \
|
||||||
|
npm \
|
||||||
|
shadow
|
||||||
|
|
||||||
|
# Install PHP extensions
|
||||||
|
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
|
||||||
|
|
||||||
|
# Install Composer
|
||||||
|
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
# Create developer user with UID 1000 (same as host user)
|
||||||
|
RUN adduser -u 1000 -s /bin/sh -D developer
|
||||||
|
|
||||||
|
# Create storage and bootstrap/cache directories
|
||||||
|
RUN mkdir -p storage/app/public storage/framework/cache storage/framework/sessions storage/framework/views storage/logs bootstrap/cache
|
||||||
|
|
||||||
|
# Change ownership to developer user
|
||||||
|
RUN chown -R developer:developer /var/www/html
|
||||||
|
|
||||||
|
# Set proper permissions for Laravel directories
|
||||||
|
RUN chmod -R 775 storage bootstrap/cache
|
||||||
|
|
||||||
|
# Switch to developer user
|
||||||
|
USER developer
|
||||||
|
|
||||||
|
# Expose port 8000 for artisan serve
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Start Laravel development server with composer install
|
||||||
|
CMD sh -c "composer install && php artisan key:generate --force && php artisan serve --host=0.0.0.0 --port=8000"
|
||||||
69
docker/backend/Dockerfile.prod
Normal file
69
docker/backend/Dockerfile.prod
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Build stage
|
||||||
|
FROM php:8.3-fpm-alpine AS builder
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
libpng-dev \
|
||||||
|
oniguruma-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
zip \
|
||||||
|
unzip
|
||||||
|
|
||||||
|
# Install PHP extensions
|
||||||
|
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd opcache
|
||||||
|
|
||||||
|
# Install Composer
|
||||||
|
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
# Copy composer files
|
||||||
|
COPY composer.json composer.lock ./
|
||||||
|
|
||||||
|
# Install dependencies (no dev)
|
||||||
|
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist
|
||||||
|
|
||||||
|
# Copy application
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Generate optimized autoloader
|
||||||
|
RUN composer dump-autoload --optimize --classmap-authoritative
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM php:8.3-fpm-alpine
|
||||||
|
|
||||||
|
# Install runtime dependencies
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
libpng-dev \
|
||||||
|
oniguruma-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
nginx \
|
||||||
|
supervisor
|
||||||
|
|
||||||
|
# Install PHP extensions
|
||||||
|
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd opcache
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
# Copy application from builder
|
||||||
|
COPY --from=builder /var/www/html .
|
||||||
|
|
||||||
|
# Copy nginx config
|
||||||
|
COPY docker/nginx/backend.conf /etc/nginx/http.d/default.conf
|
||||||
|
|
||||||
|
# Copy supervisord config
|
||||||
|
COPY docker/backend/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
|
# Configure PHP-FPM
|
||||||
|
RUN echo "opcache.enable=1" >> /usr/local/etc/php/conf.d/opcache.ini \
|
||||||
|
&& echo "opcache.memory_consumption=128" >> /usr/local/etc/php/conf.d/opcache.ini \
|
||||||
|
&& echo "opcache.max_accelerated_files=10000" >> /usr/local/etc/php/conf.d/opcache.ini \
|
||||||
|
&& echo "opcache.validate_timestamps=0" >> /usr/local/etc/php/conf.d/opcache.ini
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
|
||||||
|
|
||||||
|
# Expose port 80
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||||
21
docker/backend/supervisord.conf
Normal file
21
docker/backend/supervisord.conf
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
|
||||||
|
[program:php-fpm]
|
||||||
|
command=/usr/local/sbin/php-fpm -F
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:nginx]
|
||||||
|
command=/usr/sbin/nginx -g "daemon off;"
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
18
docker/frontend/Dockerfile.dev
Normal file
18
docker/frontend/Dockerfile.dev
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Install global dependencies as root
|
||||||
|
RUN npm install -g vite
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Change ownership of /app to node user (UID 1000)
|
||||||
|
RUN chown -R node:node /app
|
||||||
|
|
||||||
|
# Switch to node user (UID 1000, same as host user)
|
||||||
|
USER node
|
||||||
|
|
||||||
|
# Expose Vite dev server port
|
||||||
|
EXPOSE 5173
|
||||||
|
|
||||||
|
# Start development server
|
||||||
|
CMD ["sh", "-c", "npm install && npm run dev -- --host 0.0.0.0"]
|
||||||
30
docker/frontend/Dockerfile.prod
Normal file
30
docker/frontend/Dockerfile.prod
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Build stage
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm ci --only=production
|
||||||
|
|
||||||
|
# Copy app files
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the app
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Copy built app from builder stage
|
||||||
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Copy nginx config
|
||||||
|
COPY docker/nginx/frontend.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# Expose port 80
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
40
docker/nginx/backend.conf
Normal file
40
docker/nginx/backend.conf
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
root /var/www/html/public;
|
||||||
|
index index.php;
|
||||||
|
|
||||||
|
# Disable access log for performance
|
||||||
|
access_log off;
|
||||||
|
error_log /var/log/nginx/error.log error;
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
try_files $uri =404;
|
||||||
|
fastcgi_pass 127.0.0.1:9000;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_buffer_size 32k;
|
||||||
|
fastcgi_buffers 8 16k;
|
||||||
|
fastcgi_read_timeout 240;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /\.(?!well-known).* {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
}
|
||||||
27
docker/nginx/frontend.conf
Normal file
27
docker/nginx/frontend.conf
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue