#!/bin/bash # # DataOps Platform 部署脚本 # 用于初始化或重建虚拟环境并配置 supervisor # set -e # 配置变量 APP_NAME="dataops-platform" APP_DIR="/opt/dataops-platform" VENV_DIR="${APP_DIR}/venv" LOG_DIR="${APP_DIR}/logs" PYTHON_VERSION="python3" SUPERVISOR_CONF="/etc/supervisor/conf.d/${APP_NAME}.conf" # Gunicorn 配置 GUNICORN_WORKERS=4 GUNICORN_BIND="0.0.0.0:80" GUNICORN_TIMEOUT=120 # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color echo_info() { echo -e "${GREEN}[INFO]${NC} $1" } echo_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } echo_error() { echo -e "${RED}[ERROR]${NC} $1" } echo_step() { echo -e "${BLUE}[STEP]${NC} $1" } # 检查是否以 root 或 sudo 运行 check_permissions() { if [ "$EUID" -ne 0 ]; then echo_error "请使用 sudo 运行此脚本" exit 1 fi } # 检查 Python 版本 check_python() { echo_step "检查 Python 版本..." if ! command -v ${PYTHON_VERSION} &> /dev/null; then echo_error "Python3 未安装" exit 1 fi python_ver=$(${PYTHON_VERSION} --version 2>&1 | awk '{print $2}') echo_info "Python 版本: ${python_ver}" # 检查 python3-venv if ! dpkg -l | grep -q python3-venv; then echo_warn "python3-venv 未安装,正在安装..." apt-get update && apt-get install -y python3-venv python3-pip fi } # 检查 supervisor check_supervisor() { echo_step "检查 Supervisor..." if ! command -v supervisord &> /dev/null; then echo_warn "Supervisor 未安装,正在安装..." apt-get update && apt-get install -y supervisor systemctl enable supervisor systemctl start supervisor fi echo_info "Supervisor 已安装" } # 创建目录结构 create_directories() { echo_step "创建目录结构..." mkdir -p ${LOG_DIR} chown -R ubuntu:ubuntu ${LOG_DIR} echo_info "日志目录: ${LOG_DIR}" } # 创建虚拟环境 create_venv() { echo_step "创建虚拟环境..." # 如果虚拟环境存在,先备份再删除 if [ -d "${VENV_DIR}" ]; then echo_warn "发现已存在的虚拟环境,正在删除..." rm -rf ${VENV_DIR} fi # 创建新的虚拟环境 ${PYTHON_VERSION} -m venv ${VENV_DIR} # 更新 pip ${VENV_DIR}/bin/pip install --upgrade pip echo_info "虚拟环境创建完成: ${VENV_DIR}" } # 安装依赖 install_dependencies() { echo_step "安装 Python 依赖..." if [ ! -f "${APP_DIR}/requirements.txt" ]; then echo_error "requirements.txt 不存在" exit 1 fi # 安装依赖 ${VENV_DIR}/bin/pip install -r ${APP_DIR}/requirements.txt # 确保 gunicorn 已安装 ${VENV_DIR}/bin/pip install gunicorn echo_info "依赖安装完成" # 显示已安装的关键包 echo_info "已安装的关键包:" ${VENV_DIR}/bin/pip list | grep -E "Flask|gunicorn|neo4j|SQLAlchemy|psycopg2" } # 验证安装 verify_installation() { echo_step "验证安装..." # 测试导入 cd ${APP_DIR} ${VENV_DIR}/bin/python -c " from app import create_app app = create_app() print('Flask 应用创建成功') print(f'已注册的蓝图: {list(app.blueprints.keys())}') " || { echo_error "应用验证失败" exit 1 } echo_info "应用验证通过" } # 创建 Gunicorn 配置文件 create_gunicorn_config() { echo_step "创建 Gunicorn 配置..." cat > ${APP_DIR}/gunicorn.conf.py << EOF # Gunicorn 配置文件 import multiprocessing # 绑定地址 bind = "${GUNICORN_BIND}" # Worker 进程数 workers = ${GUNICORN_WORKERS} # Worker 类型 worker_class = "sync" # 超时时间 timeout = ${GUNICORN_TIMEOUT} # 优雅重启超时 graceful_timeout = 30 # 保持连接时间 keepalive = 5 # 最大请求数(防止内存泄漏) max_requests = 1000 max_requests_jitter = 50 # 日志配置 accesslog = "${LOG_DIR}/gunicorn_access.log" errorlog = "${LOG_DIR}/gunicorn_error.log" loglevel = "info" # 进程名 proc_name = "${APP_NAME}" # 工作目录 chdir = "${APP_DIR}" # 预加载应用 preload_app = True # 环境变量 raw_env = [ "FLASK_ENV=production", ] EOF chown ubuntu:ubuntu ${APP_DIR}/gunicorn.conf.py echo_info "Gunicorn 配置文件已创建: ${APP_DIR}/gunicorn.conf.py" } # 创建 WSGI 入口文件 create_wsgi() { echo_step "创建 WSGI 入口文件..." cat > ${APP_DIR}/wsgi.py << 'EOF' """ WSGI 入口文件 用于 Gunicorn 启动 Flask 应用 """ from app import create_app application = create_app() if __name__ == "__main__": application.run() EOF chown ubuntu:ubuntu ${APP_DIR}/wsgi.py echo_info "WSGI 入口文件已创建: ${APP_DIR}/wsgi.py" } # 配置 Supervisor configure_supervisor() { echo_step "配置 Supervisor..." cat > ${SUPERVISOR_CONF} << EOF [program:${APP_NAME}] command=${VENV_DIR}/bin/gunicorn -c ${APP_DIR}/gunicorn.conf.py wsgi:application directory=${APP_DIR} user=ubuntu autostart=true autorestart=true stopasgroup=true killasgroup=true redirect_stderr=true stdout_logfile=${LOG_DIR}/supervisor_stdout.log stderr_logfile=${LOG_DIR}/supervisor_stderr.log environment=FLASK_ENV="production",PATH="${VENV_DIR}/bin:%(ENV_PATH)s" EOF echo_info "Supervisor 配置已创建: ${SUPERVISOR_CONF}" # 重新加载 supervisor 配置 supervisorctl reread supervisorctl update echo_info "Supervisor 配置已更新" } # 设置文件权限 set_permissions() { echo_step "设置文件权限..." chown -R ubuntu:ubuntu ${APP_DIR} chmod +x ${APP_DIR}/scripts/*.sh 2>/dev/null || true echo_info "文件权限设置完成" } # 启动应用 start_application() { echo_step "启动应用..." supervisorctl start ${APP_NAME} sleep 3 status=$(supervisorctl status ${APP_NAME} | awk '{print $2}') if [ "$status" = "RUNNING" ]; then echo_info "应用启动成功!" supervisorctl status ${APP_NAME} else echo_error "应用启动失败,请检查日志" echo_info "查看日志: tail -f ${LOG_DIR}/gunicorn_error.log" exit 1 fi } # 健康检查 health_check() { echo_step "执行健康检查..." sleep 3 response=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:80/api/system/health 2>/dev/null || echo "000") if [ "$response" = "200" ]; then echo_info "健康检查通过! HTTP 状态码: ${response}" else echo_warn "健康检查返回状态码: ${response}" echo_info "服务可能需要更多时间启动" fi } # 显示部署信息 show_summary() { echo "" echo "==========================================" echo -e "${GREEN} 部署完成!${NC}" echo "==========================================" echo "" echo "应用信息:" echo " - 应用名称: ${APP_NAME}" echo " - 应用目录: ${APP_DIR}" echo " - 虚拟环境: ${VENV_DIR}" echo " - 日志目录: ${LOG_DIR}" echo " - 监听地址: ${GUNICORN_BIND}" echo "" echo "常用命令:" echo " - 启动: sudo ${APP_DIR}/scripts/start_dataops.sh" echo " - 停止: sudo ${APP_DIR}/scripts/stop_dataops.sh" echo " - 重启: sudo ${APP_DIR}/scripts/restart_dataops.sh" echo " - 状态: sudo supervisorctl status ${APP_NAME}" echo " - 日志: tail -f ${LOG_DIR}/gunicorn_error.log" echo "" echo "Supervisor 命令:" echo " - sudo supervisorctl status" echo " - sudo supervisorctl restart ${APP_NAME}" echo " - sudo supervisorctl tail -f ${APP_NAME}" echo "" } # 主函数 main() { echo "==========================================" echo " DataOps Platform 部署脚本" echo "==========================================" echo "" check_permissions check_python check_supervisor create_directories create_venv install_dependencies verify_installation create_gunicorn_config create_wsgi configure_supervisor set_permissions start_application health_check show_summary } main "$@"