LaravelPublisher v0.0.1 20250609

This commit is contained in:
allen.yan 2025-06-09 18:11:59 +08:00
parent 04670b820b
commit 225725a627
17 changed files with 474 additions and 0 deletions

15
.env.example Normal file
View File

@ -0,0 +1,15 @@
# Project
APP_NAME=ktvcentral
APP_DOMAIN=zqd.superstar.dnsnet.cc
APP_PORT=80
APP_URL=http://zqd.superstar.dnsnet.cc/
REPO_URL="http://47.251.18.130:3000/Leecheng/KTVCentral.git"
REPO_BRANCH="main"
# Database
DB_HOST=mariadb
DB_PORT=3306
DB_DATABASE=KaraokeKingpin
DB_USERNAME=KaraokeKingpin
DB_PASSWORD=ESM7yTPMnavFmbBH

20
.gitignore vendored Normal file
View File

@ -0,0 +1,20 @@
# 忽略開發用 override 設定
docker-compose.override.yml
# 忽略建置產出的 volume、掛載資料
data/
html/
log/
logs/
*.sqlite
# 忽略環境變數備份
.env
.env.backup
.env.*.backup
# 忽略暫存與 log
*.log
*.pid
.DS_Store

32
Dockerfile Normal file
View File

@ -0,0 +1,32 @@
FROM php:8.3-fpm
# ---- system & PHP extensions -------------------------------------------------
RUN apt-get update && apt-get install -y \
git unzip zip curl ca-certificates supervisor cron nano \
libpng-dev libjpeg62-turbo-dev libfreetype6-dev \
libonig-dev libxml2-dev libzip-dev libpq-dev libicu-dev libxslt-dev \
libsqlite3-dev sqlite3 default-mysql-client \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g npm \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd pdo_mysql zip bcmath intl xsl pcntl sockets \
&& docker-php-ext-install opcache \
&& pecl install redis && docker-php-ext-enable redis \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# ---- composer ---------------------------------------------------------------
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# ---- config files -----------------------------------------------------------
COPY docker/php/php.ini /usr/local/etc/php/conf.d/custom-php.ini
COPY docker/php/opcache.ini /usr/local/etc/php/conf.d/opcache.ini
COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY docker/entrypoint.sh /entrypoint.sh
COPY docker/entrypoint.git.sh /entrypoint.git.sh
WORKDIR /var/www
RUN chmod +x /entrypoint.sh /entrypoint.git.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["docker-php-entrypoint", "php-fpm"]

View File

@ -0,0 +1,33 @@
services:
nginx-proxy:
image: jwilder/nginx-proxy
container_name: ${PROJECT_NAME}_nginx_proxy
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs:/etc/nginx/certs
- ./vhost.d:/etc/nginx/vhost.d
- ./html:/usr/share/nginx/html
networks:
- nginx_proxy
letsencrypt:
image: jrcs/letsencrypt-nginx-proxy-companion
container_name: ${PROJECT_NAME}_letsencrypt
environment:
NGINX_PROXY_CONTAINER: ${PROJECT_NAME}_nginx_proxy
DEFAULT_EMAIL: ${LETSENCRYPT_EMAIL}
volumes_from:
- nginx-proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./certs:/etc/nginx/certs:rw
- ./vhost.d:/etc/nginx/vhost.d
- ./html:/usr/share/nginx/html
networks:
- nginx_proxy
networks:
nginx_proxy:
external: true

63
docker-compose.yml Normal file
View File

@ -0,0 +1,63 @@
services:
mariadb:
image: mariadb:10.6
container_name: ${APP_NAME}_db
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- ./data/mariadb/lib:/var/lib/mysql
- ./data/mariadb/conf.d:/etc/mysql/conf.d
- ./data/logs/mariadb:/var/log/mysql
- ./docker/mariadb/my.cnf:/etc/mysql/conf.d/custom.cnf
ports:
- "3306:3306"
networks:
- app_network
app:
build:
context: .
dockerfile: Dockerfile
container_name: ${APP_NAME}_app
volumes:
- ./data/html:/var/www/html
- ./data/logs/php:/var/www/logs
depends_on:
- mariadb
environment:
REPO_URL: ${REPO_URL}
BRANCH: ${REPO_BRANCH}
APP_NAME: ${APP_NAME}
APP_URL: ${APP_URL}
DB_HOST: ${DB_HOST}
DB_PORT: ${DB_PORT}
DB_DATABASE: ${DB_DATABASE}
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
networks:
- app_network
nginx:
image: nginx:stable-alpine
container_name: ${APP_NAME}_nginx
ports:
- "80:80"
volumes:
- ./data/html:/var/www/html
- ./data/nginx/conf.d/:/etc/nginx/conf.d/
- ./data/logs/nginx/:/var/log/nginx
- ./docker/nginx/:/etc/nginx/templates
depends_on:
- app
environment:
NGINX_HOST: ${APP_DOMAIN}
NGINX_PORT: ${APP_PORT}
networks:
- app_network
networks:
app_network:

