diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..12d85ec Binary files /dev/null and b/.DS_Store differ diff --git a/.env.example b/.env.example index 8b999b5..15fcdf9 100644 --- a/.env.example +++ b/.env.example @@ -1,15 +1,19 @@ # Project -PROJECT_NAME=ktvcentral +APP_NAME=ktvcentral APP_DOMAIN=ktvcentral.test +APP_PORT=80 APP_URL=https://ktvcentral.test -LETSENCRYPT_EMAIL=you@example.com - -# Git -GIT_REPO_URL=http://47.251.18.130:3000/Leecheng/KTVCentral.git # Database DB_HOST=mariadb DB_PORT=3306 -DB_DATABASE=Karaoke-Kingpin -DB_USERNAME=Karaoke-Kingpin +DB_DATABASE=KaraokeKingpin +DB_USERNAME=KaraokeKingpin DB_PASSWORD=ESM7yTPMnavFmbBH + +# Redis +REDIS_HOST=redis +REDIS_PORT=6379 +QUEUE_CONNECTION=redis +CACHE_DRIVER=redis +SESSION_DRIVER=redis \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1bfba6d..2284af6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ docker-compose.override.yml # 忽略建置產出的 volume、掛載資料 data/ html/ +log/ +logs/ *.sqlite # 忽略環境變數備份 diff --git a/Dockerfile b/Dockerfile index 12b8a46..208739b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,20 +3,26 @@ FROM php:8.3-fpm RUN apt-get update && apt-get install -y \ git unzip zip curl libpng-dev libjpeg62-turbo-dev libfreetype6-dev \ libonig-dev libxml2-dev libzip-dev libpq-dev libicu-dev libxslt-dev \ - libsqlite3-dev sqlite3 cron supervisor && \ - 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 gd pdo_mysql zip bcmath intl xsl pcntl sockets - + libsqlite3-dev sqlite3 cron supervisor bash nano \ + 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 gd pdo_mysql zip bcmath intl xsl pcntl sockets COPY --from=composer:latest /usr/bin/composer /usr/bin/composer -WORKDIR /var/www +COPY ./data/KTVCentral/ /var/www/html/ + +RUN chown -R www-data:www-data /var/www/html + + +WORKDIR /var/www/html COPY ./docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf -COPY ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh -RUN chmod +x /usr/local/bin/entrypoint.sh +COPY ./docker/entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] -CMD ["/usr/local/bin/entrypoint.sh"] \ No newline at end of file +CMD ["supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"] \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yml similarity index 54% rename from docker-compose.yaml rename to docker-compose.yml index 219244f..9d28435 100644 --- a/docker-compose.yaml +++ b/docker-compose.yml @@ -1,18 +1,34 @@ 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/db:/var/lib/mysql + - ./data/logs/mysql:/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: ${PROJECT_NAME}_app + container_name: ${APP_NAME}_app volumes: - - ./data:/var/www + - ./data/KTVCentral:/var/www/html + - ./data/logs:/var/www/logs + - ./docker/supervisord.conf:/etc/supervisor/conf.d/supervisord.conf depends_on: - mariadb environment: - VIRTUAL_HOST: ${APP_DOMAIN} - LETSENCRYPT_HOST: ${APP_DOMAIN} - LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL} - GIT_REPO_URL: ${GIT_REPO_URL} + APP_NAME: ${APP_NAME} APP_URL: ${APP_URL} DB_HOST: ${DB_HOST} DB_PORT: ${DB_PORT} @@ -21,39 +37,22 @@ services: DB_PASSWORD: ${DB_PASSWORD} networks: - app_network - - mariadb: - image: mariadb:10.6 - container_name: ${PROJECT_NAME}_db - restart: always - environment: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: ${DB_DATABASE} - MYSQL_USER: ${DB_USERNAME} - MYSQL_PASSWORD: ${DB_PASSWORD} - volumes: - - dbdata:/var/lib/mysql - ports: - - "3306:3306" - networks: - - app_network - nginx: image: nginx:stable-alpine - container_name: ${PROJECT_NAME}_nginx + container_name: ${APP_NAME}_nginx ports: - "80:80" volumes: - - ./data:/var/www - - ./default.conf:/etc/nginx/conf.d/default.conf + - ./data/KTVCentral/public:/var/www/html/public + - ./docker/nginx/:/etc/nginx/templates + - ./data/logs/nginx/:/var/log/nginx depends_on: - app + environment: + NGINX_HOST: ${APP_DOMAIN} + NGINX_PORT: ${APP_PORT} networks: - app_network - -volumes: - dbdata: - networks: app_network: - name: app_network \ No newline at end of file + name: ${APP_NAME}_network \ No newline at end of file diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index a8f1685..fa8510d 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,21 +1,20 @@ #!/bin/bash -cd /var/www +cd /var/www/html APP_URL="${APP_URL%/}" -if [ ! -d "html" ]; then - if [ -n "$GIT_REPO_URL" ]; then - echo "Cloning project from ${GIT_REPO_URL}..." - git clone "$GIT_REPO_URL" html - else - echo "GIT_REPO_URL not set. Skipping clone." - exit 1 - fi -fi +# if [ ! -d "html" ]; then +# if [ -n "$GIT_REPO_URL" ]; then +# echo "Cloning project from ${GIT_REPO_URL}..." +# git clone "$GIT_REPO_URL" html +# else +# echo "GIT_REPO_URL not set. Skipping clone." +# exit 1 +# fi +#fi -cd html echo "Running composer install..." composer install --no-interaction --prefer-dist @@ -35,8 +34,8 @@ update_env_var() { echo "${key}=${value}" >> .env } +update_env_var "APP_NAME" "$APP_NAME" update_env_var "APP_URL" "$APP_URL" -update_env_var "L5_SWAGGER_CONST_HOST" "$APP_URL" update_env_var "DB_HOST" "$DB_HOST" update_env_var "DB_PORT" "$DB_PORT" update_env_var "DB_DATABASE" "$DB_DATABASE" @@ -55,9 +54,4 @@ echo "Installing npm packages..." echo "Building front-end assets..." npm run build -echo "Adding schedule:run to crontab..." -crontab -l 2>/dev/null | grep -q 'schedule:run' || \ - (echo "* * * * * cd /var/www/html && php artisan schedule:run >> /dev/null 2>&1" | crontab -) - -echo "Starting supervisord..." -exec supervisord -n \ No newline at end of file +exec "$@" \ No newline at end of file diff --git a/docker/mariadb/my.cnf b/docker/mariadb/my.cnf new file mode 100644 index 0000000..f978700 --- /dev/null +++ b/docker/mariadb/my.cnf @@ -0,0 +1,2 @@ +[mysqld] +log_error = /var/log/mysql/error.log \ No newline at end of file diff --git a/default.conf.template b/docker/nginx/default.conf.template similarity index 86% rename from default.conf.template rename to docker/nginx/default.conf.template index a177c7e..0887457 100644 --- a/default.conf.template +++ b/docker/nginx/default.conf.template @@ -1,6 +1,6 @@ server { - listen 80 default_server; - server_name {}; + listen ${NGINX_PORT}; + server_name ${NGINX_HOST}; # ✅ 加上分號 root /var/www/html/public; index index.php index.html; diff --git a/docker/supervisord.conf b/docker/supervisord.conf index d17211e..081b789 100644 --- a/docker/supervisord.conf +++ b/docker/supervisord.conf @@ -1,11 +1,15 @@ [supervisord] nodaemon=true +logfile=/var/www/logs/supervisord.log ; 設定 log 儲存位置 +pidfile=/var/www/logs/supervisord.pid ; 設定 pid 儲存位置 [program:php-fpm] command=docker-php-entrypoint php-fpm autostart=true autorestart=true priority=1 +stdout_logfile=/var/www/logs/php-fpm.log +stderr_logfile=/var/www/logs/php-fpm.err.log [program:queue-worker] directory=/var/www/html @@ -13,11 +17,14 @@ command=php artisan queue:work --daemon --timeout=3600 --tries=1 --queue=default autostart=true autorestart=true priority=2 -stdout_logfile=/var/www/html/storage/logs/queue.log -stderr_logfile=/var/www/html/storage/logs/queue_error.log +stdout_logfile=/var/www/logs/queue.log +stderr_logfile=/var/www/logs/queue_error.log -[program:schedule-run] -command=cron -f +[program:scheduler] +directory=/var/www/html +command=sh -c "while true; do php artisan schedule:run; sleep 60; done" autostart=true autorestart=true -priority=3 \ No newline at end of file +priority=3 +stdout_logfile=/var/www/logs/schedule.log +stderr_logfile=/var/www/logs/schedule_error.log diff --git a/restart.sh b/restart.sh new file mode 100755 index 0000000..8f91e22 --- /dev/null +++ b/restart.sh @@ -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:-ktvproject}" + +echo "♻️ 正在重新啟動 $PROJECT_NAME 所有服務..." + +# 先停服務 +echo "🔻 執行 stop.sh..." +./stop.sh $([ "$WIPE" == "true" ] && echo "--wipe") + +# 再啟動服務 +echo "🔺 執行 start.sh..." +./start.sh + +echo "✅ $PROJECT_NAME 已完成重啟!" \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..d97b405 --- /dev/null +++ b/start.sh @@ -0,0 +1,37 @@ +#!/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}" +NETWORK_NAME="${APP_NAME}_network" + +# 檢查並建立 network(如果不存在) +if ! docker network ls --format '{{.Name}}' | grep -wq "$NETWORK_NAME"; then + echo "🔌 建立 Docker 網路 $NETWORK_NAME ..." + docker network create $NETWORK_NAME +else + echo "🔌 Docker 網路 $NETWORK_NAME 已存在" +fi + +# 組合額外參數(如果有需要清除 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!" \ No newline at end of file diff --git a/status.sh b/status.sh new file mode 100644 index 0000000..f6bfc07 --- /dev/null +++ b/status.sh @@ -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:-ktvproject}" + +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 \ No newline at end of file diff --git a/stop.sh b/stop.sh new file mode 100755 index 0000000..df082ea --- /dev/null +++ b/stop.sh @@ -0,0 +1,41 @@ +#!/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}" +NETWORK_NAME="${APP_NAME}_network" + + +# 組合額外參數(如果有需要清除 volume 與 image) +EXTRA_FLAGS="" +if [ "$WIPE" == "true" ]; then + EXTRA_FLAGS="-v --rmi all" + # 檢查並建立 network(如果不存在) + if ! docker network ls --format '{{.Name}}' | grep -wq "$NETWORK_NAME"; then + echo "🔌 Docker 網路 $NETWORK_NAME 不存在" + else + docker network rm $NETWORK_NAME + echo "🔌 Docker 網路 $NETWORK_NAME 已刪除" + fi +fi + +echo "🛑 Stopping APP services..." +docker compose -p "$PROJECT_NAME" -f docker-compose.app.yml down $EXTRA_FLAGS + +if [ "$WIPE" == "true" ]; then + echo "🧹 所有資料(volumes, image)已清除!" +else + echo "✅ 所有服務 $PROJECT_NAME 已成功關閉。" +fi