deploy_dataops.sh 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. local validator="${SCRIPT_DIR}/../app/config/database_urls.py"
  56. if [[ ! -f "${validator}" ]] || ! "${PYTHON_BIN}" "${validator}" --env-file "${ENV_FILE}"; then
  57. echo_error "数据库环境变量仍为空、格式错误或包含模板占位值"
  58. exit 2
  59. fi
  60. }
  61. setup_venv() {
  62. echo_step "配置 Python 虚拟环境..."
  63. if [[ "${RECREATE_VENV}" == "1" && -d "${VENV_DIR}" ]]; then
  64. echo_warn "重建虚拟环境: ${VENV_DIR}"
  65. rm -rf "${VENV_DIR}"
  66. fi
  67. if [[ ! -d "${VENV_DIR}" ]]; then
  68. sudo -u "${APP_USER}" "${PYTHON_BIN}" -m venv "${VENV_DIR}"
  69. fi
  70. "${VENV_DIR}/bin/pip" install --upgrade pip
  71. if [[ ! -f "${APP_DIR}/requirements.txt" ]]; then
  72. echo_error "缺少 ${APP_DIR}/requirements.txt"
  73. exit 1
  74. fi
  75. "${VENV_DIR}/bin/pip" install -r "${APP_DIR}/requirements.txt"
  76. chown -R "${APP_USER}:${APP_GROUP}" "${VENV_DIR}"
  77. echo_info "依赖安装完成"
  78. }
  79. verify_app() {
  80. echo_step "验证应用..."
  81. load_env_file
  82. sudo -u "${APP_USER}" env APP_ENV_FILE="${ENV_FILE}" FLASK_ENV=production \
  83. 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 \"
  84. from app import create_app
  85. app = create_app()
  86. print('Flask 应用创建成功')
  87. print('蓝图:', list(app.blueprints.keys()))
  88. \"" || {
  89. echo_error "应用验证失败,请检查 ${ENV_FILE} 中的数据库/Neo4j 等配置"
  90. exit 1
  91. }
  92. echo_info "应用验证通过"
  93. }
  94. sync_ops_scripts() {
  95. echo_step "同步运维脚本..."
  96. mkdir -p "${APP_DIR}/scripts"
  97. install -m 755 "${SCRIPT_DIR}/run_dataops.sh" "${RUN_SCRIPT}"
  98. for script in deploy_dataops.sh start_dataops.sh stop_dataops.sh restart_dataops.sh dataops-common.sh; do
  99. if [[ -f "${SCRIPT_DIR}/${script}" ]]; then
  100. install -m 755 "${SCRIPT_DIR}/${script}" "${SCRIPTS_DIR}/${script}"
  101. fi
  102. done
  103. chown -R "${APP_USER}:${APP_GROUP}" "${SCRIPTS_DIR}"
  104. normalize_shell_scripts "${SCRIPTS_DIR}"
  105. ensure_run_script
  106. }
  107. start_application() {
  108. echo_step "启动应用..."
  109. supervisorctl restart "${APP_NAME}" 2>/dev/null || supervisorctl start "${APP_NAME}"
  110. sleep 8
  111. local status
  112. status="$(supervisorctl status "${APP_NAME}" | awk '{print $2}')"
  113. if [[ "${status}" == "RUNNING" ]]; then
  114. echo_info "应用已运行"
  115. supervisorctl status "${APP_NAME}"
  116. else
  117. echo_error "应用启动失败,状态: ${status}"
  118. echo_info "查看日志: tail -f ${SUPERVISOR_LOG}"
  119. exit 1
  120. fi
  121. }
  122. show_summary() {
  123. local app_port
  124. app_port="$(resolve_listen_port)"
  125. echo ""
  126. echo "=========================================="
  127. echo -e "${GREEN} 部署完成${NC}"
  128. echo "=========================================="
  129. echo " 应用目录: ${APP_DIR}"
  130. echo " 环境变量: ${ENV_FILE}"
  131. echo " 监听地址: ${LISTEN_HOST}:${app_port}"
  132. echo ""
  133. echo " 启动: sudo ${APP_DIR}/scripts/start_dataops.sh"
  134. echo " 停止: sudo ${APP_DIR}/scripts/stop_dataops.sh"
  135. echo " 重启: sudo ${APP_DIR}/scripts/restart_dataops.sh"
  136. echo " 健康: curl http://127.0.0.1:${app_port}/api/system/health"
  137. echo ""
  138. }
  139. main() {
  140. echo "=========================================="
  141. echo " DataOps Platform 部署脚本"
  142. echo "=========================================="
  143. require_root
  144. check_python
  145. check_supervisor_pkg
  146. create_directories
  147. setup_env_file
  148. ensure_wsgi "${SCRIPT_DIR}"
  149. setup_venv
  150. verify_app
  151. sync_ops_scripts
  152. load_env_file
  153. configure_supervisor
  154. start_application
  155. if ! health_check; then
  156. echo_error "部署完成但健康检查失败,请根据上方诊断信息排查"
  157. exit 1
  158. fi
  159. show_summary
  160. }
  161. main "$@"