24
docker/entrypoint.git.sh Normal file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -e
BRANCH=${BRANCH:-main}
TARGET_DIR=/var/www/html
echo "[git-worker] Loop started for branch $BRANCH"
while true; do
cd "$TARGET_DIR"
git remote update
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "origin/$BRANCH")
if [ "$LOCAL" != "$REMOTE" ]; then
echo "[git-worker] Detected new commits, pulling..."
git pull origin "$BRANCH"
echo "[git-worker] Restarting queue-worker..."
supervisorctl restart queue-worker
else
echo "[git-worker] No changes."
fi
sleep 300
done

44
docker/entrypoint.sh Normal file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -e
REPO_URL=${REPO_URL}
BRANCH=${BRANCH:-main}
TARGET_DIR=/var/www/html
# 1) 初次 clone 或拉取
if [ -z "$(ls -A "$TARGET_DIR")" ]; then
echo "[entrypoint] Cloning $BRANCH from $REPO_URL ..."
git clone --branch "$BRANCH" "$REPO_URL" "$TARGET_DIR"
else
echo "[entrypoint] Repository already present, skipping first clone."
fi
cd "$TARGET_DIR"
# 2) Laravel 基礎安裝
composer install --no-interaction --prefer-dist
[ -f .env ] || cp .env.example .env
update_env() { local k=$1 v=$2; grep -q "^$k=" .env && sed -i "s|^$k=.*|$k=$v|" .env || echo "$k=$v" >> .env; }
update_env APP_NAME "$APP_NAME"
update_env APP_URL "${APP_URL%/}"
update_env DB_HOST "$DB_HOST"
update_env DB_PORT "$DB_PORT"
update_env DB_DATABASE "$DB_DATABASE"
update_env DB_USERNAME "$DB_USERNAME"
update_env DB_PASSWORD "$DB_PASSWORD"
php artisan key:generate --force
php artisan migrate --force
[ -d node_modules ] || npm install
npm run build
chown -R www-data:www-data storage bootstrap/cache
chmod -R 775 storage bootstrap/cache
echo "[entrypoint] Starting supervisord ..."
supervisord -c /etc/supervisor/conf.d/supervisord.conf &
exec "$@"

23
docker/mariadb/my.cnf Normal file
View File

@ -0,0 +1,23 @@
[mysqld]
log_error = /var/log/mysql/error.log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# 使用 UTF-8 編碼
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
# 提升最大連線數
max_connections=200
# InnoDB 設定
default-storage-engine=InnoDB
innodb_file_per_table=1
innodb_buffer_pool_size=256M
# 安全 SQL 模式
sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
# 時區
default_time_zone='+08:00'

View File

@ -0,0 +1,38 @@
server {
listen ${NGINX_PORT};
server_name ${NGINX_HOST};
client_max_body_size 100M;
root /var/www/html/public;
index index.php index.html;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass app:9000;
fastcgi_index index.php;
# Laravel 正確位置
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Optional: 支援 PATH_INFO
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
# 避免 NGINX 直接 cache
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
}
location ~ /\.ht {
deny all;
}
}

8
docker/php/opcache.ini Normal file
View File

@ -0,0 +1,8 @@
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.fast_shutdown=1

5
docker/php/php.ini Normal file
View File

@ -0,0 +1,5 @@
memory_limit = 512M
upload_max_filesize = 50M
post_max_size = 50M
max_execution_time = 300
date.timezone = Asia/Taipei

29
docker/supervisord.conf Normal file
View File

@ -0,0 +1,29 @@
[supervisord]
nodaemon=true
logfile=/var/www/logs/supervisord.log ; 設定 log 儲存位置
pidfile=/var/www/logs/supervisord.pid ; 設定 pid 儲存位置
[program:queue-worker]
directory=/var/www/html
command=php artisan queue:work --daemon --timeout=3600 --tries=1 --queue=default
autostart=true
autorestart=true
stdout_logfile=/var/www/logs/queue.log
stderr_logfile=/var/www/logs/queue_error.log
stopsignal=INT
[program:scheduler]
directory=/var/www/html
command=/bin/sh -c "while true; do php artisan schedule:run; sleep 60; done"
autostart=true
autorestart=true
stdout_logfile=/var/www/logs/schedule.log
stderr_logfile=/var/www/logs/schedule_error.log
[program:git-worker]
command=/bin/sh /entrypoint.git.sh
autostart=true
autorestart=true
stdout_logfile=/var/www/logs/git-worker.log
stderr_logfile=/var/www/logs/git-worker_error.log
startsecs=0

