deploy_dataops.sh 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #!/usr/bin/env bash
  2. #
  3. # DataOps Platform 生产部署脚本
  4. # - 安装 /etc/dataops-platform/dataops.env
  5. # - 创建/更新虚拟环境
  6. # - 配置 Supervisor,通过 run_dataops.sh 加载环境变量并启动 Gunicorn
  7. #
  8. set -euo pipefail
  9. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  10. # shellcheck source=dataops-common.sh
  11. source "${SCRIPT_DIR}/dataops-common.sh"
  12. PYTHON_BIN="${PYTHON_BIN:-python3}"
  13. RECREATE_VENV="${RECREATE_VENV:-0}"
  14. check_python() {
  15. echo_step "检查 Python..."
  16. if ! command -v "${PYTHON_BIN}" >/dev/null 2>&1; then
  17. echo_error "${PYTHON_BIN} 未安装"
  18. exit 1
  19. fi
  20. echo_info "Python: $(${PYTHON_BIN} --version 2>&1)"
  21. if command -v apt-get >/dev/null 2>&1; then
  22. if ! dpkg -l 2>/dev/null | grep -q python3-venv; then
  23. echo_warn "安装 python3-venv / python3-pip..."
  24. apt-get update && apt-get install -y python3-venv python3-pip
  25. fi
  26. fi
  27. }
  28. check_supervisor_pkg() {
  29. echo_step "检查 Supervisor..."
  30. if ! command -v supervisord >/dev/null 2>&1; then
  31. if command -v apt-get >/dev/null 2>&1; then
  32. apt-get update && apt-get install -y supervisor
  33. systemctl enable supervisor
  34. systemctl start supervisor
  35. else
  36. echo_error "Supervisor 未安装"
  37. exit 1
  38. fi
  39. fi
  40. echo_info "Supervisor 已就绪"
  41. }
  42. create_directories() {
  43. echo_step "创建目录..."
  44. mkdir -p "${APP_DIR}" "${LOG_DIR}" /data/upload /data/archive /var/log/supervisor
  45. chown -R "${APP_USER}:${APP_GROUP}" "${APP_DIR}" "${LOG_DIR}" /data/upload /data/archive
  46. echo_info "应用目录: ${APP_DIR}"
  47. echo_info "日志目录: ${LOG_DIR}"
  48. }
  49. setup_env_file() {
  50. echo_step "配置环境变量..."
  51. ensure_env_file "${SCRIPT_DIR}"
  52. normalize_env_file
  53. load_env_file
  54. ensure_env_file_permissions
  55. }
  56. setup_venv() {
  57. echo_step "配置 Python 虚拟环境..."
  58. if [[ "${RECREATE_VENV}" == "1" && -d "${VENV_DIR}" ]]; then
  59. echo_warn "重建虚拟环境: ${VENV_DIR}"
  60. rm -rf "${VENV_DIR}"
  61. fi
  62. if [[ ! -d "${VENV_DIR}" ]]; then
  63. sudo -u "${APP_USER}" "${PYTHON_BIN}" -m venv "${VENV_DIR}"
  64. fi
  65. "${VENV_DIR}/bin/pip" install --upgrade pip
  66. if [[ ! -f "${APP_DIR}/requirements.txt" ]]; then
  67. echo_error "缺少 ${APP_DIR}/requirements.txt"
  68. exit 1
  69. fi
  70. "${VENV_DIR}/bin/pip" install -r "${APP_DIR}/requirements.txt"
  71. chown -R "${APP_USER}:${APP_GROUP}" "${VENV_DIR}"
  72. echo_info "依赖安装完成"
  73. }
  74. verify_app() {
  75. echo_step "验证应用..."
  76. load_env_file
  77. sudo -u "${APP_USER}" env APP_ENV_FILE="${ENV_FILE}" FLASK_ENV=production \
  78. 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 \"
  79. from app import create_app
  80. app = create_app()
  81. print('Flask 应用创建成功')
  82. print('蓝图:', list(app.blueprints.keys()))
  83. \"" || {
  84. echo_error "应用验证失败,请检查 ${ENV_FILE} 中的数据库/Neo4j 等配置"
  85. exit 1
  86. }
  87. echo_info "应用验证通过"
  88. }
  89. sync_ops_scripts() {
  90. echo_step "同步运维脚本..."
  91. mkdir -p "${APP_DIR}/scripts"
  92. install -m 755 "${SCRIPT_DIR}/run_dataops.sh" "${RUN_SCRIPT}"
  93. for script in deploy_dataops.sh start_dataops.sh stop_dataops.sh restart_dataops.sh dataops-common.sh; do
  94. if [[ -f "${SCRIPT_DIR}/${script}" ]]; then
  95. install -m 755 "${SCRIPT_DIR}/${script}" "${SCRIPTS_DIR}/${script}"
  96. fi
  97. done
  98. chown -R "${APP_USER}:${APP_GROUP}" "${SCRIPTS_DIR}"
  99. normalize_shell_scripts "${SCRIPTS_DIR}"
  100. ensure_run_script
  101. }
  102. start_application() {
  103. echo_step "启动应用..."
  104. supervisorctl restart "${APP_NAME}" 2>/dev/null || supervisorctl start "${APP_NAME}"
  105. sleep 8
  106. local status
  107. status="$(supervisorctl status "${APP_NAME}" | awk '{print $2}')"
  108. if [[ "${status}" == "RUNNING" ]]; then
  109. echo_info "应用已运行"
  110. supervisorctl status "${APP_NAME}"
  111. else
  112. echo_error "应用启动失败,状态: ${status}"
  113. echo_info "查看日志: tail -f ${SUPERVISOR_LOG}"
  114. exit 1
  115. fi
  116. }
  117. show_summary() {
  118. local app_port
  119. app_port="$(resolve_listen_port)"
  120. echo ""
  121. echo "=========================================="
  122. echo -e "${GREEN} 部署完成${NC}"
  123. echo "=========================================="
  124. echo " 应用目录: ${APP_DIR}"
  125. echo " 环境变量: ${ENV_FILE}"
  126. echo " 监听地址: ${LISTEN_HOST}:${app_port}"
  127. echo ""
  128. echo " 启动: sudo ${APP_DIR}/scripts/start_dataops.sh"
  129. echo " 停止: sudo ${APP_DIR}/scripts/stop_dataops.sh"
  130. echo " 重启: sudo ${APP_DIR}/scripts/restart_dataops.sh"
  131. echo " 健康: curl http://127.0.0.1:${app_port}/api/system/health"
  132. echo ""
  133. }
  134. main() {
  135. echo "=========================================="
  136. echo " DataOps Platform 部署脚本"
  137. echo "=========================================="
  138. require_root
  139. check_python
  140. check_supervisor_pkg
  141. create_directories
  142. setup_env_file
  143. ensure_wsgi "${SCRIPT_DIR}"
  144. setup_venv
  145. verify_app
  146. sync_ops_scripts
  147. load_env_file
  148. configure_supervisor
  149. start_application
  150. if ! health_check; then
  151. echo_error "部署完成但健康检查失败,请根据上方诊断信息排查"
  152. exit 1
  153. fi
  154. show_summary
  155. }
  156. main "$@"