diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7e292d9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.git +__pycache__/ +venv/ +*.pyc +*.log +*.backup +*_old.* +.last_* +debug_page.html +monitor.log +config.ini +data/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ec0f98b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.11-slim + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + GPA_DATA_DIR=/data + +WORKDIR /app + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && rm -rf /var/lib/apt/lists/* \ + && useradd --create-home --shell /usr/sbin/nologin appuser \ + && mkdir -p /data \ + && chown -R appuser:appuser /app /data + +COPY requirements.txt /app/ +RUN pip install --no-cache-dir -r requirements.txt + +COPY monitor.py /app/ + +USER appuser + +CMD ["python", "/app/monitor.py", "--config", "/data/config.ini"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a124f0b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ + services: + gpa-monitor: + build: . + container_name: gpa-monitor + restart: unless-stopped + environment: + GPA_DATA_DIR: /data + volumes: + - ./data:/data + - ./config.ini:/data/config.ini:ro diff --git a/docs/完整使用文档.md b/docs/完整使用文档.md index eb247ad..30a4ba3 100644 --- a/docs/完整使用文档.md +++ b/docs/完整使用文档.md @@ -24,6 +24,7 @@ - Python 3.7+ - 服务器能访问外网 - SSH访问权限 +- (可选)Docker 20+ / Docker Compose v2 ## 📦 项目文件说明 @@ -127,6 +128,45 @@ python3 monitor.py --test cat .last_grade_content.txt ``` +--- + +## 🐳 Docker 部署(推荐) + +> 适合已有 Docker 环境的服务器(例如 docker.aizhangz.top)。 + +### 1) 准备文件(本地或服务器) + +必需文件: +- `monitor.py` +- `requirements.txt` +- `Dockerfile` +- `docker-compose.yml` +- `config.ini`(⚠️ 敏感文件) + +### 2) 在服务器上运行 + +```bash +# 进入项目目录 +cd ~/grade_monitor + +# 首次构建并启动 +docker compose up -d --build + +# 查看日志 +docker logs -f gpa-monitor +``` + +### 3) 测试模式(可选) + +```bash +docker compose run --rm gpa-monitor python /app/monitor.py --config /data/config.ini --test +``` + +### 4) 说明 + +- 运行日志和缓存文件会写入 `./data/` +- 配置文件通过 `./config.ini:/data/config.ini:ro` 挂载 + ## 🔧 设置后台运行 ### 使用 systemd(推荐,生产环境) diff --git a/monitor.py b/monitor.py index 2b5089c..111081b 100644 --- a/monitor.py +++ b/monitor.py @@ -26,6 +26,11 @@ from email.mime.multipart import MIMEMultipart from typing import Optional, Dict import signal +# 数据目录(用于日志和运行时文件) +_DEFAULT_DATA_DIR = Path(__file__).parent.resolve() +DATA_DIR = Path(os.environ.get('GPA_DATA_DIR', str(_DEFAULT_DATA_DIR))).expanduser() +DATA_DIR.mkdir(parents=True, exist_ok=True) + # 配置日志 logger = logging.getLogger(__name__) @@ -40,7 +45,7 @@ if not logger.handlers: ) # 文件处理器 - file_handler = logging.FileHandler('monitor.log', encoding='utf-8') + file_handler = logging.FileHandler(DATA_DIR / 'monitor.log', encoding='utf-8') file_handler.setFormatter(formatter) logger.addHandler(file_handler) @@ -67,10 +72,10 @@ class GradeMonitor: }) # 文件路径 - self.script_dir = Path(__file__).parent.absolute() - self.last_grade_file = self.script_dir / '.last_grade_hash.txt' - self.last_grade_html_file = self.script_dir / '.last_grade_page.html' - self.last_grade_content_file = self.script_dir / '.last_grade_content.txt' + self.data_dir = DATA_DIR + self.last_grade_file = self.data_dir / '.last_grade_hash.txt' + self.last_grade_html_file = self.data_dir / '.last_grade_page.html' + self.last_grade_content_file = self.data_dir / '.last_grade_content.txt' # 运行标志 self.running = True @@ -362,7 +367,7 @@ class GradeMonitor: if not result: logger.warning("未能提取到成绩信息,页面可能结构异常") # 保存HTML以便调试 - debug_file = self.script_dir / 'debug_page.html' + debug_file = self.data_dir / 'debug_page.html' debug_file.write_text(html, encoding='utf-8') logger.info(f"已保存HTML到 {debug_file} 供调试") @@ -469,7 +474,7 @@ class GradeMonitor: logger.info("=" * 60) # 保存课程列表 - courses_file = self.script_dir / '.last_courses.txt' + courses_file = self.data_dir / '.last_courses.txt' courses_file.write_text('\n'.join(current_courses), encoding='utf-8') # 计算哈希 @@ -478,7 +483,7 @@ class GradeMonitor: return (False, []) # 读取上次的课程列表 - courses_file = self.script_dir / '.last_courses.txt' + courses_file = self.data_dir / '.last_courses.txt' if courses_file.exists(): last_courses = courses_file.read_text(encoding='utf-8').strip().split('\n') else: @@ -792,7 +797,7 @@ class GradeMonitor: # 如果解析失败(0门课程)且之前有课程,可能是临时问题 if len(current_courses) == 0: # 检查是否之前有课程记录 - courses_file = self.script_dir / '.last_courses.txt' + courses_file = self.data_dir / '.last_courses.txt' if courses_file.exists(): try: previous_courses = courses_file.read_text(encoding='utf-8').strip().split('\n') diff --git a/readme.md b/readme.md index d2a1c98..930168c 100644 --- a/readme.md +++ b/readme.md @@ -54,6 +54,24 @@ python3 monitor.py # 按 Ctrl+B 然后按 D 离开会话 ``` +## Docker 部署(推荐) + +> 运行日志和缓存文件会写入 `./data/`,配置文件挂载为只读。 + +```bash +# 1) 准备配置文件(同级目录下的 config.ini) +# 2) 启动 +docker compose up -d --build + +# 查看日志 +docker logs -f gpa-monitor +``` + +**测试模式:** +```bash +docker compose run --rm gpa-monitor python /app/monitor.py --config /data/config.ini --test +``` + ## 功能特点 ✅ **智能检测** - 检测新增课程(而非简单的页面变化) @@ -193,4 +211,4 @@ tmux attach -t grade_monitor ## 许可证 -MIT License \ No newline at end of file +MIT License diff --git a/私有Docker仓库部署手册.md b/私有Docker仓库部署手册.md new file mode 100644 index 0000000..c4bf948 --- /dev/null +++ b/私有Docker仓库部署手册.md @@ -0,0 +1,164 @@ +# **Debian 私有 Docker 仓库 (Registry \+ UI \+ HTTPS) 部署手册** + +本文档详细说明了如何在 Debian 系统上构建一个支持域名访问、HTTPS 加密、用户认证以及图形化管理界面的私有 Docker 仓库。 + +## **1\. 基础环境准备** + +### **1.1 系统更新与防火墙** + +确保服务器已开启 80 (HTTP) 和 443 (HTTPS) 端口。 + +sudo apt update && sudo apt upgrade \-y +\# 如果开启了 ufw 防火墙 +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +### **1.2 安装 Docker 与 Docker Compose** + +使用 Docker 官方源安装最新版本。 + +sudo apt install ca-certificates curl gnupg lsb-release \-y +sudo install \-m 0755 \-d /etc/apt/keyrings +curl \-fsSL \[https://download.docker.com/linux/debian/gpg\](https://download.docker.com/linux/debian/gpg) | sudo gpg \--dearmor \-o /etc/apt/keyrings/docker.gpg +sudo chmod a+r /etc/apt/keyrings/docker.gpg + +echo "deb \[arch=$(dpkg \--print-architecture) signed-by=/etc/apt/keyrings/docker.gpg\] \[https://download.docker.com/linux/debian\](https://download.docker.com/linux/debian) $(lsb\_release \-cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list \> /dev/null + +sudo apt update +sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin \-y + +## **2\. 仓库服务配置 (Registry & UI)** + +### **2.1 创建项目目录与认证文件** + +我们将使用 htpasswd 为仓库添加登录限制。 + +mkdir \-p \~/docker-registry/auth && cd \~/docker-registry + +\# 创建用户名为 admin,密码为 your\_password 的认证文件 +\# 请务必修改下方的 your\_password +docker run \--entrypoint htpasswd httpd:2 \-Bbn admin your\_password \> auth/htpasswd + +### **2.2 编写 docker-compose.yml** + +该配置包含仓库核心服务和可视化 UI 服务。 + +version: '3.8' + +services: + registry: + image: registry:2 + container\_name: registry-server + restart: always + environment: + REGISTRY\_AUTH: htpasswd + REGISTRY\_AUTH\_HTPASSWD\_REALM: Registry Realm + REGISTRY\_AUTH\_HTPASSWD\_PATH: /auth/htpasswd + REGISTRY\_HTTP\_SECRET: some\_random\_secret + REGISTRY\_HTTP\_CORS\_ENABLED: "true" + REGISTRY\_HTTP\_CORS\_ALLOWEDMETHODS: "\[HEAD,GET,OPTIONS,DELETE\]" + REGISTRY\_HTTP\_CORS\_ALLOWEDORIGINS: "\['\[https://docker.aizhangz.top\](https://docker.aizhangz.top)'\]" + REGISTRY\_STORAGE\_DELETE\_ENABLED: "true" + volumes: + \- ./data:/var/lib/registry + \- ./auth:/auth + ports: + \- "127.0.0.1:5000:5000" + + ui: + image: joxit/docker-registry-ui:latest + container\_name: registry-ui + restart: always + environment: + \- REGISTRY\_TITLE=My Private Registry + \- NGINX\_PROXY\_PASS\_URL=http://registry:5000 + \- SINGLE\_REGISTRY=true + \- DELETE\_IMAGES=true + ports: + \- "127.0.0.1:8080:80" + +启动容器: + +docker compose up \-d + +## **3\. Nginx 反向代理与 SSL 证书** + +### **3.1 安装 Nginx 与 Certbot** + +sudo apt install nginx certbot python3-certbot-nginx \-y + +### **3.2 申请证书** + +\# 请将 docker.aizhangz.top 替换为您实际解析好的域名 +sudo certbot \--nginx \-d docker.aizhangz.top + +### **3.3 修改 Nginx 配置文件** + +编辑 /etc/nginx/sites-available/default,将 HTTPS 核心块修改为如下代理逻辑。 + +server { + listen 443 ssl; + server\_name docker.aizhangz.top; + + \# SSL 证书路径(由 Certbot 自动生成) + ssl\_certificate /etc/letsencrypt/live/docker.aizhangz.top/fullchain.pem; + ssl\_certificate\_key /etc/letsencrypt/live/docker.aizhangz.top/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl\_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + \# 允许上传大型镜像文件 + client\_max\_body\_size 0; + chunked\_transfer\_encoding on; + + \# 1\. 路由 Docker API 请求 (命令行操作及 UI 后台通讯) + location /v2/ { + proxy\_pass \[http://127.0.0.1:5000\](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; + proxy\_read\_timeout 900; + } + + \# 2\. 路由浏览器访问请求 (UI 界面) + location / { + proxy\_pass \[http://127.0.0.1:8080\](http://127.0.0.1:8080); + 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; + } +} + +重启 Nginx: + +sudo nginx \-t && sudo systemctl restart nginx + +## **4\. 客户端使用指南** + +### **4.1 登录仓库** + +在任意客户端机器(Windows/Linux/Mac)执行: + +docker login docker.aizhangz.top +\# 输入步骤 2.1 中设置的用户名(admin)和密码 + +### **4.2 推送镜像** + +\# 以 busybox 为例 +docker pull busybox +docker tag busybox docker.aizhangz.top/my-busybox:v1 +docker push docker.aizhangz.top/my-busybox:v1 + +### **4.3 访问 Web 界面** + +在浏览器打开:https://docker.aizhangz.top + +输入账号密码后即可可视化管理镜像。 + +## **5\. 维护说明** + +* **查看容器状态**:docker compose ps +* **查看日志**:docker compose logs \-f +* **证书续期**:Certbot 会自动处理,可手动测试:sudo certbot renew \--dry-run +* **存储位置**:所有镜像物理文件存储在 \~/docker-registry/data 目录下。 \ No newline at end of file