Kamixitong/deploy.py

292 lines
8.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
KaMiXiTong 部署脚本
用于生产环境的一键部署
"""
import os
import sys
import subprocess
import argparse
from pathlib import Path
def check_python_version():
"""检查Python版本"""
if sys.version_info < (3, 6):
print("❌ 错误: 需要Python 3.6或更高版本")
print(f"当前版本: {sys.version}")
sys.exit(1)
print(f"✅ Python版本检查通过: {sys.version}")
def create_directories():
"""创建必要的目录"""
directories = [
'logs',
'static/uploads',
'static/css',
'static/js'
]
for directory in directories:
Path(directory).mkdir(parents=True, exist_ok=True)
print("✅ 目录结构创建完成")
def check_env_file():
"""检查环境配置文件"""
env_file = Path('.env')
if not env_file.exists():
print("⚠️ 未找到 .env 文件,正在创建默认配置...")
try:
with open('.env.example', 'r', encoding='utf-8') as src:
with open('.env', 'w', encoding='utf-8') as dst:
dst.write(src.read())
print("✅ 已创建默认 .env 文件")
except FileNotFoundError:
print("❌ 未找到 .env.example 文件")
return False
else:
print("✅ 环境配置文件已存在")
return True
def install_dependencies():
"""安装依赖"""
print("📦 正在安装依赖包...")
try:
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt'])
# 检查并安装生产环境依赖
try:
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'gunicorn'])
print("✅ Gunicorn安装完成")
except subprocess.CalledProcessError:
print("⚠️ Gunicorn安装失败")
print("✅ 依赖安装完成")
return True
except subprocess.CalledProcessError:
print("❌ 依赖安装失败")
return False
def init_database():
"""初始化数据库"""
print("🗄️ 正在初始化数据库...")
# 检查使用哪种数据库
env_file = Path('.env')
if env_file.exists():
with open(env_file, 'r', encoding='utf-8') as f:
content = f.read()
if 'DATABASE_URL=sqlite' in content:
init_script = 'init_db_sqlite.py'
else:
init_script = 'setup_mysql.py'
else:
# 默认使用SQLite
init_script = 'init_db_sqlite.py'
try:
if os.path.exists(init_script):
subprocess.check_call([sys.executable, init_script])
print("✅ 数据库初始化完成")
return True
else:
print(f"⚠️ 数据库初始化脚本 {init_script} 不存在")
return False
except subprocess.CalledProcessError as e:
print(f"❌ 数据库初始化失败: {e}")
return False
def setup_systemd_service():
"""配置Systemd服务"""
print("⚙️ 正在配置Systemd服务...")
# 获取当前路径
app_path = os.path.abspath('.')
venv_path = os.path.join(app_path, 'venv', 'bin', 'gunicorn')
# 如果没有虚拟环境使用系统gunicorn
if not os.path.exists(venv_path):
venv_path = 'gunicorn'
service_content = f"""[Unit]
Description=KaMiXiTong Service
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory={app_path}
Environment="FLASK_ENV=production"
ExecStart={venv_path} -w 4 -b 127.0.0.1:5000 run:app
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
"""
try:
# 写入服务文件
with open('/tmp/kamaxitong.service', 'w') as f:
f.write(service_content)
print("✅ Systemd服务配置文件已生成")
print("💡 请使用以下命令安装服务:")
print(" sudo cp /tmp/kamaxitong.service /etc/systemd/system/")
print(" sudo systemctl daemon-reload")
print(" sudo systemctl enable kamaxitong.service")
print(" sudo systemctl start kamaxitong.service")
return True
except Exception as e:
print(f"❌ Systemd服务配置失败: {e}")
return False
def setup_nginx_config():
"""配置Nginx"""
print("⚙️ 正在生成Nginx配置...")
# 从环境变量获取域名
frontend_domain = os.environ.get('FRONTEND_DOMAIN', '')
if frontend_domain:
# 移除协议部分
if '://' in frontend_domain:
server_name = frontend_domain.split('://', 1)[1]
else:
server_name = frontend_domain
else:
server_name = 'your-domain.com'
nginx_config = f"""server {{
listen 80;
server_name {server_name};
# 重定向到HTTPS可选
return 301 https://$server_name$request_uri;
}}
server {{
listen 443 ssl http2;
server_name {server_name};
# SSL证书配置请替换为实际路径
# ssl_certificate /path/to/your/certificate.crt;
# ssl_certificate_key /path/to/your/private.key;
# 安全头配置
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private must-revalidate auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss;
# 代理到Flask应用
location / {{
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;
proxy_set_header X-Forwarded-Host $server_name;
}}
# 静态文件直接由Nginx处理
location /static/ {{
alias {os.path.abspath('static')}/;
expires 1y;
add_header Cache-Control "public, immutable";
}}
# 日志配置
access_log /var/log/nginx/kamaxitong.access.log;
error_log /var/log/nginx/kamaxitong.error.log;
}}
"""
try:
# 写入配置文件
with open('/tmp/kamaxitong_nginx.conf', 'w') as f:
f.write(nginx_config)
print("✅ Nginx配置文件已生成")
print("💡 请使用以下命令安装配置:")
print(" sudo cp /tmp/kamaxitong_nginx.conf /etc/nginx/sites-available/kamaxitong")
print(" sudo ln -s /etc/nginx/sites-available/kamaxitong /etc/nginx/sites-enabled/")
print(" sudo nginx -t")
print(" sudo systemctl restart nginx")
return True
except Exception as e:
print(f"❌ Nginx配置生成失败: {e}")
return False
def main():
"""主函数"""
parser = argparse.ArgumentParser(description='KaMiXiTong 部署脚本')
parser.add_argument('--skip-install', action='store_true', help='跳过依赖安装')
parser.add_argument('--skip-db', action='store_true', help='跳过数据库初始化')
parser.add_argument('--setup-service', action='store_true', help='配置Systemd服务')
parser.add_argument('--setup-nginx', action='store_true', help='生成Nginx配置')
args = parser.parse_args()
print("=" * 50)
print(" KaMiXiTong 生产环境部署脚本")
print("=" * 50)
# 检查Python版本
check_python_version()
# 创建目录
create_directories()
# 检查环境配置
if not check_env_file():
sys.exit(1)
# 安装依赖
if not args.skip_install:
if not install_dependencies():
sys.exit(1)
else:
print("⏭️ 跳过依赖安装")
# 初始化数据库
if not args.skip_db:
if not init_database():
sys.exit(1)
else:
print("⏭️ 跳过数据库初始化")
# 配置Systemd服务
if args.setup_service:
setup_systemd_service()
# 配置Nginx
if args.setup_nginx:
setup_nginx_config()
print("\n" + "=" * 50)
print("✅ 部署准备完成!")
print("=" * 50)
if args.setup_service:
print("💡 已生成Systemd服务配置文件请按提示安装")
if args.setup_nginx:
print("💡 已生成Nginx配置文件请按提示安装")
print("\n📌 下一步操作:")
print("1. 编辑 .env 文件,配置数据库和其他参数")
print("2. 配置SSL证书推荐")
print("3. 启动服务")
print("4. 访问你的域名")
if __name__ == '__main__':
main()