Files
KnowledgeBase/docker/deploy-to-openeuler.sh
lizhuoran 3c206e9e06 feat: 新增 Docker 部署支持、Swoole/Octane 集成及相关优化
- 添加 Dockerfile 与多套 docker-compose 配置(开发/生产环境)
- 集成 Laravel Octane (Swoole) 提升性能
- 新增健康检查、监控脚本及部署文档
- 新增 Docker 镜像离线导入包(MySQL/Redis/Meilisearch)
- 优化文档转换、预览服务及队列任务
- 添加 CreateAdminUser 命令与路由健康检查接口
- 新增 Swoole 队列兼容性测试套件

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 15:51:19 +08:00

616 lines
14 KiB
Bash
Executable File
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.
#!/bin/bash
# OpenEuler服务器部署脚本
# 用于在OpenEuler服务器上部署Laravel知识库系统
set -e
# 脚本配置
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_NAME="knowledge-base"
DEPLOY_DIR="/opt/${PROJECT_NAME}"
BACKUP_DIR="/opt/${PROJECT_NAME}-backup"
LOG_FILE="/var/log/${PROJECT_NAME}-deploy.log"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log() {
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE"
}
log_success() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] ✓${NC} $1" | tee -a "$LOG_FILE"
}
log_warning() {
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] ⚠${NC} $1" | tee -a "$LOG_FILE"
}
log_error() {
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ✗${NC} $1" | tee -a "$LOG_FILE"
}
# 显示帮助信息
show_help() {
cat << EOF
OpenEuler服务器部署脚本
用法: $0 [选项] [镜像目录]
选项:
-h, --help 显示此帮助信息
-d, --deploy-dir DIR 部署目录 (默认: /opt/knowledge-base)
-b, --backup 部署前备份现有安装
-u, --update 更新现有部署
-r, --rollback 回滚到上一个版本
--skip-docker-install 跳过Docker安装
--skip-images 跳过镜像导入
--skip-env-setup 跳过环境配置
--dry-run 仅显示将要执行的操作
参数:
镜像目录 包含Docker镜像文件的目录
示例:
$0 /path/to/docker-images # 全新部署
$0 -u /path/to/docker-images # 更新现有部署
$0 -b -d /custom/path # 备份并部署到自定义目录
$0 --rollback # 回滚到上一个版本
EOF
}
# 默认配置
BACKUP=false
UPDATE=false
ROLLBACK=false
SKIP_DOCKER_INSTALL=false
SKIP_IMAGES=false
SKIP_ENV_SETUP=false
DRY_RUN=false
IMAGES_DIR=""
# 解析命令行参数
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-d|--deploy-dir)
DEPLOY_DIR="$2"
BACKUP_DIR="${DEPLOY_DIR}-backup"
shift 2
;;
-b|--backup)
BACKUP=true
shift
;;
-u|--update)
UPDATE=true
shift
;;
-r|--rollback)
ROLLBACK=true
shift
;;
--skip-docker-install)
SKIP_DOCKER_INSTALL=true
shift
;;
--skip-images)
SKIP_IMAGES=true
shift
;;
--skip-env-setup)
SKIP_ENV_SETUP=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
-*)
log_error "未知参数: $1"
show_help
exit 1
;;
*)
IMAGES_DIR="$1"
shift
;;
esac
done
# 检查是否以root权限运行
if [[ $EUID -ne 0 ]]; then
log_error "此脚本需要root权限运行"
exit 1
fi
# 创建日志目录
mkdir -p "$(dirname "$LOG_FILE")"
log "开始OpenEuler服务器部署..."
log "部署目录: $DEPLOY_DIR"
log "备份目录: $BACKUP_DIR"
log "镜像目录: $IMAGES_DIR"
# 检查系统信息
check_system() {
log "检查系统信息..."
# 检查操作系统
if [[ -f /etc/os-release ]]; then
source /etc/os-release
log "操作系统: $NAME $VERSION"
if [[ "$ID" != "openEuler" ]] && [[ "$ID_LIKE" != *"rhel"* ]]; then
log_warning "此脚本专为OpenEuler设计当前系统: $NAME"
read -p "是否继续? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
else
log_warning "无法检测操作系统版本"
fi
# 检查架构
local arch=$(uname -m)
log "系统架构: $arch"
if [[ "$arch" != "x86_64" ]]; then
log_warning "推荐使用x86_64架构当前: $arch"
fi
# 检查内存
local memory=$(free -h | awk '/^Mem:/ {print $2}')
log "系统内存: $memory"
# 检查磁盘空间
local disk_space=$(df -h / | awk 'NR==2 {print $4}')
log "可用磁盘空间: $disk_space"
}
# 安装Docker
install_docker() {
if [[ "$SKIP_DOCKER_INSTALL" == true ]]; then
log "跳过Docker安装"
return 0
fi
log "检查Docker安装状态..."
if command -v docker >/dev/null 2>&1; then
local docker_version=$(docker --version)
log "Docker已安装: $docker_version"
# 检查Docker是否运行
if systemctl is-active --quiet docker; then
log_success "Docker服务正在运行"
else
log "启动Docker服务..."
systemctl start docker
systemctl enable docker
log_success "Docker服务已启动"
fi
return 0
fi
log "安装Docker..."
if [[ "$DRY_RUN" == true ]]; then
log "[DRY RUN] 将安装Docker"
return 0
fi
# 更新系统包
dnf update -y
# 安装必要的包
dnf install -y dnf-plugins-core
# 添加Docker仓库
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装Docker
dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 启动Docker服务
systemctl start docker
systemctl enable docker
# 验证安装
if docker --version >/dev/null 2>&1; then
log_success "Docker安装成功"
else
log_error "Docker安装失败"
exit 1
fi
# 添加当前用户到docker组如果不是root
if [[ -n "$SUDO_USER" ]]; then
usermod -aG docker "$SUDO_USER"
log "已将用户 $SUDO_USER 添加到docker组"
fi
}
# 安装Docker Compose
install_docker_compose() {
log "检查Docker Compose..."
if docker compose version >/dev/null 2>&1; then
local compose_version=$(docker compose version)
log_success "Docker Compose已安装: $compose_version"
return 0
fi
log "安装Docker Compose..."
if [[ "$DRY_RUN" == true ]]; then
log "[DRY RUN] 将安装Docker Compose"
return 0
fi
# Docker Compose通常随Docker一起安装
# 如果没有,可以手动安装
if ! docker compose version >/dev/null 2>&1; then
log_error "Docker Compose未找到请手动安装"
exit 1
fi
}
# 备份现有部署
backup_existing() {
if [[ "$BACKUP" == false ]]; then
return 0
fi
if [[ ! -d "$DEPLOY_DIR" ]]; then
log "没有现有部署需要备份"
return 0
fi
log "备份现有部署..."
if [[ "$DRY_RUN" == true ]]; then
log "[DRY RUN] 将备份 $DEPLOY_DIR$BACKUP_DIR"
return 0
fi
# 停止现有服务
if [[ -f "$DEPLOY_DIR/docker-compose.yml" ]]; then
log "停止现有服务..."
cd "$DEPLOY_DIR"
docker compose down || true
fi
# 创建备份
local backup_name="${BACKUP_DIR}-$(date +%Y%m%d-%H%M%S)"
if cp -r "$DEPLOY_DIR" "$backup_name"; then
log_success "备份创建成功: $backup_name"
# 创建符号链接到最新备份
rm -f "$BACKUP_DIR"
ln -s "$backup_name" "$BACKUP_DIR"
else
log_error "备份创建失败"
exit 1
fi
}
# 回滚部署
rollback_deployment() {
if [[ "$ROLLBACK" == false ]]; then
return 0
fi
log "回滚部署..."
if [[ ! -L "$BACKUP_DIR" ]] || [[ ! -d "$BACKUP_DIR" ]]; then
log_error "没有找到备份,无法回滚"
exit 1
fi
if [[ "$DRY_RUN" == true ]]; then
log "[DRY RUN] 将从 $BACKUP_DIR 回滚"
return 0
fi
# 停止当前服务
if [[ -f "$DEPLOY_DIR/docker-compose.yml" ]]; then
log "停止当前服务..."
cd "$DEPLOY_DIR"
docker compose down || true
fi
# 恢复备份
rm -rf "$DEPLOY_DIR"
cp -r "$BACKUP_DIR" "$DEPLOY_DIR"
# 启动服务
cd "$DEPLOY_DIR"
docker compose up -d
log_success "回滚完成"
exit 0
}
# 导入Docker镜像
import_images() {
if [[ "$SKIP_IMAGES" == true ]]; then
log "跳过镜像导入"
return 0
fi
if [[ -z "$IMAGES_DIR" ]] || [[ ! -d "$IMAGES_DIR" ]]; then
log_error "镜像目录不存在或未指定: $IMAGES_DIR"
exit 1
fi
log "导入Docker镜像..."
# 查找镜像文件
local image_files=($(find "$IMAGES_DIR" -name "*.tar*" -type f))
if [[ ${#image_files[@]} -eq 0 ]]; then
log_error "$IMAGES_DIR 中没有找到镜像文件"
exit 1
fi
log "找到 ${#image_files[@]} 个镜像文件"
if [[ "$DRY_RUN" == true ]]; then
for file in "${image_files[@]}"; do
log "[DRY RUN] 将导入: $(basename "$file")"
done
return 0
fi
# 导入镜像
for file in "${image_files[@]}"; do
local filename=$(basename "$file")
log "导入镜像: $filename"
if [[ "$file" == *.gz ]]; then
# 解压并导入
if gunzip -c "$file" | docker load; then
log_success "镜像导入成功: $filename"
else
log_error "镜像导入失败: $filename"
exit 1
fi
else
# 直接导入
if docker load -i "$file"; then
log_success "镜像导入成功: $filename"
else
log_error "镜像导入失败: $filename"
exit 1
fi
fi
done
# 显示导入的镜像
log "已导入的镜像:"
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
}
# 设置部署环境
setup_deployment() {
log "设置部署环境..."
if [[ "$DRY_RUN" == true ]]; then
log "[DRY RUN] 将创建部署目录: $DEPLOY_DIR"
return 0
fi
# 创建部署目录
mkdir -p "$DEPLOY_DIR"
cd "$DEPLOY_DIR"
# 复制配置文件(如果镜像目录包含)
if [[ -n "$IMAGES_DIR" ]]; then
# 查找配置文件
local config_files=(
"docker-compose.yml"
".env.production"
"docker"
)
for config in "${config_files[@]}"; do
if [[ -e "$IMAGES_DIR/../$config" ]]; then
log "复制配置: $config"
cp -r "$IMAGES_DIR/../$config" .
fi
done
fi
# 创建必要的目录
mkdir -p storage/{mysql,redis,meilisearch,app,logs}
mkdir -p storage/logs/{app,queue}
# 设置权限
chown -R 1000:1000 storage/
chmod -R 755 storage/
log_success "部署环境设置完成"
}
# 配置环境变量
setup_environment() {
if [[ "$SKIP_ENV_SETUP" == true ]]; then
log "跳过环境配置"
return 0
fi
log "配置环境变量..."
local env_file="$DEPLOY_DIR/.env"
if [[ "$DRY_RUN" == true ]]; then
log "[DRY RUN] 将创建环境配置文件: $env_file"
return 0
fi
# 生成随机密钥
local app_key="base64:$(openssl rand -base64 32)"
local db_password=$(openssl rand -base64 16)
local meilisearch_key=$(openssl rand -base64 32)
# 创建环境配置文件
cat > "$env_file" << EOF
# Laravel知识库系统 - 生产环境配置
# 生成时间: $(date)
# 应用配置
APP_NAME="知识库系统"
APP_ENV=production
APP_KEY=$app_key
APP_DEBUG=false
APP_URL=http://localhost
# 数据库配置
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=knowledge_base
DB_USERNAME=knowledge_user
DB_PASSWORD=$db_password
# Redis配置
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=
# 缓存配置
CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
# 搜索配置
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://meilisearch:7700
MEILISEARCH_KEY=$meilisearch_key
# 日志配置
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=error
# 文件系统
FILESYSTEM_DISK=local
# 邮件配置
MAIL_MAILER=log
MAIL_HOST=localhost
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="\${APP_NAME}"
EOF
log_success "环境配置文件创建成功"
log_warning "请根据实际情况修改 $env_file 中的配置"
}
# 启动服务
start_services() {
log "启动服务..."
if [[ "$DRY_RUN" == true ]]; then
log "[DRY RUN] 将启动Docker Compose服务"
return 0
fi
cd "$DEPLOY_DIR"
# 检查配置文件
if [[ ! -f "docker-compose.yml" ]]; then
log_error "docker-compose.yml 文件不存在"
exit 1
fi
if [[ ! -f ".env" ]]; then
log_error ".env 文件不存在"
exit 1
fi
# 启动服务
if docker compose up -d; then
log_success "服务启动成功"
else
log_error "服务启动失败"
exit 1
fi
# 等待服务就绪
log "等待服务就绪..."
sleep 30
# 检查服务状态
docker compose ps
# 运行Laravel初始化命令
log "运行Laravel初始化..."
docker compose exec -T app php artisan migrate --force || log_warning "数据库迁移失败"
docker compose exec -T app php artisan storage:link || log_warning "存储链接创建失败"
log_success "部署完成!"
}
# 显示部署信息
show_deployment_info() {
log "部署信息:"
log "部署目录: $DEPLOY_DIR"
log "访问地址: http://$(hostname -I | awk '{print $1}')"
log "管理命令:"
log " 查看日志: cd $DEPLOY_DIR && docker compose logs -f"
log " 重启服务: cd $DEPLOY_DIR && docker compose restart"
log " 停止服务: cd $DEPLOY_DIR && docker compose down"
log " 更新应用: cd $DEPLOY_DIR && docker compose pull && docker compose up -d"
}
# 主执行流程
main() {
check_system
# 处理回滚
rollback_deployment
# 备份现有部署
backup_existing
# 安装Docker
install_docker
install_docker_compose
# 导入镜像
import_images
# 设置部署环境
setup_deployment
# 配置环境
setup_environment
# 启动服务
start_services
# 显示部署信息
show_deployment_info
}
# 执行主流程
main