#!/usr/bin/env bash # # DataOps Platform 生产部署脚本 # - 安装 /etc/dataops-platform/dataops.env # - 创建/更新虚拟环境 # - 配置 Supervisor,通过 run_dataops.sh 加载环境变量并启动 Gunicorn # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=dataops-common.sh source "${SCRIPT_DIR}/dataops-common.sh" PYTHON_BIN="${PYTHON_BIN:-python3}" RECREATE_VENV="${RECREATE_VENV:-0}" check_python() { echo_step "检查 Python..." if ! command -v "${PYTHON_BIN}" >/dev/null 2>&1; then echo_error "${PYTHON_BIN} 未安装" exit 1 fi echo_info "Python: $(${PYTHON_BIN} --version 2>&1)" if command -v apt-get >/dev/null 2>&1; then if ! dpkg -l 2>/dev/null | grep -q python3-venv; then echo_warn "安装 python3-venv / python3-pip..." apt-get update && apt-get install -y python3-venv python3-pip fi fi } check_supervisor_pkg() { echo_step "检查 Supervisor..." if ! command -v supervisord >/dev/null 2>&1; then if command -v apt-get >/dev/null 2>&1; then apt-get update && apt-get install -y supervisor systemctl enable supervisor systemctl start supervisor else echo_error "Supervisor 未安装" exit 1 fi fi echo_info "Supervisor 已就绪" } create_directories() { echo_step "创建目录..." mkdir -p "${APP_DIR}" "${LOG_DIR}" /data/upload /data/archive /var/log/supervisor chown -R "${APP_USER}:${APP_GROUP}" "${APP_DIR}" "${LOG_DIR}" /data/upload /data/archive echo_info "应用目录: ${APP_DIR}" echo_info "日志目录: ${LOG_DIR}" } setup_env_file() { echo_step "配置环境变量..." ensure_env_file "${SCRIPT_DIR}" normalize_env_file load_env_file ensure_env_file_permissions } setup_venv() { echo_step "配置 Python 虚拟环境..." if [[ "${RECREATE_VENV}" == "1" && -d "${VENV_DIR}" ]]; then echo_warn "重建虚拟环境: ${VENV_DIR}" rm -rf "${VENV_DIR}" fi if [[ ! -d "${VENV_DIR}" ]]; then sudo -u "${APP_USER}" "${PYTHON_BIN}" -m venv "${VENV_DIR}" fi "${VENV_DIR}/bin/pip" install --upgrade pip if [[ ! -f "${APP_DIR}/requirements.txt" ]]; then echo_error "缺少 ${APP_DIR}/requirements.txt" exit 1 fi "${VENV_DIR}/bin/pip" install -r "${APP_DIR}/requirements.txt" chown -R "${APP_USER}:${APP_GROUP}" "${VENV_DIR}" echo_info "依赖安装完成" } verify_app() { echo_step "验证应用..." load_env_file sudo -u "${APP_USER}" env APP_ENV_FILE="${ENV_FILE}" FLASK_ENV=production \ bash -c "set -a; source <(sed 's/\\r$//' '${ENV_FILE}' | sed '1s/^\\xEF\\xBB\\xBF//'); set +a; cd '${APP_DIR}'; '${VENV_DIR}/bin/python' -c \" from app import create_app app = create_app() print('Flask 应用创建成功') print('蓝图:', list(app.blueprints.keys())) \"" || { echo_error "应用验证失败,请检查 ${ENV_FILE} 中的数据库/Neo4j 等配置" exit 1 } echo_info "应用验证通过" } sync_ops_scripts() { echo_step "同步运维脚本..." mkdir -p "${APP_DIR}/scripts" install -m 755 "${SCRIPT_DIR}/run_dataops.sh" "${RUN_SCRIPT}" for script in deploy_dataops.sh start_dataops.sh stop_dataops.sh restart_dataops.sh dataops-common.sh; do if [[ -f "${SCRIPT_DIR}/${script}" ]]; then install -m 755 "${SCRIPT_DIR}/${script}" "${SCRIPTS_DIR}/${script}" fi done chown -R "${APP_USER}:${APP_GROUP}" "${SCRIPTS_DIR}" normalize_shell_scripts "${SCRIPTS_DIR}" ensure_run_script } start_application() { echo_step "启动应用..." supervisorctl restart "${APP_NAME}" 2>/dev/null || supervisorctl start "${APP_NAME}" sleep 8 local status status="$(supervisorctl status "${APP_NAME}" | awk '{print $2}')" if [[ "${status}" == "RUNNING" ]]; then echo_info "应用已运行" supervisorctl status "${APP_NAME}" else echo_error "应用启动失败,状态: ${status}" echo_info "查看日志: tail -f ${SUPERVISOR_LOG}" exit 1 fi } show_summary() { local app_port app_port="$(resolve_listen_port)" echo "" echo "==========================================" echo -e "${GREEN} 部署完成${NC}" echo "==========================================" echo " 应用目录: ${APP_DIR}" echo " 环境变量: ${ENV_FILE}" echo " 监听地址: ${LISTEN_HOST}:${app_port}" 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 " 健康: curl http://127.0.0.1:${app_port}/api/system/health" echo "" } main() { echo "==========================================" echo " DataOps Platform 部署脚本" echo "==========================================" require_root check_python check_supervisor_pkg create_directories setup_env_file ensure_wsgi "${SCRIPT_DIR}" setup_venv verify_app sync_ops_scripts load_env_file configure_supervisor start_application if ! health_check; then echo_error "部署完成但健康检查失败,请根据上方诊断信息排查" exit 1 fi show_summary } main "$@"