30
restart.sh Executable file
View File

@ -0,0 +1,30 @@
#!/bin/bash
WIPE=false
if [ "$1" == "--wipe" ]; then
WIPE=true
fi
# 載入 .env 中的變數
if [ -f .env ]; then
export $(grep -v '^#' .env | xargs)
echo "📦 .env 載入完成"
else
echo "❌ 沒有找到 .env無法載入環境變數"
exit 1
fi
# 使用 .env 中的 APP_NAME 作為 project name
PROJECT_NAME="${APP_NAME}"
echo "♻️ 正在重新啟動 $PROJECT_NAME 所有服務..."
# 先停服務
echo "🔻 執行 stop.sh..."
./stop.sh $([ "$WIPE" == "true" ] && echo "--wipe")
# 再啟動服務
echo "🔺 執行 start.sh..."
./start.sh
echo "$PROJECT_NAME 已完成重啟!"

28
start.sh Executable file
View File

@ -0,0 +1,28 @@
#!/bin/bash
WIPE=false
if [ "$1" == "--wipe" ]; then
WIPE=true
fi
# 載入 .env 中的變數
if [ -f .env ]; then
export $(grep -v '^#' .env | xargs)
echo "📦 .env 載入完成"
else
echo "❌ 沒有找到 .env無法載入環境變數"
exit 1
fi
# 使用 .env 中的 APP_NAME 作為 project name
PROJECT_NAME="${APP_NAME}"
# 組合額外參數(如果有需要清除 volume 與 image
EXTRA_FLAGS="up -d"
if [ "$WIPE" == "true" ]; then
EXTRA_FLAGS="up -d --build"
fi
echo "🚀 Starting APP services..."
docker compose -p $PROJECT_NAME -f docker-compose.yml $EXTRA_FLAGS
echo "✅ All services for $PROJECT_NAME are up and running!"

19
status.sh Normal file
View File

@ -0,0 +1,19 @@
#!/bin/bash
# 載入 .env 中的變數
if [ -f .env ]; then
export $(grep -v '^#' .env | xargs)
echo "📦 .env 載入完成"
else
echo "❌ 沒有找到 .env無法載入環境變數"
exit 1
fi
# 使用 .env 中的 APP_NAME 作為 project name
PROJECT_NAME="${APP_NAME}"
echo "📊 目前 $PROJECT_NAME 相關容器狀態:"
docker ps --filter "name=${PROJECT_NAME}_" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
echo "🔍 目前網路狀態(含 app_network"
docker network inspect app_network --format '{{json .Containers}}' | jq

33
stop.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/bash
WIPE=false
if [ "$1" == "--wipe" ]; then
WIPE=true
fi
# 載入 .env 中的變數
if [ -f .env ]; then
export $(grep -v '^#' .env | xargs)
echo "📦 .env 載入完成"
else
echo "❌ 沒有找到 .env無法載入環境變數"
exit 1
fi
# 使用 .env 中的 APP_NAME 作為 project name
PROJECT_NAME="${APP_NAME}"
# 組合額外參數(如果有需要清除 volume 與 image
EXTRA_FLAGS=""
if [ "$WIPE" == "true" ]; then
EXTRA_FLAGS="-v --rmi all"
fi
echo "🛑 Stopping APP services..."
docker compose -p "$PROJECT_NAME" -f docker-compose.yml down $EXTRA_FLAGS
if [ "$WIPE" == "true" ]; then
echo "🧹 所有資料volumes, image已清除"
else
echo "✅ 所有服務 $PROJECT_NAME 已成功關閉。"
fi

30
開發紀錄.txt Normal file
View File

@ -0,0 +1,30 @@
• 啟動所有服務:./start.sh --wipe
• 停止服務保留資料:./stop.sh
• 停止並清除資料:./stop.sh --wipe
# 正常重啟,不刪除資料
./restart.sh
# 重啟並清除 volumes 和 images
./restart.sh --wipe
docker ps
docker logs ktvcentral_app
docker exec -it ktvcentral_nginx sh
docker exec -it ktvcentral_app php artisan migrate
artisan:
docker exec -it ktvcentral_app php artisan $(cmd)
docker exec -it ktvcentral_app bash
docker exec -it ktvcentral_app php artisan $(cmd)
docker exec -it ktvcentral_app php artisan transfer:sqlite sqlite/tempUser.sqlite --sync