Add Docker support with Dockerfile, docker-compose, and entrypoint script; update .gitignore and add .dockerignore
This commit is contained in:
51
.dockerignore
Normal file
51
.dockerignore
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# ── Git ──────────────────────────────────────
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.gitattributes
|
||||||
|
|
||||||
|
# ── Env files (use .env.docker instead) ─────
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# ── Node / build artifacts ───────────────────
|
||||||
|
node_modules
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# ── Laravel local storage (mounted as volume)
|
||||||
|
storage/logs/*
|
||||||
|
storage/framework/cache/*
|
||||||
|
storage/framework/sessions/*
|
||||||
|
storage/framework/views/*
|
||||||
|
storage/app/private/*
|
||||||
|
|
||||||
|
# ── Laravel bootstrap cache ──────────────────
|
||||||
|
bootstrap/cache/*.php
|
||||||
|
|
||||||
|
# ── SQLite database (mounted as volume) ──────
|
||||||
|
database/database.sqlite
|
||||||
|
|
||||||
|
# ── Compiled assets (rebuilt in Dockerfile) ──
|
||||||
|
public/build
|
||||||
|
public/hot
|
||||||
|
|
||||||
|
# ── Tests / dev tooling ──────────────────────
|
||||||
|
tests
|
||||||
|
phpunit.xml
|
||||||
|
.editorconfig
|
||||||
|
.php-cs-fixer*
|
||||||
|
|
||||||
|
# ── IDE / OS ─────────────────────────────────
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# ── Docker config itself ─────────────────────
|
||||||
|
Dockerfile
|
||||||
|
docker-compose*.yml
|
||||||
|
docker/
|
||||||
|
|
||||||
|
# ── Claude / project meta ────────────────────
|
||||||
|
.claude
|
||||||
|
README.md
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
|||||||
.env
|
.env
|
||||||
.env.backup
|
.env.backup
|
||||||
.env.production
|
.env.production
|
||||||
|
.env.docker
|
||||||
.phpactor.json
|
.phpactor.json
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
/.fleet
|
/.fleet
|
||||||
|
|||||||
118
Dockerfile
Normal file
118
Dockerfile
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# ─────────────────────────────────────────────
|
||||||
|
# Stage 1 – Build frontend assets (Node)
|
||||||
|
# ─────────────────────────────────────────────
|
||||||
|
FROM node:22-alpine AS node-builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --ignore-scripts
|
||||||
|
|
||||||
|
COPY vite.config.js ./
|
||||||
|
COPY resources/ resources/
|
||||||
|
COPY public/ public/
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────
|
||||||
|
# Stage 2 – PHP runtime
|
||||||
|
# ─────────────────────────────────────────────
|
||||||
|
FROM php:8.3-fpm-alpine AS runtime
|
||||||
|
|
||||||
|
# ── System packages ──────────────────────────
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
nginx \
|
||||||
|
supervisor \
|
||||||
|
sqlite \
|
||||||
|
curl \
|
||||||
|
git \
|
||||||
|
unzip \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-turbo-dev \
|
||||||
|
freetype-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libzip-dev \
|
||||||
|
icu-dev \
|
||||||
|
oniguruma-dev
|
||||||
|
|
||||||
|
# ── PHP extensions ───────────────────────────
|
||||||
|
# GD (needed by dompdf for image rendering)
|
||||||
|
RUN docker-php-ext-configure gd \
|
||||||
|
--with-freetype \
|
||||||
|
--with-jpeg \
|
||||||
|
&& docker-php-ext-install -j"$(nproc)" \
|
||||||
|
pdo \
|
||||||
|
pdo_sqlite \
|
||||||
|
mbstring \
|
||||||
|
fileinfo \
|
||||||
|
xml \
|
||||||
|
dom \
|
||||||
|
bcmath \
|
||||||
|
zip \
|
||||||
|
intl \
|
||||||
|
gd \
|
||||||
|
opcache \
|
||||||
|
pcntl
|
||||||
|
|
||||||
|
# ── Composer ─────────────────────────────────
|
||||||
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
|
# ── App directory ────────────────────────────
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
# Install PHP dependencies first (better layer caching)
|
||||||
|
COPY composer.json composer.lock ./
|
||||||
|
RUN composer install \
|
||||||
|
--no-dev \
|
||||||
|
--no-interaction \
|
||||||
|
--no-scripts \
|
||||||
|
--optimize-autoloader \
|
||||||
|
--prefer-dist
|
||||||
|
|
||||||
|
# Copy full application
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Inject compiled frontend assets from Stage 1
|
||||||
|
COPY --from=node-builder /app/public/build public/build/
|
||||||
|
|
||||||
|
# ── Docker helper files ───────────────────────
|
||||||
|
COPY docker/nginx.conf /etc/nginx/nginx.conf
|
||||||
|
COPY docker/supervisord.conf /etc/supervisord.conf
|
||||||
|
COPY docker/entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
# ── File system ──────────────────────────────
|
||||||
|
RUN mkdir -p \
|
||||||
|
storage/app/private/talent-assets \
|
||||||
|
storage/logs \
|
||||||
|
storage/framework/cache \
|
||||||
|
storage/framework/sessions \
|
||||||
|
storage/framework/views \
|
||||||
|
bootstrap/cache \
|
||||||
|
database \
|
||||||
|
&& chown -R www-data:www-data \
|
||||||
|
storage \
|
||||||
|
bootstrap/cache \
|
||||||
|
database \
|
||||||
|
&& chmod -R 775 \
|
||||||
|
storage \
|
||||||
|
bootstrap/cache \
|
||||||
|
database
|
||||||
|
|
||||||
|
# ── PHP-FPM: run as www-data ─────────────────
|
||||||
|
RUN sed -i 's/user = www-data/user = www-data/' /usr/local/etc/php-fpm.d/www.conf 2>/dev/null || true \
|
||||||
|
&& sed -i 's/group = www-data/group = www-data/' /usr/local/etc/php-fpm.d/www.conf 2>/dev/null || true
|
||||||
|
|
||||||
|
# ── OPcache tuning ───────────────────────────
|
||||||
|
RUN { \
|
||||||
|
echo "opcache.enable=1"; \
|
||||||
|
echo "opcache.memory_consumption=128"; \
|
||||||
|
echo "opcache.interned_strings_buffer=8"; \
|
||||||
|
echo "opcache.max_accelerated_files=10000"; \
|
||||||
|
echo "opcache.validate_timestamps=0"; \
|
||||||
|
echo "opcache.fast_shutdown=1"; \
|
||||||
|
} > /usr/local/etc/php/conf.d/opcache.ini
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
6
How-To.txt
Normal file
6
How-To.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
git clone this repository
|
||||||
|
composer install
|
||||||
|
#php artisan key:generate
|
||||||
|
touch database/database.sqlite && php artisan migrate
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
38
docker-compose.yml
Normal file
38
docker-compose.yml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: kol-manager:latest
|
||||||
|
container_name: kol-manager
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- "${APP_PORT:-8080}:80"
|
||||||
|
|
||||||
|
# Mount .env.docker as the runtime .env
|
||||||
|
env_file:
|
||||||
|
- .env.docker
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Persist the SQLite database across container rebuilds
|
||||||
|
- kol_database:/var/www/html/database
|
||||||
|
|
||||||
|
# Persist uploaded files (talent assets, etc.)
|
||||||
|
- kol_storage:/var/www/html/storage
|
||||||
|
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost/up"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Named volume for SQLite database
|
||||||
|
kol_database:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
# Named volume for all file uploads / logs / cache
|
||||||
|
kol_storage:
|
||||||
|
driver: local
|
||||||
59
docker/entrypoint.sh
Normal file
59
docker/entrypoint.sh
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
APP_DIR=/var/www/html
|
||||||
|
|
||||||
|
echo "──────────────────────────────────────────"
|
||||||
|
echo " KOL Manager – Container Start"
|
||||||
|
echo "──────────────────────────────────────────"
|
||||||
|
|
||||||
|
cd "$APP_DIR"
|
||||||
|
|
||||||
|
# ── 1. Bootstrap .env ───────────────────────
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
if [ -f .env.docker ]; then
|
||||||
|
cp .env.docker .env
|
||||||
|
echo "[env] Copied .env.docker → .env"
|
||||||
|
else
|
||||||
|
echo "[env] WARNING: No .env or .env.docker found!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 2. Generate APP_KEY if empty ────────────
|
||||||
|
if grep -qE '^APP_KEY=$' .env 2>/dev/null; then
|
||||||
|
echo "[key] Generating application key…"
|
||||||
|
php artisan key:generate --force --quiet
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 3. Ensure SQLite database file exists ───
|
||||||
|
if [ ! -f database/database.sqlite ]; then
|
||||||
|
echo "[db] Creating SQLite database file…"
|
||||||
|
touch database/database.sqlite
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 4. Fix ownership / permissions ──────────
|
||||||
|
chown -R www-data:www-data \
|
||||||
|
storage \
|
||||||
|
bootstrap/cache \
|
||||||
|
database
|
||||||
|
chmod -R 775 \
|
||||||
|
storage \
|
||||||
|
bootstrap/cache \
|
||||||
|
database
|
||||||
|
|
||||||
|
# ── 5. Run migrations ────────────────────────
|
||||||
|
echo "[migrate] Running database migrations…"
|
||||||
|
php artisan migrate --force --no-interaction
|
||||||
|
|
||||||
|
# ── 6. Cache config / routes / views ────────
|
||||||
|
echo "[optimize] Caching configuration…"
|
||||||
|
php artisan config:cache --quiet
|
||||||
|
php artisan route:cache --quiet
|
||||||
|
php artisan view:cache --quiet
|
||||||
|
|
||||||
|
echo "──────────────────────────────────────────"
|
||||||
|
echo " All checks passed. Starting services…"
|
||||||
|
echo "──────────────────────────────────────────"
|
||||||
|
|
||||||
|
# ── 7. Hand off to Supervisor ────────────────
|
||||||
|
exec supervisord -c /etc/supervisord.conf
|
||||||
74
docker/nginx.conf
Normal file
74
docker/nginx.conf
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
user www-data;
|
||||||
|
worker_processes auto;
|
||||||
|
pid /run/nginx.pid;
|
||||||
|
error_log /dev/stderr warn;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
multi_accept on;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# Logging to stdout/stderr so Docker captures it
|
||||||
|
access_log /dev/stdout;
|
||||||
|
error_log /dev/stderr warn;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
gzip on;
|
||||||
|
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
|
||||||
|
|
||||||
|
# Upload size limit (matches file uploads in the app)
|
||||||
|
client_max_body_size 64M;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /var/www/html/public;
|
||||||
|
index index.php;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
|
||||||
|
# Laravel health-check endpoint
|
||||||
|
location = /up {
|
||||||
|
try_files $uri /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main catch-all → Laravel router
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
# PHP-FPM handler
|
||||||
|
location ~ \.php$ {
|
||||||
|
fastcgi_pass 127.0.0.1:9000;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||||
|
|
||||||
|
# Increase timeouts for long-running requests (PDF export, uploads)
|
||||||
|
fastcgi_read_timeout 300;
|
||||||
|
fastcgi_connect_timeout 60;
|
||||||
|
fastcgi_send_timeout 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deny access to hidden files (.env, .git, etc.)
|
||||||
|
location ~ /\.(?!well-known).* {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|otf)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
docker/supervisord.conf
Normal file
56
docker/supervisord.conf
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
logfile=/dev/null
|
||||||
|
logfile_maxbytes=0
|
||||||
|
pidfile=/run/supervisord.pid
|
||||||
|
|
||||||
|
[unix_http_server]
|
||||||
|
file=/run/supervisor.sock
|
||||||
|
|
||||||
|
[supervisorctl]
|
||||||
|
serverurl=unix:///run/supervisor.sock
|
||||||
|
|
||||||
|
[rpcinterface:supervisor]
|
||||||
|
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||||
|
|
||||||
|
; ── Nginx ─────────────────────────────────────────────────────────────────
|
||||||
|
[program:nginx]
|
||||||
|
command=nginx -g "daemon off;"
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=10
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
; ── PHP-FPM ───────────────────────────────────────────────────────────────
|
||||||
|
[program:php-fpm]
|
||||||
|
command=php-fpm --nodaemonize
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=5
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
; ── Laravel Queue Worker ──────────────────────────────────────────────────
|
||||||
|
[program:queue]
|
||||||
|
command=php /var/www/html/artisan queue:work \
|
||||||
|
--sleep=3 \
|
||||||
|
--tries=3 \
|
||||||
|
--max-time=3600 \
|
||||||
|
--queue=default
|
||||||
|
directory=/var/www/html
|
||||||
|
user=www-data
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
priority=20
|
||||||
|
numprocs=1
|
||||||
|
startsecs=5
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
Reference in New Issue
Block a user