diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4854636 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,57 @@ +# 使用官方 PHP 8.2 FPM 鏡像作為基礎 +FROM php:8.2-fpm + +# 安裝系統依賴 +# 1. 更新套件列表並安裝必要的套件 +RUN apt-get update && apt-get install -y \ + git \ + curl \ + libpng-dev \ + libonig-dev \ + libxml2-dev \ + zip \ + unzip \ + libzip-dev \ + default-mysql-client \ + netcat-openbsd \ + grep + +# 清理 apt 快取以減小鏡像大小 +RUN apt-get clean && rm -rf /var/lib/apt/lists/* + +# 安裝 PHP 擴展 +# 這些擴展是 Laravel 和一般 PHP 開發所需的 +RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip + +# 從官方 Composer 鏡像複製 Composer 執行文件 +# 這樣可以確保我們使用最新版本的 Composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +# 設置工作目錄 +WORKDIR /var/www + +# 設置目錄權限 +# 將 /var/www 目錄的所有權更改為 www-data 用戶和組 +RUN chown -R www-data:www-data /var/www + +# 創建必要的目錄並設置權限 +# Laravel 需要這些目錄來存儲日誌、緩存等 +RUN mkdir -p /var/www/storage /var/www/bootstrap/cache +RUN chmod -R 775 /var/www/storage /var/www/bootstrap/cache + +# 複製自定義的 PHP 配置文件 +# 這個文件包含 PHP 運行時的配置選項 +COPY docker/php/local.ini /usr/local/etc/php/conf.d/local.ini + +# 複製並設置入口點腳本 +# 這個腳本將在容器啟動時執行 +COPY docker/php/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +# 設置容器啟動時執行的入口點 +# 這將在 CMD 指令之前執行 +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] + +# 設置默認的容器命令 +# 這將在 ENTRYPOINT 執行後運行 +CMD ["php-fpm"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..965baa1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,131 @@ +# Docker Compose 版本 +version: '3.8' + +# 定義所有服務 +services: + # PHP-FPM 服務 + app: + # 構建配置 + build: + context: . # 使用當前目錄作為構建上下文 + dockerfile: Dockerfile # 指定 Dockerfile 路徑 + image: cfdive-platform # 構建的鏡像名稱 + container_name: cfdive-app # 容器名稱 + restart: unless-stopped # 自動重啟策略:除非手動停止,否則自動重啟 + working_dir: /var/www/ # 工作目錄 + + # 卷掛載:將本地代碼掛載到容器中 + volumes: + - ./:/var/www # 本地代碼目錄掛載到容器中的 /var/www + + # 環境變數:設置 Laravel 數據庫連接 + environment: + - DB_CONNECTION=mysql # 數據庫類型 + - DB_HOST=db # 數據庫主機名 + - DB_PORT=3306 # 數據庫端口 + - DB_DATABASE=CFDivePlatform # 數據庫名稱 + - DB_USERNAME=cfdiveuser # 數據庫用戶名 + - DB_PASSWORD=cfdivepass # 數據庫密碼 + + # 網絡配置 + networks: + - cfdive-network # 連接到自定義網絡 + + # 依賴關係:確保 db 和 redis 服務先啟動 + depends_on: + db: # 依賴 db 服務 + condition: service_healthy # 等待數據庫健康檢查通過 + redis: # 依賴 redis 服務 + condition: service_started # 等待服務啟動 + + # 健康檢查配置 + healthcheck: + test: ["CMD", "php", "-v"] # 檢查 PHP 版本確認服務正常 + interval: 30s # 每30秒檢查一次 + timeout: 10s # 超時時間10秒 + retries: 3 # 重試3次 + start_period: 40s # 容器啟動後40秒開始檢查 + + nginx: + image: nginx:alpine + container_name: cfdive-nginx + restart: unless-stopped + ports: + - 8080:80 + volumes: + - ./:/var/www + - ./docker/nginx/conf.d/:/etc/nginx/conf.d/ + networks: + - cfdive-network + depends_on: + app: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"] + interval: 30s + timeout: 10s + retries: 3 + + db: + image: mysql:8.0 + container_name: cfdive-db + restart: unless-stopped + environment: + MYSQL_DATABASE: CFDivePlatform + MYSQL_ROOT_PASSWORD: root + MYSQL_USER: cfdiveuser + MYSQL_PASSWORD: cfdivepass + SERVICE_TAGS: dev + SERVICE_NAME: mysql + volumes: + - mysql-data:/var/lib/mysql + ports: + - "3306:3306" + networks: + - cfdive-network + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "cfdiveuser", "-pcfdivepass"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s + + phpmyadmin: + image: phpmyadmin/phpmyadmin + container_name: cfdive-phpmyadmin + restart: unless-stopped + ports: + - "8081:80" + environment: + PMA_HOST: db + PMA_PORT: 3306 + PMA_USER: cfdiveuser + PMA_PASSWORD: cfdivepass + MYSQL_ROOT_PASSWORD: root + networks: + - cfdive-network + depends_on: + db: + condition: service_healthy + + redis: + image: redis:alpine + container_name: cfdive-redis + restart: unless-stopped + ports: + - "6379:6379" + networks: + - cfdive-network + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 30s + timeout: 10s + retries: 3 + +networks: + cfdive-network: + driver: bridge + +volumes: + mysql-data: + driver: local diff --git a/docker/nginx/conf.d/app.conf b/docker/nginx/conf.d/app.conf new file mode 100644 index 0000000..7360631 --- /dev/null +++ b/docker/nginx/conf.d/app.conf @@ -0,0 +1,58 @@ +# 定義一個 HTTP 服務器塊 +server { + # 監聽 80 端口(HTTP) + listen 80; + + # 默認索引文件,按順序嘗試 + index index.php index.html; + + # 錯誤日誌和訪問日誌的路徑 + error_log /var/log/nginx/error.log; + access_log /var/log/nginx/access.log; + + # 網站根目錄,指向 Laravel 的 public 目錄 + root /var/www/public; + + # 客戶端上傳文件大小限制 + client_max_body_size 100M; + + # 處理所有請求 + location / { + # 嘗試以 URI 作為文件查找,然後作為目錄,最後轉發到 index.php + try_files $uri $uri/ /index.php?$query_string; + + # 啟用靜態 gzip 文件服務(如果存在 .gz 文件) + gzip_static on; + } + + # 處理 PHP 文件請求 + location ~ \.php$ { + # 如果文件不存在,返回 404 + try_files $uri =404; + + # 分割路徑信息,用於處理 PATH_INFO + fastcgi_split_path_info ^(.+\.php)(/.+)$; + + # 轉發 PHP 請求到 PHP-FPM 服務 + fastcgi_pass app:9000; + + # 設置 FastCGI 緩衝區大小 + fastcgi_buffers 16 16k; + fastcgi_buffer_size 32k; + + # 默認索引文件 + fastcgi_index index.php; + + # 設置 FastCGI 讀取超時時間(秒) + fastcgi_read_timeout 600; + + # 包含 FastCGI 參數 + include fastcgi_params; + + # 設置 SCRIPT_FILENAME 參數,告訴 PHP-FPM 要執行的文件 + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + + # 設置 PATH_INFO 參數,用於獲取路徑信息 + fastcgi_param PATH_INFO $fastcgi_path_info; + } +} \ No newline at end of file diff --git a/docker/php/docker-entrypoint.sh b/docker/php/docker-entrypoint.sh new file mode 100644 index 0000000..26d2eac --- /dev/null +++ b/docker/php/docker-entrypoint.sh @@ -0,0 +1,114 @@ +#!/bin/bash +set -e + +echo "=== CFDivePlatform 容器初始化開始 ===" + +# 檢查目錄結構 +if [ ! -d "/var/www/storage" ]; then + echo "創建 storage 目錄..." + mkdir -p /var/www/storage +fi + +if [ ! -d "/var/www/bootstrap/cache" ]; then + echo "創建 bootstrap/cache 目錄..." + mkdir -p /var/www/bootstrap/cache +fi + +# 設置權限 +echo "設置目錄權限..." +chown -R www-data:www-data /var/www +chmod -R 775 /var/www/storage /var/www/bootstrap/cache + +# 等待 MySQL 服務啟動 +echo "等待 MySQL 服務啟動..." + +# 使用更穩定的方法檢查 MySQL 連接 +MAX_TRIES=60 +COUNT=0 + +wait_for_mysql() { + while [ $COUNT -lt $MAX_TRIES ]; do + if mysqladmin ping -h"db" -u"cfdiveuser" -p"cfdivepass" --silent 2>/dev/null; then + echo "✅ MySQL 服務已準備就緒" + return 0 + fi + + # 備用檢查方法 + if php -r " + try { + \$pdo = new PDO('mysql:host=db;port=3306', 'cfdiveuser', 'cfdivepass'); + echo 'PHP-PDO-OK'; + exit(0); + } catch(Exception \$e) { + exit(1); + } + " 2>/dev/null; then + echo "✅ MySQL 連接成功 (通過 PHP PDO)" + break + fi + + echo "⏳ 等待 MySQL... ($((COUNT+1))/$MAX_TRIES)" + sleep 2 + COUNT=$((COUNT+1)) + done + + if [ $COUNT -eq $MAX_TRIES ]; then + echo "⚠️ 無法連接到 MySQL,但將繼續啟動服務" + fi +} + +wait_for_mysql + +# 檢查並安裝 Composer 依賴 +echo "📦 檢查 Composer 依賴..." +if [ -f "composer.json" ]; then + if [ ! -d "vendor" ] || [ "composer.json" -nt "vendor/autoload.php" ]; then + echo "安裝 Composer 依賴..." + composer install --no-scripts --no-autoloader --optimize-autoloader + composer dump-autoload --optimize + else + echo "✅ Composer 依賴已是最新" + fi +fi + +# 設置 Laravel 環境 +if [ ! -f .env ]; then + echo "🔧 創建 .env 檔案..." + cp .env.example .env + php artisan key:generate +else + echo "✅ .env 檔案已存在" +fi + +# 更新環境變數以確保正確配置 +echo "🔧 更新資料庫配置..." +sed -i "s/DB_HOST=.*/DB_HOST=db/g" .env +sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=cfdivepass/g" .env +sed -i "s/DB_USERNAME=.*/DB_USERNAME=cfdiveuser/g" .env +sed -i "s/DB_DATABASE=.*/DB_DATABASE=CFDivePlatform/g" .env + +# 執行遷移(如果數據庫已準備好) +echo "🗄️ 執行數據庫遷移..." +if php artisan migrate:status 2>/dev/null; then + php artisan migrate --force || echo "⚠️ 遷移執行遇到問題,但繼續執行" +else + echo "⚠️ 無法檢查遷移狀態,跳過遷移" +fi + +# 清除與優化 Laravel 緩存 +echo "🧹 清除 Laravel 緩存..." +php artisan config:clear || true +php artisan cache:clear || true +php artisan route:clear || true +php artisan view:clear || true + +# 生成 Swagger 文檔(如果可能) +if php -r "echo class_exists('L5Swagger\\L5SwaggerServiceProvider') ? 'yes' : 'no';" 2>/dev/null | grep -q 'yes'; then + echo "📖 生成 API 文檔..." + php artisan l5-swagger:generate || echo "⚠️ API 文檔生成失敗" +fi + +echo "✅ CFDivePlatform 初始化完成!" + +# 執行傳入的命令 +exec "$@" diff --git a/docker/php/local.ini b/docker/php/local.ini new file mode 100644 index 0000000..4f8b444 --- /dev/null +++ b/docker/php/local.ini @@ -0,0 +1,5 @@ +upload_max_filesize=40M +post_max_size=40M +memory_limit=512M +max_execution_time=600 +max_input_vars=10000 \ No newline at end of file