添加docker构建配置

This commit is contained in:
2025-12-13 20:36:31 +08:00
parent 307573ba1b
commit b32e1d25d1
15 changed files with 995 additions and 842 deletions

48
.dockerignore Normal file
View File

@@ -0,0 +1,48 @@
# Git
.git
.gitignore
# Node
node_modules
npm-debug.log
# Python
__pycache__
*.pyc
*.pyo
*.pyd
.Python
*.egg-info
dist
build
# IDE
.vscode
.idea
*.swp
*.swo
*~
# 环境变量
.env
.env.local
.env.backup
**/.env.local
**/.env.production.local
**/.env.development.local
# 日志
*.log
logs
# 测试
test
*.test.js
# 临时文件
*.tmp
.DS_Store
Thumbs.db
# README
README.md

49
Dockerfile Normal file
View File

@@ -0,0 +1,49 @@
# ====== Frontend build stage ======
FROM node:18-alpine AS fe-builder
WORKDIR /fe
COPY SmyWorkCollect-Frontend/package*.json ./
# 使用 npm install 以避免对锁文件严格校验导致构建失败
RUN npm install
COPY SmyWorkCollect-Frontend/ .
# 确保不带 REACT_APP_API_URL生产默认使用相对路径 /api
RUN npm run build
# ====== Final runtime (Python + Nginx + Supervisor) ======
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# 安装系统依赖: nginx, supervisor, curl
RUN apt-get update \
&& apt-get install -y --no-install-recommends nginx supervisor curl \
&& rm -rf /var/lib/apt/lists/*
# 创建目录结构
WORKDIR /app
RUN mkdir -p /app/backend \
/app/SmyWorkCollect-Frontend/build \
/app/SmyWorkCollect-Frontend/config \
/run/nginx \
/var/log/supervisor
# 复制后端依赖并安装(包含 gunicorn
COPY SmyWorkCollect-Backend/requirements.txt /app/backend/requirements.txt
RUN pip install --no-cache-dir -r /app/backend/requirements.txt \
&& pip install --no-cache-dir gunicorn
# 复制后端代码
COPY SmyWorkCollect-Backend/ /app/backend/
# 复制前端构建产物到预期目录(与后端中的路径逻辑兼容)
COPY --from=fe-builder /fe/build /app/SmyWorkCollect-Frontend/build
# 复制 Nginx 与 Supervisor 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# 暴露对外端口 8383Nginx 监听此端口)
EXPOSE 8383
# 运行 supervisor 同时管理 nginx 与 gunicornFlask
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

217
README-Docker.md Normal file
View File

@@ -0,0 +1,217 @@
# 树萌芽の作品集 - Docker 部署指南
## 📦 快速部署
### 前置要求
- Docker 20.10+
- Docker Compose 2.0+
- 至少 2GB 可用内存
- 至少 10GB 可用磁盘空间
### 一键部署
```bash
# 1. 克隆或下载项目到本地
# 2. 进入项目目录
cd 树萌芽の作品集
# 3. 构建并启动服务
docker-compose up -d --build
```
### 访问应用
部署成功后,通过浏览器访问: **http://localhost:8383**
## 📂 持久化目录说明
所有数据都持久化存储在 `/shumengya/docker/smyworkcollect/data/` 目录下:
```
/shumengya/docker/smyworkcollect/data/
├── works/ # 作品数据(图片、视频、文件等)
├── config/ # 网站配置文件
└── logs/ # 应用/访问日志(可选)
```
### Windows 环境
如果在 Windows 上部署,建议修改 `docker-compose.yml` 中的路径为:
```yaml
volumes:
- C:/shumengya/docker/smyworkcollect/data/works:/app/backend/works
- C:/shumengya/docker/smyworkcollect/data/config:/app/SmyWorkCollect-Frontend/config
- C:/shumengya/docker/smyworkcollect/data/logs:/var/log/nginx
```
### Linux/Mac 环境
确保创建目录并设置正确权限:
```bash
sudo mkdir -p /shumengya/docker/smyworkcollect/data/{works,config,logs}
sudo chown -R 1000:1000 /shumengya/docker/smyworkcollect/data/
```
## 🔧 常用命令
### 启动服务
```bash
docker-compose up -d
```
### 停止服务
```bash
docker-compose down
```
### 查看日志
```bash
# 查看所有服务日志
docker-compose logs -f
# 只查看后端日志
docker-compose logs -f backend
# 只查看前端日志
docker-compose logs -f frontend
```
### 重启服务
```bash
docker-compose restart
```
### 重新构建并启动
```bash
docker-compose up -d --build
```
### 查看服务状态
```bash
docker-compose ps
```
### 进入容器
```bash
# 进入单容器
docker exec -it smywork-app sh
```
## 🔐 管理员配置
管理员 Token: `shumengya520`
访问管理面板: http://localhost:8383/#/admin?token=shumengya520
## 🎨 自定义配置
### 修改端口
编辑 `docker-compose.yml` 文件中的端口映射:
```yaml
ports:
- "你的端口:80" # 例如: "8080:80"
```
### 修改管理员密码
编辑 `SmyWorkCollect-Backend/app.py`:
```python
ADMIN_TOKEN = "你的新密码"
```
然后重新构建:
```bash
docker-compose up -d --build backend
```
### 修改网站配置
编辑持久化目录中的配置文件:
```bash
/shumengya/docker/smyworkcollect/data/config/settings.json
```
## 📊 资源限制(可选)
`docker-compose.yml` 中添加资源限制:
```yaml
services:
backend:
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
```
## 🔄 更新应用
```bash
# 1. 停止服务
docker-compose down
# 2. 拉取最新代码
git pull
# 3. 重新构建并启动
docker-compose up -d --build
```
## 🛠️ 故障排查
### 服务无法启动
```bash
# 查看详细日志
docker-compose logs
# 检查端口是否被占用
netstat -ano | findstr 8383 # Windows
lsof -i :8383 # Linux/Mac
```
### 权限问题
```bash
# Linux/Mac 下设置正确权限
sudo chown -R 1000:1000 /shumengya/docker/smyworkcollect/data/
```
### 清理并重新部署
```bash
# 停止并删除所有容器
docker-compose down
# 删除旧镜像(可选,镜像名以目录为准)
docker images | findstr smywork
# 重新构建
docker-compose up -d --build
```
## 📝 备份与恢复
### 备份数据
```bash
# 备份作品数据
tar -czf smywork-backup-$(date +%Y%m%d).tar.gz /shumengya/docker/smyworkcollect/data/
```
### 恢复数据
```bash
# 解压备份
tar -xzf smywork-backup-20231125.tar.gz -C /
```
## 🌐 生产环境建议
1. **使用反向代理** (Nginx/Traefik) 并配置 HTTPS
2. **定期备份** 持久化数据
3. **监控日志** 并设置告警
4. **资源限制** 防止资源耗尽
5. **安全加固** 修改默认管理员密码
## 📞 支持
- 作者: 树萌芽
- 邮箱: 3205788256@qq.com
---
**祝部署顺利! 🎉**

View File

@@ -0,0 +1,24 @@
# 后端 Dockerfile
FROM python:3.11-slim
WORKDIR /app/backend
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 复制后端代码
COPY . .
# 暴露端口
EXPOSE 5000
# 启动后端服务
CMD ["python", "app.py"]

View File

@@ -12,6 +12,11 @@ import tempfile
import re
import unicodedata
import string
import math
import calendar
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

View File

@@ -1 +1,4 @@
REACT_APP_API_URL=http://127.0.0.1:5000/api
REACT_APP_API_URL=/api
# 保持开发环境通过 package.json 的 proxy 转发到后端
DANGEROUSLY_DISABLE_HOST_CHECK=true
WDS_SOCKET_HOST=localhost

View File

@@ -0,0 +1,29 @@
# 前端构建阶段
FROM node:18-alpine as builder
WORKDIR /app
# 复制 package 文件
COPY package*.json ./
# 安装依赖
RUN npm install
# 复制源代码
COPY . .
# 构建前端
RUN npm run build
# Nginx 运行阶段
FROM nginx:alpine
# 复制构建产物到 nginx
COPY --from=builder /app/build /usr/share/nginx/html
# 复制 nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -0,0 +1,33 @@
server {
listen 80;
server_name localhost;
# 前端静态文件
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
# 代理后端 API 请求
location /api/ {
proxy_pass http://backend:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 大文件上传配置
client_max_body_size 5000M;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
}
# 错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,11 +6,11 @@
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"axios": "^1.4.0",
"react-router-dom": "^6.8.0",
"react-scripts": "5.0.1",
"styled-components": "^5.3.9",
"web-vitals": "^2.1.4"
},

View File

@@ -1,5 +1,5 @@
@echo off
echo 正在启动树萌芽の作品集前端...
npm start
npm run dev
pause
npm install

26
docker-compose.yml Normal file
View File

@@ -0,0 +1,26 @@
version: '3.8'
services:
smywork-app:
build:
context: .
dockerfile: Dockerfile
container_name: smywork-app
restart: unless-stopped
ports:
- "8383:8383"
environment:
- FLASK_ENV=production
- PYTHONUNBUFFERED=1
volumes:
# 持久化数据目录(根据你的要求统一为 /shumengya/docker/smyworkcollect/data/
- /shumengya/docker/smyworkcollect/data/works:/app/backend/works
- /shumengya/docker/smyworkcollect/data/config:/app/SmyWorkCollect-Frontend/config
# 可选:持久化 Nginx 日志
- /shumengya/docker/smyworkcollect/data/logs:/var/log/nginx
healthcheck:
test: ["CMD-SHELL", "curl -sSf http://localhost:8383 >/dev/null"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s

32
nginx.conf Normal file
View File

@@ -0,0 +1,32 @@
server {
listen 8383;
server_name _;
# 前端静态文件
root /app/SmyWorkCollect-Frontend/build;
index index.html;
# 尽量命中静态资源
location / {
try_files $uri $uri/ /index.html;
}
# 反向代理到 Flask 后端
location /api/ {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 大文件与超时
client_max_body_size 5000M;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html { root /usr/share/nginx/html; }
}

20
supervisord.conf Normal file
View File

@@ -0,0 +1,20 @@
[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[program:gunicorn]
command=gunicorn -w 2 -b 0.0.0.0:5000 app:app
user=root
directory=/app/backend
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/gunicorn.log
stderr_logfile=/var/log/supervisor/gunicorn_err.log
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/nginx.log
stderr_logfile=/var/log/supervisor/nginx_err.log

View File

@@ -1,112 +0,0 @@
server
{
listen 80;
listen 443 ssl;
listen 443 quic;
http2 on;
server_name work.shumengya.top;
index index.html index.htm default.htm default.html;
root /shumengya/树萌芽的作品集网站/frontend/build;
# 大文件上传支持
client_max_body_size 500M;
client_body_timeout 300s;
client_header_timeout 300s;
send_timeout 300s;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
#CERT-APPLY-CHECK--START
# 用于SSL证书申请时的文件验证相关配置 -- 请勿删除并保持这段设置在优先级高的位置
include /www/server/panel/vhost/nginx/well-known/work.shumengya.top.conf;
#CERT-APPLY-CHECK--END
#SSL-START SSL相关配置请勿删除或修改下一行带注释的404规则
#error_page 404/404.html;
#HTTP_TO_HTTPS_START
set $isRedcert 1;
if ($server_port != 443) {
set $isRedcert 2;
}
if ( $uri ~ /\.well-known/ ) {
set $isRedcert 1;
}
if ($isRedcert != 1) {
rewrite ^(/.*)$ https://$host$1 permanent;
}
#HTTP_TO_HTTPS_END
ssl_certificate /www/server/panel/vhost/cert/work.shumengya.top/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/work.shumengya.top/privkey.pem;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_tickets on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000";
add_header Alt-Svc 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"';
error_page 497 https://$host$request_uri;
#SSL-END
#ERROR-PAGE-START 错误页配置,可以注释、删除或修改
#error_page 404 /404.html;
#error_page 502 /502.html;
#ERROR-PAGE-END
#REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
include /www/server/panel/vhost/rewrite/html_work.shumengya.top.conf;
#REWRITE-END
#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
#一键申请SSL证书验证目录相关设置
location ~ \.well-known{
allow all;
}
#禁止在证书验证目录放入敏感文件
if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
return 403;
}
# SPA路由支持 - 关键添加部分
location / {
try_files $uri $uri/ /index.html;
# 添加安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 处理预检请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log /dev/null;
access_log /dev/null;
}
location ~ .*\\.(js|css)?$
{
expires 12h;
error_log /dev/null;
access_log /dev/null;
}
access_log /www/wwwlogs/work.shumengya.top.log;
error_log /www/wwwlogs/work.shumengya.top.error.log;
}