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.backup
|
||||
.env.production
|
||||
.env.docker
|
||||
.phpactor.json
|
||||
.phpunit.result.cache
|
||||
/.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