Dockerfile 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # ========================================
  2. # 第一阶段:构建前端资源
  3. # ========================================
  4. FROM node:20-alpine AS frontend-builder
  5. # 设置工作目录
  6. WORKDIR /app
  7. # 安装 bun
  8. RUN npm install -g bun@latest
  9. # 复制 package.json 并配置 npm 镜像
  10. COPY package.json ./
  11. RUN npm config set registry https://registry.npmmirror.com
  12. # 安装依赖并生成 lockfile
  13. RUN bun install
  14. # 复制其他配置文件
  15. COPY tailwind.config.js postcss.config.js vite.config.js ./
  16. # 复制源码
  17. COPY resources/ ./resources/
  18. # 构建前端资源
  19. RUN bun run build
  20. # ========================================
  21. # 第二阶段:PHP 运行时(使用 php-fpm)
  22. # ========================================
  23. FROM php:8.3-fpm-alpine AS base-runtime
  24. # 安装系统依赖 - 使用阿里云镜像
  25. RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
  26. apk add --no-cache \
  27. git \
  28. curl \
  29. ca-certificates \
  30. libzip-dev \
  31. libpng-dev \
  32. oniguruma-dev \
  33. libjpeg-turbo-dev \
  34. freetype-dev \
  35. icu-dev \
  36. libzip-dev \
  37. sqlite-dev \
  38. # Chrome/Chromium 依赖(PDF 生成必须)
  39. chromium \
  40. nss \
  41. freetype \
  42. harfbuzz \
  43. # dbus(解决 Chrome 在容器中的连接问题)
  44. dbus \
  45. # 字体(PDF 中文显示必须)
  46. ttf-freefont \
  47. font-noto-cjk \
  48. font-noto \
  49. ttf-dejavu \
  50. fontconfig \
  51. # PDF 合并工具
  52. poppler-utils \
  53. # Node.js(KaTeX 服务端渲染需要)
  54. nodejs \
  55. npm \
  56. && rm -rf /var/cache/apk/* \
  57. && fc-cache -fv \
  58. && mkdir -p /run/dbus
  59. # 设置 Chrome 环境变量
  60. ENV CHROME_BIN=/usr/bin/chromium-browser \
  61. CHROME_PATH=/usr/lib/chromium/ \
  62. PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
  63. PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
  64. # 安装 PHP 扩展
  65. RUN docker-php-ext-configure gd --with-freetype --with-jpeg && \
  66. docker-php-ext-install -j$(nproc) pdo pdo_mysql pdo_sqlite gd zip intl pcntl
  67. # 安装 Redis 扩展
  68. RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \
  69. && pecl install redis \
  70. && docker-php-ext-enable redis \
  71. && apk del .build-deps
  72. # 调高 PHP 上传限制(Livewire 多图上传需要)
  73. RUN { \
  74. echo "file_uploads=On"; \
  75. echo "upload_max_filesize=20M"; \
  76. echo "post_max_size=64M"; \
  77. echo "max_file_uploads=50"; \
  78. echo "max_execution_time=120"; \
  79. echo "max_input_time=120"; \
  80. echo "memory_limit=512M"; \
  81. } > /usr/local/etc/php/conf.d/99-upload-limits.ini
  82. # 安装 Composer - 使用国内镜像
  83. COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
  84. RUN composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
  85. # 创建应用目录
  86. WORKDIR /app
  87. # 复制 Composer 文件并安装依赖
  88. COPY composer.json composer.lock ./
  89. RUN composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader --no-scripts
  90. # 安装 KaTeX(服务端公式渲染)
  91. RUN npm config set registry https://registry.npmmirror.com && \
  92. npm install -g katex@0.16.9
  93. # 复制应用代码(排除 node_modules, vendor 等)
  94. COPY . .
  95. # 创建必要目录
  96. RUN mkdir -p storage/logs storage/framework/cache storage/framework/sessions storage/framework/views bootstrap/cache
  97. # 设置权限
  98. RUN chown -R www-data:www-data /app && \
  99. chmod -R 755 /app && \
  100. chmod -R 777 /app/storage /app/bootstrap/cache
  101. # 通用入口脚本(queue worker 模式仅执行命令,不启动 nginx)
  102. COPY docker-entrypoint.sh /usr/local/bin/
  103. RUN chmod +x /usr/local/bin/docker-entrypoint.sh
  104. ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
  105. # ========================================
  106. # 第三阶段:App Runtime(Nginx + PHP-FPM)
  107. # ========================================
  108. FROM base-runtime AS app-runtime
  109. # 安装 Nginx(仅 Web API 容器需要)
  110. RUN apk add --no-cache nginx && \
  111. mkdir -p /run/nginx /var/log/nginx
  112. # 从第一阶段复制构建好的前端资源
  113. COPY --from=frontend-builder /app/public/build ./public/build
  114. # 缓存路由和视图(不缓存配置,配置在运行时从 .env 读取)
  115. RUN php artisan route:cache && \
  116. php artisan view:cache && \
  117. php artisan filament:upgrade || true
  118. # 复制 Nginx 和 PHP-FPM 配置
  119. COPY docker/nginx.conf /etc/nginx/nginx.conf
  120. COPY docker/www.conf /usr/local/etc/php-fpm.d/www.conf
  121. EXPOSE 8000
  122. # 健康检查(检查 Nginx 是否响应)
  123. HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  124. CMD curl -f http://127.0.0.1:8000/health || exit 1
  125. CMD ["nginx", "-g", "daemon off;"]
  126. # ========================================
  127. # 第四阶段:PDF Worker Runtime(无 Nginx/无前端构建)
  128. # ========================================
  129. FROM base-runtime AS pdfworker
  130. CMD ["php", "artisan", "queue:work", "--queue=pdf", "--sleep=3", "--tries=2", "--max-time=300", "--max-jobs=10"]