Compare commits

..

1 Commits
main ... main

16 changed files with 269 additions and 1300 deletions

View File

@ -0,0 +1,71 @@
# =============================================================================
# ComfyAI Web 静态资源 CDN 初始化配置
# 用于 comfyAI-web-init 容器:构建后上传前端静态资源到 OSS/CDN
# 部署时请根据实际使用的 OSS 服务商填写对应配置
# =============================================================================
# -----------------------------------------------------------------------------
# 基础开关与路径
# -----------------------------------------------------------------------------
# 是否启用静态资源 CDN 加速
# true: 构建完成后将静态资源上传至 OSS前端通过 CDN 地址加载
# false: 不启用,静态资源随应用一起部署(不推荐生产环境)
STATIC_CDN_ENABLED=true
# 前端静态资源在 OSS 中的根目录(桶内路径前缀)
# 例如: static / frontend-assets
# 与 STATIC_CDN_BASE_URL 末尾路径保持一致,用于上传时的目录划分
STATIC_CDN_ROOT_PATH=static
# 静态资源的完整访问基础 URL不含末尾斜杠
# 用户访问前端时加载 JS/CSS/图片的根地址
# 示例: https://cdn.example.com/static 或 http://minio.example.com:9000/bucket/frontend-assets
STATIC_CDN_BASE_URL=https://cdn.example.com/static
# -----------------------------------------------------------------------------
# OSS 服务商与连接配置
# -----------------------------------------------------------------------------
# OSS 服务商类型(小写)
# 可选: aliyun | tencent | minio | qiniu | s3Compatible
# aliyun=阿里云 OSS, tencent=腾讯云 COS, minio=MinIO, qiniu=七牛云, s3Compatible=兼容 S3 的存储
STATIC_CDN_OSS_PROVIDER=aliyun
# OSS 服务端点Endpoint
# 阿里云: oss-cn-shanghai.aliyuncs.com
# 腾讯云: cos.ap-guangzhou.myqcloud.com
# MinIO: minio.example.com 或 宿主机访问容器时用 host.docker.internal
# 七牛: 无需填写 endpoint使用 region
STATIC_CDN_OSS_ENDPOINT=oss-cn-shanghai.aliyuncs.com
# OSS 存储桶名称Bucket
# 需提前在对应云控制台或 MinIO 中创建好
STATIC_CDN_OSS_BUCKET=your_bucket
# OSS Access Key ID访问密钥 ID
STATIC_CDN_OSS_ACCESS_KEY=your_access_key_id
# OSS Secret Access Key访问密钥 Secret
# 请勿提交到版本库,生产环境建议使用密钥管理服务
STATIC_CDN_OSS_SECRET_KEY=your_secret_access_key
# OSS 区域Region部分服务商必填
# 阿里云: oss-cn-shanghai
# 腾讯云: ap-guangzhou
# MinIO/自建: 可留空或填 us-east-1
# 七牛: 如 z0华东
STATIC_CDN_OSS_REGION=oss-cn-shanghai
# 自定义域名(可选)
# 若通过自有域名访问 OSS如 cdn.example.com在此填写否则留空将使用 endpoint + bucket 生成地址
STATIC_CDN_OSS_DOMAIN=
# OSS 服务端口(可选)
# 非标准端口时填写,如 MinIO 默认 9000标准 80/443 可留空
STATIC_CDN_OSS_PORT=
# 连接 OSS 时是否使用 HTTPS
# true: 使用 https生产推荐
# false: 使用 http本地 MinIO 调试时可设为 false
STATIC_CDN_OSS_USE_SSL=true

View File

@ -88,14 +88,6 @@ CONFIG_TOKEN_SIGN_SK=easyai2025easyai
#MINIO_ROOT_USER=minioadmin #MINIO_ROOT_USER=minioadmin
#MINIO_ROOT_PASSWORD=minioadmin #MINIO_ROOT_PASSWORD=minioadmin
# VideoEdit OSS 配置PDF 解析图片上传,填写 .env.tools 或在此覆盖)
# OSS_ENDPOINT=
# OSS_ACCESS_KEY_ID=
# OSS_ACCESS_KEY_SECRET=
# OSS_BUCKET=
# OSS_REGION=us-east-1
# OSS_DOMAIN=

View File

@ -1,38 +0,0 @@
# 在 Windows 上测试 start.ps1DRY_RUN 模式,不启动 Docker
name: Test start.ps1 (Windows)
on:
push:
paths:
- 'start.ps1'
- '.env.sample'
- '.github/workflows/test-start-ps1.yml'
pull_request:
paths:
- 'start.ps1'
- '.env.sample'
- '.github/workflows/test-start-ps1.yml'
workflow_dispatch:
jobs:
test-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Run start.ps1 (DRY_RUN)
env:
DEPLOY_DRY_RUN: "1"
DEPLOY_IP: "192.168.1.100"
run: |
powershell -ExecutionPolicy Bypass -File .\start.ps1
- name: Verify .env
run: |
$api = Select-String -Path .env -Pattern '^NUXT_PUBLIC_BASE_APIURL=' | ForEach-Object { $_.Line }
$socket = Select-String -Path .env -Pattern '^NUXT_PUBLIC_BASE_SOCKETURL=' | ForEach-Object { $_.Line }
$sg = Select-String -Path .env -Pattern '^NUXT_PUBLIC_SG_APIURL=' | ForEach-Object { $_.Line }
if ($api -ne 'NUXT_PUBLIC_BASE_APIURL=http://192.168.1.100:3001') { exit 1 }
if ($socket -ne 'NUXT_PUBLIC_BASE_SOCKETURL=ws://192.168.1.100:3002') { exit 1 }
if ($sg -ne 'NUXT_PUBLIC_SG_APIURL=http://192.168.1.100:3003') { exit 1 }
Write-Host "OK: .env 配置正确"

View File

@ -1,23 +1,3 @@
## 一键部署
### Linux
```bash
git clone https://git.51easyai.com/wangbo/easyai.git && cd easyai && chmod +x start.sh && ./start.sh
```
### Windows
```powershell
git clone https://git.51easyai.com/wangbo/easyai.git; cd easyai; powershell -ExecutionPolicy Bypass -File .\start.ps1
```
> **Windows 脚本权限说明**PowerShell 默认禁止运行脚本,直接双击 `start.ps1` 会闪退。
>
> - **推荐**:使用 `powershell -ExecutionPolicy Bypass -File .\start.ps1` 执行,无需修改系统策略
> - **或**:以管理员身份打开 PowerShell执行 `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`,之后可直接运行 `.\start.ps1`
---
## 重要更新记录: ## 重要更新记录:
@ -267,46 +247,6 @@ chmod +x start.sh
``` ```
6. 脚本运行完成无错误,并且提示`EasyAI应用启动成功`表示应用启动成功打开浏览器输入服务器的公网ip3010或者局域网IP3010即可访问EasyAI应用 6. 脚本运行完成无错误,并且提示`EasyAI应用启动成功`表示应用启动成功打开浏览器输入服务器的公网ip3010或者局域网IP3010即可访问EasyAI应用
## Windows 一键启动
start.ps1 脚本用于 Windows 本机/局域网一键部署 EasyAI 应用。**不要直接双击运行**(会闪退),请按以下方式执行:
### 权限配置(首次执行必做)
PowerShell 默认可能禁止运行脚本,需先执行以下任一方式:
**方式一:临时允许本次运行(推荐)**
```powershell
powershell -ExecutionPolicy Bypass -File .\start.ps1
```
**方式二:为当前用户永久放开脚本执行权限**
```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
执行后再运行 `.\start.ps1` 即可。
### 启动步骤
1. 克隆并进入目录
```powershell
git clone https://git.51easyai.com/wangbo/easyai.git
cd easyai
```
2. 在 PowerShell 或 CMD 中运行(二选一)
```powershell
# 若已设置 ExecutionPolicy可直接执行
.\start.ps1
# 未设置时使用 Bypass 方式
powershell -ExecutionPolicy Bypass -File .\start.ps1
```
3. 按提示选择 [1] 本地访问 或 [2] 局域网访问,脚本将自动配置并启动 Docker 服务。
4. 若窗口闪退,可查看日志 `start.ps1.log`(与 start.ps1 同目录,或 `%TEMP%\start.ps1.log`)获取退出原因。
### 启用HTTPS ### 启用HTTPS
1. [更改为你的域名]修改`easyai-proxy.conf`中域名`51easyai.com`为你的域名[可以使用Ctrl+F批量替换51easyai.com为你的域名] 1. [更改为你的域名]修改`easyai-proxy.conf`中域名`51easyai.com`为你的域名[可以使用Ctrl+F批量替换51easyai.com为你的域名]
2. [修改.env文件]修改如下两个环境变量为如下的对应的值 2. [修改.env文件]修改如下两个环境变量为如下的对应的值

View File

@ -1,43 +0,0 @@
## 部署配置,通过问答让用户选择
1. 通过IP地址还是通过域名访问
2. 如果通过IP地址访问输入服务器IP并保证300130023003三个端口已经开放
3. 如果通过域名访问输入域名不含https://的前缀例如51easyai.com
3.1 是否启用https访问
4. 对于IP地址访问的情形复制`.env.sample`为`.env`,并将NUXT_PUBLIC_BASE_APIURL、NUXT_PUBLIC_BASE_SOCKETURL、NUXT_PUBLIC_SG_APIURL三个分别进行如下设置
```bash
NUXT_PUBLIC_BASE_APIURL=http://<用户输入的IP地址>:3001
NUXT_PUBLIC_BASE_SOCKETURL=ws://<用户输入的IP地址>:3002
NUXT_PUBLIC_SG_APIURL=http://<用户输入的IP地址>:3003
```
5. 对于使用域名的情况下情况,复制`.env.sampla`为`.env`,将上述3个变量设置为
```bash
NUXT_PUBLIC_BASE_APIURL=/api
NUXT_PUBLIC_BASE_SOCKETURL=wss://<用户输入的域名>/socket.io
NUXT_PUBLIC_SG_APIURL=/asg-api
```
6. 复制 `.env.tools.sample`为`.env.tools`,复制`.env.ASG.sample`为`.env.ASG.sample`
7. 对于使用域名的情况下,将`easyai-proxy.conf.sample`复制为`easyai-proxy.conf`,并将文件名修改为`用户输入的域名.conf`,并将`51easyai.com`替换为用户的域名
8. 执行原来的start脚本内容包括安装docker安装和部署
9. 如果启用https访问还要同步执行原来的https脚本
## 平台要求需要兼容主流的linux云平台
## 部署要求
直接通过一个命令访问,包含自动从https://git.51easyai.com/wangbo/easyai克隆项目
```
bash -c https://git.51easyai.com/wangbo/easyai/src/branch/main/start.sh
```

View File

@ -2,6 +2,31 @@
# (各项参数均有详细的说明,理论情况下保持默认即可运行) # (各项参数均有详细的说明,理论情况下保持默认即可运行)
#version: '3' #version: '3'
services: services:
comfyAI-web-init:
container_name: comfyAI-web-init
image: registry.cn-shanghai.aliyuncs.com/comfy-ai/one-ai:${VERSION}
labels:
- "com.centurylinklabs.watchtower.enable=true"
entrypoint: [ "sh", "-c", "node .output/scripts/static-upload-init.mjs && touch /tmp/init-done && exec sleep infinity" ]
restart: unless-stopped
healthcheck:
test: [ "CMD", "test", "-f", "/tmp/init-done" ]
interval: 5s
timeout: 3s
retries: 60
start_period: 120s
networks:
comfyai:
ipv4_address: 172.21.0.15
volumes:
- ./data/cdn-init:/tmp/cdn-init
env_file:
- .env.comfyAI-web-init
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"
comfyAI-web: comfyAI-web:
container_name: comfyAI-web container_name: comfyAI-web
#更新修改冒号后面的版本号 #更新修改冒号后面的版本号
@ -15,11 +40,15 @@ services:
volumes: volumes:
# 这一行是关键。它将一个名为 './data/forend/.pm2' 的持久化卷挂载到容器内的 /app/.pm2 目录 # 这一行是关键。它将一个名为 './data/forend/.pm2' 的持久化卷挂载到容器内的 /app/.pm2 目录
- ./data/forend/.pm2:/app/.pm2 - ./data/forend/.pm2:/app/.pm2
- ./data/cdn-init:/tmp/cdn-init:ro
networks: networks:
comfyai: comfyai:
ipv4_address: 172.21.0.8 ipv4_address: 172.21.0.8
depends_on: depends_on:
- comfy-server comfy-server:
condition: service_started
comfyAI-web-init:
condition: service_healthy
restart: unless-stopped restart: unless-stopped
environment: environment:
# 默认服务器地址本地不需要更改云服务需要修改为云端IP并放行对应端口 # 默认服务器地址本地不需要更改云服务需要修改为云端IP并放行对应端口
@ -204,11 +233,8 @@ services:
max-size: "100m" max-size: "100m"
max-file: "10" max-file: "10"
rabbitmq: rabbitmq:
# image: rabbitmq:4-management # 官方地址,需可访问外网 image: registry.cn-shanghai.aliyuncs.com/easyaigc/mq:latest #阿里云镜像加速
image: registry.cn-shanghai.aliyuncs.com/easyaigc/mq:latest # 阿里云镜像 # image: rabbitmq:4-management #官方原版镜像
# image: docker.m.daocloud.io/library/rabbitmq:4-management # 国内网络可访问
labels:
- "com.centurylinklabs.watchtower.enable=true"
container_name: rabbitmq container_name: rabbitmq
restart: unless-stopped restart: unless-stopped
environment: environment:
@ -247,36 +273,25 @@ services:
video-edit: video-edit:
image: registry.cn-shanghai.aliyuncs.com/easyaigc/videoedit:latest image: registry.cn-shanghai.aliyuncs.com/easyaigc/videoedit:latest
container_name: video-edit container_name: video-edit
platform: linux/amd64
labels: labels:
- 'com.centurylinklabs.watchtower.enable=true' - "com.centurylinklabs.watchtower.enable=true"
volumes: volumes:
- ./data/videoedit/temp:/app/temp - ./data/videoedit/temp:/app/temp
ports: ports:
- '${VIDEO_EDIT_PORT}:8000' - "${VIDEO_EDIT_PORT}:8000"
env_file:
- .env.tools
environment: environment:
- PYTHONUNBUFFERED=1 - PYTHONUNBUFFERED=1
- OMP_NUM_THREADS=4 - OMP_NUM_THREADS=4
- OPENBLAS_NUM_THREADS=4 - OPENBLAS_NUM_THREADS=4
ipc: host env_file:
shm_size: 3g - .env.tools
cap_add: shm_size: 2g
- SYS_ADMIN
init: true
restart: unless-stopped restart: unless-stopped
networks: networks:
comfyai: comfyai:
ipv4_address: 172.21.0.10 ipv4_address: 172.21.0.10
healthcheck: healthcheck:
test: test: [ "CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/docs')" ]
[
'CMD',
'python',
'-c',
"import urllib.request; urllib.request.urlopen('http://localhost:8000/docs')",
]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
@ -293,12 +308,6 @@ services:
- ./data:/data - ./data:/data
ports: ports:
- 8080:8080 - 8080:8080
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "3"
sandbox: sandbox:
image: registry.cn-shanghai.aliyuncs.com/easyaigc/sandbox:latest image: registry.cn-shanghai.aliyuncs.com/easyaigc/sandbox:latest
container_name: sandbox container_name: sandbox
@ -359,8 +368,7 @@ services:
POSTGRES_PASSWORD: ${ASG_POSTGRES_PASSWORD:-easyai2025} POSTGRES_PASSWORD: ${ASG_POSTGRES_PASSWORD:-easyai2025}
POSTGRES_DB: ${ASG_POSTGRES_DB:-agent_governance} POSTGRES_DB: ${ASG_POSTGRES_DB:-agent_governance}
volumes: volumes:
# PG 18+ 数据目录改为 /var/lib/postgresql/18/docker需挂载父目录 /var/lib/postgresql - asg_postgres_data:/var/lib/postgresql/data
- asg_postgres_data:/var/lib/postgresql
networks: networks:
comfyai: comfyai:
ipv4_address: 172.21.0.13 ipv4_address: 172.21.0.13

View File

@ -1,33 +0,0 @@
# EasyAI 部署脚本验证环境
# 在 Docker 容器内运行 start.sh通过挂载 Docker Socket 使用宿主机 Docker 启动服务
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
ca-certificates \
gnupg \
lsb-release \
git \
sudo \
&& rm -rf /var/lib/apt/lists/*
# 安装 Docker CLI使用宿主机 Docker 守护进程)
RUN install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \
&& chmod a+r /etc/apt/keyrings/docker.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends docker-ce-cli docker-compose-plugin \
&& rm -rf /var/lib/apt/lists/*
# 创建工作目录
WORKDIR /workspace/easyai
# 复制项目文件(运行时通过 volume 挂载覆盖)
COPY . /workspace/easyai/
# 允许以 root 运行(容器内通常为 root
ENV DEPLOY_ACCESS=ip
ENV DEPLOY_IP=127.0.0.1

View File

@ -1,24 +0,0 @@
#!/bin/bash
# 快速验证:仅测试配置生成,不拉取镜像、不启动服务
# 适合 CI 或快速检查脚本逻辑
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
echo "================================"
echo " EasyAI 部署脚本快速验证"
echo " (仅配置,不启动 Docker)"
echo "================================"
# 使用管道模拟用户输入1=IP模式, 127.0.0.1=IP地址
printf '1\n127.0.0.1\n' | DEPLOY_DRY_RUN=1 DEPLOY_FORCE_RECONFIG=1 ./start.sh
echo ""
echo "✅ 配置验证通过,检查生成的文件:"
ls -la .env .env.tools .env.ASG 2>/dev/null || true
echo ""
grep -E "NUXT_PUBLIC_(BASE_APIURL|BASE_SOCKETURL|SG_APIURL)" .env 2>/dev/null | head -3

View File

@ -1,46 +0,0 @@
#!/bin/bash
# 在 Docker 容器中验证 EasyAI 部署脚本
# 用法: 在 easyai 项目根目录执行 ./docker/verify/run-verify.sh
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
echo "================================"
echo " EasyAI 部署脚本 Docker 验证"
echo "================================"
echo "项目目录: $PROJECT_ROOT"
echo ""
# 构建验证镜像
echo "📦 构建验证镜像..."
docker build -f docker/verify/Dockerfile -t easyai-deploy-verify:latest .
echo ""
echo "🚀 运行部署脚本(非交互模式,挂载 Docker Socket..."
echo " 使用 DEPLOY_ACCESS=ip DEPLOY_IP=127.0.0.1"
echo ""
# 挂载 Docker Socket使容器内 docker 命令使用宿主机 Docker
# 挂载项目目录,使用本地文件(避免容器内复制过时)
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$PROJECT_ROOT:/workspace/easyai" \
-w /workspace/easyai \
-e DEPLOY_ACCESS=ip \
-e DEPLOY_IP=127.0.0.1 \
-e DEPLOY_FORCE_RECONFIG=1 \
easyai-deploy-verify:latest \
bash -c './start.sh'
EXIT_CODE=$?
echo ""
if [ $EXIT_CODE -eq 0 ]; then
echo "✅ 部署脚本验证通过"
else
echo "❌ 部署脚本验证失败 (exit code: $EXIT_CODE)"
fi
exit $EXIT_CODE

View File

@ -1,199 +0,0 @@
# EasyAI Windows 一键部署方案
## 1. 背景与目标
`start.sh` 是 Linux 下的一键部署脚本,本方案为 Windows 平台提供等效的 `start.ps1` PowerShell 脚本。针对 Windows 典型场景做如下**精简**
- **仅 IP 访问**:不含域名模式与 HTTPS
- **本地访问无需放行端口**:选择本地 (127.0.0.1) 时,不涉及防火墙配置
- **Docker 未安装时**:用户可选择手动或自动安装 **Docker Desktop for Windows**winget/Chocolatey
## 2. Linux start.sh 流程梳理
### 2.1 整体流程
| 步骤 | 功能 | 说明 |
|------|------|------|
| 1 | 项目初始化 | 校验当前目录下存在 `docker-compose.yml` |
| 2 | 部署配置问答 | IP 或域名二选一,并采集对应参数 |
| 3 | 配置文件生成 | 生成/更新 `.env`、`.env.tools`、`.env.ASG` |
| 4 | Docker 安装与检查 | 检测并安装 DockerUbuntu/CentOS |
| 5 | 启动服务 | `docker compose pull && docker compose up -d` |
| 6 | HTTPS 配置(可选) | 域名模式下执行 `https.sh` |
### 2.2 配置问答逻辑
- **IP 模式**:输入服务器 IP 地址,需要放行 3001、3002、3003 端口
- **域名模式**:输入域名,可选是否启用 HTTPS需放行 80、443 端口
### 2.3 环境变量写入 .env
- `NUXT_PUBLIC_BASE_APIURL`API 地址
- `NUXT_PUBLIC_BASE_SOCKETURL`WebSocket 地址
- `NUXT_PUBLIC_SG_APIURL`Agent 服务治理 API 地址
**IP 模式**
```
NUXT_PUBLIC_BASE_APIURL=http://<IP>:3001
NUXT_PUBLIC_BASE_SOCKETURL=ws://<IP>:3002
NUXT_PUBLIC_SG_APIURL=http://<IP>:3003
```
**域名模式**
```
NUXT_PUBLIC_BASE_APIURL=/api
NUXT_PUBLIC_BASE_SOCKETURL=wss://<domain>/socket.io
NUXT_PUBLIC_SG_APIURL=/asg-api
```
---
## 3. Windows 与 Linux 差异
| 项目 | Linux | Windows |
|------|-------|---------|
| 脚本语言 | Bash | PowerShell |
| 文本替换 | sed | `(Get-Content) -replace``Set-Content` |
| 用户输入 | `read -p` | `Read-Host` |
| 访问方式 | IP + 域名 + HTTPS | **仅 IP**(本地 / 局域网) |
| 端口放行 | 本地无特殊说明 | **本地访问无需放行**,局域网需放行 3001/3002/3003 |
| Docker | apt/yum 安装 Linux Docker | **Docker Desktop for Windows**,未安装时可选择手动或自动安装 |
---
## 4. Windows IP 访问方式设计(核心差异)
Windows 版**仅支持 IP 访问**,不包含域名模式与 HTTPS 配置。用户访问方式分为两类:
| 选项 | 访问方式 | IP 值 | 端口说明 |
|------|----------|-------|----------|
| 1 | 本地访问 | `127.0.0.1` | 本机访问,**无需放行端口** |
| 2 | 局域网访问 | 用户输入本机局域网 IP | 同网段设备访问,需放行 3001、3002、3003 |
**交互流程:**
1. `[1] 本地访问` → 自动使用 `127.0.0.1`,无需配置防火墙
2. `[2] 局域网访问` → 提示用户输入局域网 IP可提示 `ipconfig` 查看),并提醒放行上述端口
---
## 5. 实现方案
### 5.1 脚本文件
- 文件路径:`easyai/start.ps1`
- 一行命令示例:
```powershell
git clone https://git.51easyai.com/wangbo/easyai; cd easyai; .\start.ps1
```
### 5.2 模块划分
| 模块 | 函数/区块 | 功能 |
|------|-----------|------|
| 项目初始化 | `Init-ProjectDir` | 检查 `docker-compose.yml`,切换到项目根目录 |
| 配置问答 | `Run-DeployQuestions` | 本地访问 / 局域网访问选择(含 IP 输入) |
| 环境变量 | `PromptOrEnv` | 支持环境变量覆盖,用于 CI/自动化 |
| 配置文件 | `Setup-EnvFiles` | 复制 sample 并修改 `.env`、`.env.tools`、`.env.ASG` |
| Docker 检查 | `Test-Docker` | 检测 `docker`,未安装则让用户选择**手动安装**或**自动安装** |
| 启动服务 | `Start-Services` | `docker compose pull``docker compose up -d` |
| 主流程 | `Main` | 串联上述步骤 |
### 5.3 环境变量支持(非交互模式)
| 变量 | 说明 |
|------|------|
| `DEPLOY_IP` | 访问 IP本地填 `127.0.0.1`,局域网填实际 IP |
| `DEPLOY_DRY_RUN` | 1 时只生成配置,不安装/启动 Docker |
| `DEPLOY_FORCE_RECONFIG` | 非空时强制重新配置 |
### 5.4 配置文件修改实现(仅 IP 模式)
使用 PowerShell 替换 `.env` 中相关行:
```powershell
$content = Get-Content .env -Raw -Encoding UTF8
$content = $content -replace 'NUXT_PUBLIC_BASE_APIURL=.*', "NUXT_PUBLIC_BASE_APIURL=http://${DEPLOY_IP}:3001"
$content = $content -replace 'NUXT_PUBLIC_BASE_SOCKETURL=.*', "NUXT_PUBLIC_BASE_SOCKETURL=ws://${DEPLOY_IP}:3002"
$content = $content -replace 'NUXT_PUBLIC_SG_APIURL=.*', "NUXT_PUBLIC_SG_APIURL=http://${DEPLOY_IP}:3003"
Set-Content .env -Value $content -Encoding UTF8 -NoNewline
```
### 5.5 Docker 处理策略
- **目标**:检测并安装 **Docker Desktop for Windows**Windows 版 Docker
- **检测**:执行 `docker --version``docker compose version`
- **未安装时** prompt 让用户选择
- `[1] 手动安装`:输出安装说明及 Docker Desktop for Windows 下载链接,退出脚本
- `[2] 自动安装`:通过 winget 或 Chocolatey 安装 Docker Desktop for Windows安装后需用户重启终端/机器再继续
### 5.6 执行策略
PowerShell 默认可能禁止执行脚本,建议在文档中说明:
```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
或在脚本开头提示用户使用:
```powershell
powershell -ExecutionPolicy Bypass -File .\start.ps1
```
---
## 6. 部署完成输出
成功部署后输出访问地址,例如:
- 本地访问:`http://127.0.0.1:3010`
- 局域网访问:`http://<LAN_IP>:3010`
---
## 7. 实现清单
- [ ] 创建 `start.ps1` 主脚本
- [ ] 实现 `Init-ProjectDir`:项目目录校验
- [ ] 实现 `Run-DeployQuestions`:本地 / 局域网 IP 选择(无域名/HTTPS
- [ ] 实现 `Setup-EnvFiles`:配置文件生成与替换
- [ ] 实现 `Test-Docker`Docker 检测,未安装时 prompt「手动安装」或「自动安装」
- [ ] 实现 `Install-Docker`:自动安装 **Docker Desktop for Windows**winget / Chocolatey
- [ ] 实现 `Start-Services``docker compose` 启动
- [ ] 实现 `Main`:主流程串联
- [ ] 支持 `DEPLOY_DRY_RUN`、`DEPLOY_IP` 环境变量非交互模式
- [x] 在 README 或文档中补充 Windows 部署说明与执行策略
- [x] 创建 `scripts/test-start-ps1-env.py` 验证 .env 替换逻辑
---
## 8. Windows 测试说明
### 本地测试(需 Windows 或 WSL + PowerShell
```powershell
# 非交互 + 仅生成配置(不启动 Docker
$env:DEPLOY_DRY_RUN = "1"
$env:DEPLOY_IP = "127.0.0.1"
.\start.ps1
# 检查 .env 是否已正确写入
Select-String -Path .env -Pattern "NUXT_PUBLIC_BASE"
```
### 完整部署测试(需 Windows + Docker Desktop
```powershell
.\start.ps1
# 按提示选择 [1] 本地访问 或 [2] 局域网访问
# 若未安装 Docker选择 [1] 手动 或 [2] 自动安装
```
### 执行策略(若提示无法运行脚本)
```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# 或
powershell -ExecutionPolicy Bypass -File .\start.ps1
```

View File

@ -144,17 +144,4 @@ server {
proxy_buffering off; # 对于 WebSocket 连接禁用缓冲 proxy_buffering off; # 对于 WebSocket 连接禁用缓冲
} }
# 沙箱环境 API脚本执行、下载、安装依赖等需在 docker-compose 中取消 SANDBOX_PORT 映射
location /sandbox/ {
proxy_pass http://127.0.0.1:8081/;
proxy_read_timeout 300s;
client_max_body_size 50M;
proxy_redirect off;
proxy_set_header X-Original-Prefix '/sandbox';
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
}
} }

View File

@ -104,13 +104,7 @@ else
fi fi
echo "🚀 复制当前目录的配置文件到nginx配置文件目录" echo "🚀 复制当前目录的配置文件到nginx配置文件目录"
# 支持 EASYAI_PROXY_CONF 指定配置文件(如 51easyai.com.conf cp -r ./easyai-proxy.conf /etc/nginx/conf.d/
CONF_FILE="${EASYAI_PROXY_CONF:-easyai-proxy.conf}"
if [ -f "./$CONF_FILE" ]; then
cp "./$CONF_FILE" "/etc/nginx/conf.d/$CONF_FILE"
else
cp -r ./easyai-proxy.conf /etc/nginx/conf.d/ 2>/dev/null || { echo "❌ 未找到 nginx 配置文件"; exit 1; }
fi
echo "🚀 重载nginx" echo "🚀 重载nginx"
sudo nginx -s reload sudo nginx -s reload
@ -119,8 +113,7 @@ sudo nginx -s stop
echo "🚀 使用certbot 自动配置证书" echo "🚀 使用certbot 自动配置证书"
# 从 Nginx 配置文件中提取所有域名 # 从 Nginx 配置文件中提取所有域名
CONF_FILE="${EASYAI_PROXY_CONF:-easyai-proxy.conf}" DOMAINS=$(find /etc/nginx/conf.d/ -name "easyai-proxy.conf" -type f -exec grep "server_name" {} \; | \
DOMAINS=$(grep "server_name" /etc/nginx/conf.d/"$CONF_FILE" 2>/dev/null || find /etc/nginx/conf.d/ -name "easyai-proxy.conf" -exec grep "server_name" {} \; | \
grep -v "#" | \ grep -v "#" | \
awk '{for(i=2;i<=NF;i++) if($i!=";") print $i}' | \ awk '{for(i=2;i<=NF;i++) if($i!=";") print $i}' | \
sed 's/;//g' | \ sed 's/;//g' | \

View File

@ -1,67 +0,0 @@
#Requires -RunAsAdministrator
# WSL 与 Docker 网络配置重置脚本
# 需以管理员身份运行
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = "Continue"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " WSL & Docker 网络配置重置" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# 1. 关闭 WSL
Write-Host "[1/5] 关闭 WSL..." -ForegroundColor Yellow
wsl --shutdown
Start-Sleep -Seconds 3
Write-Host " 完成" -ForegroundColor Green
# 2. 重置 Windows 网络栈(可选,可能需重启)
Write-Host "[2/5] 重置 Windows 网络栈..." -ForegroundColor Yellow
try {
netsh winsock reset 2>$null
netsh int ip reset 2>$null
Write-Host " 完成 (如有提示重启,建议执行)" -ForegroundColor Green
} catch {
Write-Host " 跳过: $($_.Exception.Message)" -ForegroundColor Gray
}
# 3. 清理 Docker 网络
Write-Host "[3/5] 清理 Docker 未使用网络..." -ForegroundColor Yellow
$dockerOk = $false
try {
$null = docker info 2>&1
$dockerOk = $true
} catch { }
if ($dockerOk) {
docker network prune -f 2>$null
Write-Host " 完成" -ForegroundColor Green
} else {
Write-Host " 跳过 (Docker 未运行,请先启动 Docker Desktop)" -ForegroundColor Gray
}
# 4. 清除 Docker 端口代理残留(若有)
Write-Host "[4/5] 检查端口代理..." -ForegroundColor Yellow
$proxies = netsh interface portproxy show all 2>$null
if ($proxies -and $proxies -match "3010|3001|3002|3003") {
Write-Host " 发现相关端口代理,请手动在管理员 CMD 执行:" -ForegroundColor Yellow
Write-Host " netsh interface portproxy reset" -ForegroundColor White
} else {
Write-Host " 无异常端口代理" -ForegroundColor Green
}
# 5. 提示
Write-Host "[5/5] 下一步操作:" -ForegroundColor Yellow
Write-Host ""
Write-Host " 1. 启动 Docker Desktop若已关闭" -ForegroundColor White
Write-Host " 2. 等待 Docker 完全就绪后,执行:" -ForegroundColor White
Write-Host " cd D:\01一键部署包\easyai" -ForegroundColor Cyan
Write-Host " docker compose up -d" -ForegroundColor Cyan
Write-Host ""
Write-Host " 3. 若端口仍不可访问,在 Docker Desktop 中:" -ForegroundColor White
Write-Host " [设置] -> [Troubleshoot] -> [Reset to factory defaults]" -ForegroundColor Cyan
Write-Host " (会清除所有容器/镜像,谨慎使用)" -ForegroundColor Gray
Write-Host ""
Write-Host " 4. 若执行了 netsh winsock/int ip reset建议重启电脑" -ForegroundColor White
Write-Host ""
Read-Host "按 Enter 键退出"

View File

@ -1,27 +0,0 @@
#!/usr/bin/env python3
# 验证 start.ps1 的 .env 替换逻辑(与 PowerShell 等效)
import re
DEPLOY_IP = "192.168.1.100"
content = """NUXT_PUBLIC_BASE_APIURL=http://127.0.0.1:3001
#NUXT_PUBLIC_BASE_APIURL=/api
NUXT_PUBLIC_BASE_SOCKETURL=ws://127.0.0.1:3002
NUXT_PUBLIC_SG_APIURL=http://127.0.0.1:3003
"""
content = re.sub(r'^NUXT_PUBLIC_BASE_APIURL=.*', f'NUXT_PUBLIC_BASE_APIURL=http://{DEPLOY_IP}:3001', content, flags=re.MULTILINE)
content = re.sub(r'^NUXT_PUBLIC_BASE_SOCKETURL=.*', f'NUXT_PUBLIC_BASE_SOCKETURL=ws://{DEPLOY_IP}:3002', content, flags=re.MULTILINE)
content = re.sub(r'^NUXT_PUBLIC_SG_APIURL=.*', f'NUXT_PUBLIC_SG_APIURL=http://{DEPLOY_IP}:3003', content, flags=re.MULTILINE)
expected = f"""NUXT_PUBLIC_BASE_APIURL=http://{DEPLOY_IP}:3001
#NUXT_PUBLIC_BASE_APIURL=/api
NUXT_PUBLIC_BASE_SOCKETURL=ws://{DEPLOY_IP}:3002
NUXT_PUBLIC_SG_APIURL=http://{DEPLOY_IP}:3003
"""
# 注释行不应被替换,检查第一行和第三行
lines = content.split('\n')
assert lines[0] == f'NUXT_PUBLIC_BASE_APIURL=http://{DEPLOY_IP}:3001', f"Got {lines[0]}"
assert lines[2] == f'NUXT_PUBLIC_BASE_SOCKETURL=ws://{DEPLOY_IP}:3002', f"Got {lines[2]}"
assert lines[3] == f'NUXT_PUBLIC_SG_APIURL=http://{DEPLOY_IP}:3003', f"Got {lines[3]}"
assert lines[1] == '#NUXT_PUBLIC_BASE_APIURL=/api', f"Comment should not change: {lines[1]}"
print("OK: .env replacement logic validated")

435
start.ps1
View File

@ -1,435 +0,0 @@
#Requires -Version 5.1
# EasyAI Windows 一键部署脚本
# 仅支持 IP 访问(本地/局域网),不含域名与 HTTPS
# 一行命令: git clone https://git.51easyai.com/wangbo/easyai; cd easyai; .\start.ps1
# 设置控制台编码为 UTF-8确保中文正确显示
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = "Stop"
$script:LogDir = $PSScriptRoot
if (-not $script:LogDir) { $script:LogDir = $env:TEMP }
$script:LogFile = Join-Path $script:LogDir "start.ps1.log"
# 尽早写入启动标记,便于闪退时排查
try { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === 脚本加载 ===" | Out-File -FilePath $script:LogFile -Append -Encoding utf8 } catch { }
function Write-Log {
param([string]$Msg)
try {
$line = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $Msg"
Add-Content -Path $script:LogFile -Value $line -Encoding UTF8 -ErrorAction SilentlyContinue
} catch { }
}
trap {
$errMsg = $_.Exception.Message
$errStack = if ($_.ScriptStackTrace) { " | 堆栈: $($_.ScriptStackTrace)" } else { "" }
try {
$logPath = $script:LogFile
if (-not $logPath) { $logPath = Join-Path $env:TEMP "start.ps1.log" }
$logLine = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] 错误退出: $errMsg$errStack"
Add-Content -Path $logPath -Value $logLine -Encoding UTF8 -ErrorAction SilentlyContinue
} catch { }
try {
Write-Host ""
Write-Host "========================================" -ForegroundColor Red
Write-Host " 发生错误,详见日志: $script:LogFile" -ForegroundColor Red
Write-Host "========================================" -ForegroundColor Red
Write-Host $errMsg -ForegroundColor Red
if ($errStack) { Write-Host $errStack }
} catch { }
Wait-ForExit
exit 1
}
# 结束时保持窗口不关闭,便于查看输出和 DebugCI 环境自动跳过)
function Wait-ForExit {
if ($env:CI -eq "true") { return }
Write-Host ""
Read-Host "按 Enter 键退出"
}
# 仅配置模式DEPLOY_DRY_RUN=1 只生成配置文件,不执行 Docker 安装和启动
$script:DeployDryRun = if ($env:DEPLOY_DRY_RUN -eq "1") { $true } else { $false }
$script:DeployIP = ""
$script:DeployModeSkip = $false
# Docker Desktop for Windows 下载链接
$DockerDesktopUrl = "https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe"
function Write-Step { param($Msg) Write-Host $Msg }
function Write-Ok { param($Msg) Write-Host "$Msg" -ForegroundColor Green }
function Write-Err { param($Msg) Write-Host "$Msg" -ForegroundColor Red; throw $Msg }
function Write-Warn { param($Msg) Write-Host "⚠️ $Msg" -ForegroundColor Yellow }
# ==================== 项目初始化 ====================
function Init-ProjectDir {
$scriptDir = $PSScriptRoot
if (-not $scriptDir) { throw "无法获取脚本所在目录。请在 easyai 目录下打开 PowerShell 执行: .\start.ps1" }
$composePath = Join-Path $scriptDir "docker-compose.yml"
if (Test-Path $composePath) {
Set-Location $scriptDir
Write-Step "📁 项目目录: $scriptDir"
return
}
Write-Err "未找到 docker-compose.yml请在 easyai 项目目录下运行 start.ps1"
}
# ==================== 配置问答 ====================
function Run-DeployQuestions {
Write-Host ""
Write-Host "================================"
Write-Host " EasyAI 部署配置Windows"
Write-Host "================================"
Write-Host ""
# 非交互模式:环境变量 DEPLOY_IP 已设置
if ($env:DEPLOY_IP) {
$script:DeployIP = $env:DEPLOY_IP.Trim()
Write-Step "使用环境变量: DEPLOY_IP=$($script:DeployIP)"
return
}
Write-Host "请选择访问方式:"
Write-Host " [1] 本地访问 (127.0.0.1) - 仅本机访问,无需放行端口"
Write-Host " [2] 局域网访问 - 同网段设备访问,需放行 3001、3002、3003 端口"
$choice = Read-Host "请选择 [1/2]"
switch ($choice) {
"1" {
$script:DeployIP = "127.0.0.1"
Write-Step "已选择本地访问"
}
"2" {
# 自动获取局域网 IP排除回环和 APIPA 地址)
$detectedIp = $null
try {
$addrs = Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue | Where-Object {
$_.InterfaceAlias -notlike "*Loopback*" -and
$_.IPAddress -notmatch "^127\." -and
$_.IPAddress -notmatch "^169\.254\."
}
$detectedIp = ($addrs | Sort-Object InterfaceIndex | Select-Object -First 1).IPAddress
} catch { }
if ($detectedIp) {
$defaultHint = "回车使用 [$detectedIp]"
Write-Host " 检测到局域网 IP: $detectedIp"
$inputIp = Read-Host "请输入本机局域网 IP$defaultHint 或手动输入)"
$inputIp = $inputIp.Trim()
$script:DeployIP = if ([string]::IsNullOrWhiteSpace($inputIp)) { $detectedIp } else { $inputIp }
} else {
Write-Host " 提示: 未自动检测到局域网 IP可在本机运行 ipconfig 查看"
$lanIp = Read-Host "请输入本机局域网 IP 地址"
$lanIp = $lanIp.Trim()
if ([string]::IsNullOrWhiteSpace($lanIp)) { Write-Err "IP 不能为空" }
$script:DeployIP = $lanIp
}
Write-Warn "请确保防火墙已放行 3001、3002、3003 端口"
}
default {
Write-Err "无效选择"
}
}
}
# ==================== 生成配置文件 ====================
function Setup-EnvFiles {
Write-Host ""
Write-Step "📝 配置环境文件..."
# 复制 .env.tools 和 .env.ASG
if (-not (Test-Path ".env.tools")) {
Copy-Item ".env.tools.sample" ".env.tools"
Write-Ok ".env.tools"
}
if (-not (Test-Path ".env.ASG")) {
Copy-Item ".env.ASG.sample" ".env.ASG"
Write-Ok ".env.ASG"
}
# 配置 .env
if (-not (Test-Path ".env")) {
Copy-Item ".env.sample" ".env"
}
$content = Get-Content ".env" -Raw -Encoding UTF8
if (-not $content) { $content = "" }
$content = $content -replace '(?m)^NUXT_PUBLIC_BASE_APIURL=.*', "NUXT_PUBLIC_BASE_APIURL=http://$($script:DeployIP):3001"
$content = $content -replace '(?m)^NUXT_PUBLIC_BASE_SOCKETURL=.*', "NUXT_PUBLIC_BASE_SOCKETURL=ws://$($script:DeployIP):3002"
$content = $content -replace '(?m)^NUXT_PUBLIC_SG_APIURL=.*', "NUXT_PUBLIC_SG_APIURL=http://$($script:DeployIP):3003"
# 保持文件末尾换行
if ($content -and -not $content.EndsWith("`n")) { $content += "`n" }
$envPath = Join-Path (Get-Location) ".env"
[System.IO.File]::WriteAllText($envPath, $content, [System.Text.UTF8Encoding]::new($false))
Write-Ok ".env 已配置为 IP 模式 ($($script:DeployIP))"
}
# ==================== Docker 检测 ====================
function Test-DockerInstalled {
$docker = Get-Command docker -ErrorAction SilentlyContinue
if (-not $docker) { return $false }
try {
$null = & docker --version 2>&1
return $true
} catch {
return $false
}
}
# 检查 Docker 引擎是否已启动并可响应(带超时,避免 docker info 卡住)
function Test-DockerRunning {
param([int]$TimeoutSeconds = 10)
try {
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = "docker"
$psi.Arguments = "info"
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.UseShellExecute = $false
$psi.CreateNoWindow = $true
$p = [System.Diagnostics.Process]::Start($psi)
$exited = $p.WaitForExit($TimeoutSeconds * 1000)
if (-not $exited) {
try { $p.Kill() } catch { }
return $false
}
return ($p.ExitCode -eq 0)
} catch {
return $false
}
}
# 启动 Docker Desktop 并等待就绪
function Start-DockerDesktopAndWait {
param(
[int]$MaxWaitSeconds = 120,
[int]$CheckIntervalSeconds = 5
)
Write-Step "Docker 未运行,正在启动 Docker Desktop..."
$dockerDesktopPath = "${env:ProgramFiles}\Docker\Docker\Docker Desktop.exe"
if (-not (Test-Path $dockerDesktopPath)) {
$dockerDesktopPath = "${env:ProgramFiles(x86)}\Docker\Docker\Docker Desktop.exe"
}
if (-not (Test-Path $dockerDesktopPath)) {
Write-Warn "未找到 Docker Desktop 可执行文件"
Write-Host "请手动启动 Docker Desktop 后重新运行本脚本。"
return $false
}
# 尝试使用 docker desktop startDocker Desktop 4.38+ 支持)
$useCli = $false
try {
$null = & docker desktop start 2>&1
$useCli = $true
Write-Step "已通过 docker desktop start 发送启动命令"
} catch {
# 回退到直接启动进程
}
if (-not $useCli) {
Start-Process -FilePath $dockerDesktopPath -WindowStyle Hidden
Write-Step "已启动 Docker Desktop 进程"
}
Write-Host "等待 Docker 引擎就绪(最长 $MaxWaitSeconds 秒)..." -ForegroundColor Cyan
$elapsed = 0
while ($elapsed -lt $MaxWaitSeconds) {
Start-Sleep -Seconds $CheckIntervalSeconds
$elapsed += $CheckIntervalSeconds
Write-Host " 已等待 $elapsed 秒..." -NoNewline
if (Test-DockerRunning) {
Write-Host " 完成" -ForegroundColor Green
Write-Ok "Docker 已就绪"
return $true
}
Write-Host ""
}
Write-Warn "等待超时Docker 可能仍在启动中"
Write-Host "请稍后手动执行 docker info 确认,或重新运行本脚本。"
return $false
}
# 确保 Docker 已安装且运行,若未运行则尝试启动
function Ensure-DockerRunning {
if (-not (Test-DockerInstalled)) {
return $false
}
if (Test-DockerRunning) {
Write-Ok "Docker 引擎已运行"
$v = docker --version 2>$null
if ($v) { Write-Host " $v" }
return $true
}
return (Start-DockerDesktopAndWait)
}
function Install-DockerDesktop {
$isWin = ($env:OS -eq "Windows_NT") -or ($PSVersionTable.PSVersion.Major -ge 6 -and $IsWindows)
if (-not $isWin) {
Write-Warn "自动安装仅支持 Windows。请手动安装 Docker Desktop。"
Write-Host "下载地址: $DockerDesktopUrl"
Wait-ForExit; exit 1
}
# 优先 winget其次 Chocolatey
if (Get-Command winget -ErrorAction SilentlyContinue) {
Write-Step "正在通过 winget 安装 Docker Desktop for Windows..."
winget install --id Docker.DockerDesktop -e --accept-source-agreements --accept-package-agreements
if ($LASTEXITCODE -eq 0) {
Write-Ok "安装已启动。安装完成后请重启终端,然后重新运行本脚本。"
exit 0
}
}
if (Get-Command choco -ErrorAction SilentlyContinue) {
Write-Step "正在通过 Chocolatey 安装 Docker Desktop for Windows..."
choco install docker-desktop -y
if ($LASTEXITCODE -eq 0) {
Write-Ok "安装已启动。安装完成后请重启终端,然后重新运行本脚本。"
exit 0
}
}
Write-Warn "未找到 winget 或 Chocolatey请手动安装 Docker Desktop。"
Write-Host "下载地址: $DockerDesktopUrl"
Wait-ForExit; exit 1
}
function Test-Docker {
Write-Host ""
Write-Host "================================"
Write-Host " Docker 检查"
Write-Host "================================"
Write-Host ""
if (Test-DockerInstalled) {
Write-Ok "Docker 已安装"
# 检查并确保 Docker 引擎运行
if (-not (Ensure-DockerRunning)) {
Write-Warn "Docker 未能自动启动"
Write-Host ""
Write-Host "请手动启动 Docker Desktop确认其完全启动后再重新运行本脚本。"
Wait-ForExit
exit 1
}
return
}
Write-Warn "未检测到 Docker Desktop for Windows"
Write-Host ""
Write-Host "请选择:"
Write-Host " [1] 手动安装 - 打开下载页面,退出脚本"
Write-Host " [2] 自动安装 - 通过 winget 或 Chocolatey 安装(需管理员权限)"
$choice = Read-Host "请选择 [1/2]"
switch ($choice) {
"1" {
Write-Host ""
Write-Host "Docker Desktop for Windows 下载地址:"
Write-Host " $DockerDesktopUrl"
Write-Host ""
Write-Host "安装完成后请重新运行本脚本。"
if ($env:OS -eq "Windows_NT") {
Start-Process $DockerDesktopUrl
}
Wait-ForExit; exit 1
}
"2" {
Install-DockerDesktop
}
default {
Write-Err "无效选择"
}
}
}
# ==================== 启动服务 ====================
function Start-Services {
Write-Host ""
Write-Step "🚀 启动 EasyAI 服务..."
$hasComposeV2 = $false
try {
$null = docker compose version 2>&1
$hasComposeV2 = $true
} catch { }
if ($hasComposeV2) {
docker compose pull
if ($LASTEXITCODE -ne 0) { Write-Err "docker compose pull 失败" }
docker compose up -d
if ($LASTEXITCODE -ne 0) { Write-Err "docker compose up 失败" }
} else {
docker-compose pull
if ($LASTEXITCODE -ne 0) { Write-Err "docker-compose pull 失败" }
docker-compose up -d
if ($LASTEXITCODE -ne 0) { Write-Err "docker-compose up 失败" }
}
Write-Host "🎉 EasyAI 应用启动成功"
}
# ==================== 主流程 ====================
function Main {
Init-ProjectDir
# 检查是否已有 .env 且非强制重新配置
if ((Test-Path ".env") -and -not $env:DEPLOY_FORCE_RECONFIG -and -not $env:DEPLOY_IP) {
Write-Step "📁 检测到已有 .env 配置"
$reconfigure = Read-Host "是否重新配置访问方式?[y/N]"
$trimmed = $reconfigure.Trim().ToLower()
$startsWithY = ($trimmed.Length -gt 0) -and ($trimmed[0] -eq [char]121)
if (-not $startsWithY) {
Write-Step "使用现有配置继续..."
# 从现有 .env 读取 IP用于最后输出
$line = Get-Content ".env" -Encoding UTF8 | Where-Object { $_ -like "NUXT_PUBLIC_BASE_APIURL=*" } | Select-Object -First 1
if ($line -and $line -like "*:3001*") {
$prefix = ".*http://"
$suffix = ":3001.*"
$script:DeployIP = ($line -replace $prefix, "" -replace $suffix, "").Trim()
}
$script:DeployModeSkip = $true
}
}
if (-not $script:DeployModeSkip) {
Run-DeployQuestions
}
if (-not $script:DeployModeSkip) {
Setup-EnvFiles
} else {
if (-not (Test-Path ".env.tools")) { Copy-Item ".env.tools.sample" ".env.tools" }
if (-not (Test-Path ".env.ASG")) { Copy-Item ".env.ASG.sample" ".env.ASG" }
}
if ($script:DeployDryRun) {
Write-Host ""
Write-Warn "dry-run 模式:跳过 Docker 安装和服务启动"
Write-Host " 配置文件已生成,可直接运行 .\start.ps1 完成部署"
} else {
Test-Docker
Start-Services
}
Write-Host ""
Write-Host "================================"
Write-Host " 部署完成"
Write-Host "================================"
$accessIp = if ($script:DeployIP) { $script:DeployIP } else { "127.0.0.1" }
Write-Host "访问地址: http://${accessIp}:3010"
Write-Host "默认登录账户: admin"
Write-Host "默认登录密码: 123456"
Write-Host ""
Wait-ForExit
}
Write-Log "=== 脚本启动 ==="
Write-Host "EasyAI Windows 部署脚本启动中..." -ForegroundColor Cyan
Write-Host "日志文件: $script:LogFile"
Write-Host ""
Main
Write-Log "=== 脚本正常结束 ==="

424
start.sh
View File

@ -1,296 +1,186 @@
#!/bin/bash #!/bin/bash
# EasyAI 一键部署脚本
# 支持交互式问答配置,兼容 IP 与域名两种访问方式
# 一行命令: git clone https://git.51easyai.com/wangbo/easyai && cd easyai && chmod +x ./start.sh && ./start.sh
set -e set -e # 发生错误时终止脚本执行
# 仅配置模式验证用DEPLOY_DRY_RUN=1 只生成配置文件,不执行 Docker 安装和启动 echo "==========================="
DEPLOY_DRY_RUN="${DEPLOY_DRY_RUN:-0}" echo "🚀 开始自动安装 Docker 和 Docker Compose"
echo "==========================="
# ==================== 项目初始化 ==================== # 获取操作系统类型和版本
init_project_dir() { OS_FAMILY=$(hostnamectl | grep "Operating System" | awk '{print $3}')
local script_source OS_VERSION_ID=$(grep -oP '(?<=^VERSION_ID=")[0-9.]+' /etc/os-release | cut -d'.' -f1)
script_source="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" OS_CODENAME=""
if [ -f "${script_source}/docker-compose.yml" ]; then if [[ "$OS_FAMILY" == "Ubuntu" ]]; then
echo "📁 项目目录: ${script_source}" OS_CODENAME=$(lsb_release -cs)
cd "$script_source" fi
# 定义国内镜像源
# Ubuntu 镜像源
UBUNTU_DOCKER_MIRROR_URL="https://mirrors.ustc.edu.cn/docker-ce" # 中科大
UBUNTU_DOCKER_GPG_URL="https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg"
# CentOS 镜像源 (选择一个即可,这里提供清华和阿里云)
CENTOS_DOCKER_MIRROR_URL="https://mirrors.tuna.tsinghua.edu.cn/docker-ce" # 清华大学
# CENTOS_DOCKER_MIRROR_URL="https://mirrors.aliyun.com/docker-ce" # 阿里云 - 如果清华源不稳定可以尝试这个
# 函数:检查并等待网络连接
check_network() {
echo "🌐 检查网络连接到 Docker 官方仓库 (备用)..."
if curl -sSf https://download.docker.com/ &> /dev/null; then
echo "✅ 网络连接到 Docker 官方仓库正常。"
return 0
else
echo "⚠️ 无法连接到 Docker 官方仓库。将尝试使用国内镜像源。"
# 即使无法连接官方源,也继续尝试国内源
return 0 return 0
fi fi
echo "❌ 未找到 docker-compose.yml请在 easyai 项目目录下运行 start.sh"
echo " 启动命令: git clone https://git.51easyai.com/wangbo/easyai && cd easyai && chmod +x ./start.sh && ./start.sh"
exit 1
} }
# ==================== 配置变量(支持环境变量非交互模式) ==================== # 预检网络连接(非阻塞,仅作为提示)
DEPLOY_MODE="" # ip | domain check_network
DEPLOY_IP=""
DEPLOY_DOMAIN=""
DEPLOY_HTTPS=false
prompt_or_env() { # Docker 安装
local var_name=$1 if command -v docker &> /dev/null; then
local prompt_text=$2 echo "✅ Docker 已安装,跳过安装步骤"
local env_name=$3 else
local default=$4 if [[ "$OS_FAMILY" == "Ubuntu" ]]; then
echo "📦 安装依赖 (Ubuntu)..."
sudo apt update -y
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release
if [ -n "${!env_name}" ]; then echo "🔑 添加 Docker GPG 密钥 (Ubuntu) - 优先使用国内镜像源..."
eval "$var_name=\"${!env_name}\"" # 现代 Ubuntu 推荐使用 gpg --dearmor
return sudo install -m 0755 -d /etc/apt/keyrings
fi if ! curl -fsSL "$UBUNTU_DOCKER_GPG_URL" | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg; then
echo "❌ 无法从国内镜像源获取 GPG 密钥,尝试从官方源获取..."
if [ -n "$default" ]; then curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg || {
read -r -p "${prompt_text} [$default]: " input echo "❌ 无法获取 Docker GPG 密钥,请检查网络或 GPG 密钥 URL。"
eval "$var_name=\"${input:-$default}\"" exit 1
else }
read -r -p "${prompt_text}: " input
eval "$var_name=\"$input\""
fi
}
run_deploy_questions() {
echo ""
echo "================================"
echo " EasyAI 部署配置(问答模式)"
echo "================================"
echo ""
# 非交互模式环境变量已完整设置则直接使用CI/自动化部署)
if [ -n "$DEPLOY_ACCESS" ]; then
if [ "$DEPLOY_ACCESS" = "ip" ] && [ -n "$DEPLOY_IP" ]; then
DEPLOY_MODE="ip"
echo "使用环境变量: IP 模式, IP=$DEPLOY_IP"
return
fi fi
if [ "$DEPLOY_ACCESS" = "domain" ] && [ -n "$DEPLOY_DOMAIN" ]; then sudo chmod a+r /etc/apt/keyrings/docker.gpg # 确保可读权限
DEPLOY_MODE="domain"
DEPLOY_HTTPS="${DEPLOY_HTTPS_INPUT:-false}"
echo "使用环境变量: 域名模式, 域名=$DEPLOY_DOMAIN"
return
fi
fi
# 1. IP 或域名访问 echo "🌍 添加 Docker 源 (Ubuntu) - 使用国内镜像源..."
if [ -z "$DEPLOY_ACCESS" ]; then echo \
echo "1. 通过 IP 地址还是域名访问?" "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] $UBUNTU_DOCKER_MIRROR_URL/linux/ubuntu \
echo " [1] IP 地址(需开放 3001、3002、3003 端口)" $OS_CODENAME stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
echo " [2] 域名" sudo apt-get update -y
read -r -p "请选择 [1/2]: " choice
case "$choice" in
1) DEPLOY_MODE="ip" ;;
2) DEPLOY_MODE="domain" ;;
*) echo "❌ 无效选择"; exit 1 ;;
esac
else
DEPLOY_MODE="$DEPLOY_ACCESS"
fi
if [ "$DEPLOY_MODE" = "ip" ]; then echo "🐳 安装 Docker (Ubuntu)..."
# 2. 输入服务器 IP sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin || {
prompt_or_env DEPLOY_IP "2. 请输入服务器 IP 地址" "DEPLOY_IP" "" echo "❌ Docker 或其组件安装失败。请检查错误日志或尝试手动安装。"
[ -z "$DEPLOY_IP" ] && { echo "❌ IP 不能为空"; exit 1; }
echo " 请确保防火墙已放行 3001、3002、3003 端口"
else
# 3. 输入域名
prompt_or_env DEPLOY_DOMAIN "3. 请输入域名(不含 https:// 前缀,如 51easyai.com" "DEPLOY_DOMAIN" ""
[ -z "$DEPLOY_DOMAIN" ] && { echo "❌ 域名不能为空"; exit 1; }
# 3.1 是否启用 HTTPS
if [ -n "$DEPLOY_HTTPS_INPUT" ]; then
DEPLOY_HTTPS=$DEPLOY_HTTPS_INPUT
else
read -r -p "3.1 是否启用 HTTPS[y/N]: " https_choice
DEPLOY_HTTPS=false
[[ "$https_choice" =~ ^[yY] ]] && DEPLOY_HTTPS=true
fi
[ "$DEPLOY_HTTPS" = true ] && echo " 启用 HTTPS 需确保防火墙已放行 80、443 端口"
fi
}
# ==================== 生成配置文件 ====================
setup_env_files() {
echo ""
echo "📝 配置环境文件..."
# 6. 复制 .env.tools 和 .env.ASG
[ ! -f .env.tools ] && cp .env.tools.sample .env.tools && echo " ✓ .env.tools"
[ ! -f .env.ASG ] && cp .env.ASG.sample .env.ASG && echo " ✓ .env.ASG"
# 4/5. 配置 .env
if [ ! -f .env ]; then
cp .env.sample .env
fi
if [ "$DEPLOY_MODE" = "ip" ]; then
# IP 模式
sed -i.bak "s|^NUXT_PUBLIC_BASE_APIURL=.*|NUXT_PUBLIC_BASE_APIURL=http://${DEPLOY_IP}:3001|" .env
sed -i.bak "s|^NUXT_PUBLIC_BASE_SOCKETURL=.*|NUXT_PUBLIC_BASE_SOCKETURL=ws://${DEPLOY_IP}:3002|" .env
sed -i.bak "s|^NUXT_PUBLIC_SG_APIURL=.*|NUXT_PUBLIC_SG_APIURL=http://${DEPLOY_IP}:3003|" .env
echo " ✓ .env 已配置为 IP 模式 (${DEPLOY_IP})"
else
# 域名模式
sed -i.bak "s|^NUXT_PUBLIC_BASE_APIURL=.*|NUXT_PUBLIC_BASE_APIURL=/api|" .env
sed -i.bak "s|^NUXT_PUBLIC_BASE_SOCKETURL=.*|NUXT_PUBLIC_BASE_SOCKETURL=wss://${DEPLOY_DOMAIN}/socket.io|" .env
sed -i.bak "s|^NUXT_PUBLIC_SG_APIURL=.*|NUXT_PUBLIC_SG_APIURL=/asg-api|" .env
echo " ✓ .env 已配置为域名模式 (${DEPLOY_DOMAIN})"
# 7. Nginx 配置(域名模式)
PROXY_CONF="${DEPLOY_DOMAIN}.conf"
if [ ! -f "$PROXY_CONF" ]; then
sed "s/51easyai.com/${DEPLOY_DOMAIN}/g" easyai-proxy.conf.sample > "$PROXY_CONF"
echo " ✓ Nginx 配置已生成: $PROXY_CONF"
fi
fi
rm -f .env.bak
}
# ==================== Docker 安装(复用原 start.sh 逻辑) ====================
install_docker() {
echo ""
echo "================================"
echo " Docker 安装与检查"
echo "================================"
if [ -f /etc/os-release ]; then
. /etc/os-release
case "${ID:-}" in
ubuntu|debian) OS_FAMILY="Ubuntu" ;;
centos|rhel|fedora) OS_FAMILY="CentOS" ;;
*) OS_FAMILY="${ID:-Unknown}" ;;
esac
else
OS_FAMILY=$(hostnamectl 2>/dev/null | grep "Operating System" | awk '{print $3}' || echo "Unknown")
fi
OS_VERSION_ID=$(grep -oP '(?<=^VERSION_ID=")[0-9.]+' /etc/os-release 2>/dev/null | cut -d'.' -f1 || echo "0")
OS_CODENAME=""
[[ "$OS_FAMILY" == "Ubuntu" ]] && OS_CODENAME=$(lsb_release -cs 2>/dev/null || (grep VERSION_CODENAME /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"'))
UBUNTU_DOCKER_MIRROR_URL="https://mirrors.ustc.edu.cn/docker-ce"
UBUNTU_DOCKER_GPG_URL="https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg"
CENTOS_DOCKER_MIRROR_URL="https://mirrors.tuna.tsinghua.edu.cn/docker-ce"
check_network() {
if curl -sSf --connect-timeout 5 https://download.docker.com/ &>/dev/null; then
echo "✅ 网络连接正常"
return 0
fi
echo "⚠️ 将使用国内镜像源"
return 0
}
check_network
if command -v docker &>/dev/null; then
echo "✅ Docker 已安装"
else
if [[ "$OS_FAMILY" == "Ubuntu" ]]; then
sudo apt update -y
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL "$UBUNTU_DOCKER_GPG_URL" | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 2>/dev/null || \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] $UBUNTU_DOCKER_MIRROR_URL/linux/ubuntu $OS_CODENAME stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
sudo apt-get update -y
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
elif [[ "$OS_FAMILY" == "CentOS" ]]; then
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo sed -i "s+https://download.docker.com+$CENTOS_DOCKER_MIRROR_URL+g" /etc/yum.repos.d/docker-ce.repo
[[ "$OS_VERSION_ID" -ge "8" ]] && sudo yum module disable -y container-tools 2>/dev/null || true
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
else
echo "❌ 不支持的操作系统: $OS_FAMILY"
exit 1 exit 1
fi }
sudo systemctl enable docker
sudo systemctl start docker elif [[ "$OS_FAMILY" == "CentOS" ]]; then
getent group docker | grep -qw "$USER" || sudo usermod -aG docker "$USER" echo "📦 安装依赖 (CentOS)..."
fi sudo yum install -y yum-utils device-mapper-persistent-data lvm2
echo "🌍 添加 Docker 源 (CentOS) - 使用国内镜像源..."
# 添加 Docker CE 官方 repo
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 替换为国内镜像源
echo "🔄 替换 Docker 源为国内镜像 ($CENTOS_DOCKER_MIRROR_URL)..."
sudo sed -i "s+https://download.docker.com+$CENTOS_DOCKER_MIRROR_URL+" /etc/yum.repos.d/docker-ce.repo || {
echo "❌ 替换 Docker 源失败,可能 repo 文件路径不正确或无权限。"
exit 1
}
# CentOS 8+ 可能会遇到 module 冲突,禁用默认的 container-tools 模块
if [[ "$OS_VERSION_ID" -ge "8" ]]; then
echo "⚙️ 禁用 CentOS 8+ 默认的 container-tools 模块以避免冲突..."
sudo yum module disable -y container-tools
sudo yum module enable -y container-tools:docker
fi
sudo yum makecache
echo "🐳 安装 Docker (CentOS)..."
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin || {
echo "❌ Docker 或其组件安装失败。请检查错误日志或尝试手动安装。"
echo "提示:如果仍遇到下载问题,请检查网络、防火墙或尝试切换另一个国内镜像源。"
exit 1
}
if docker compose version &>/dev/null; then
echo "✅ Docker Compose 已就绪"
elif command -v docker-compose &>/dev/null; then
echo "✅ Docker Compose (兼容模式) 已就绪"
else else
echo "❌ 请安装 docker-compose-plugin" echo "❌ 未知操作系统 ($OS_FAMILY),无法安装 Docker。"
exit 1 exit 1
fi fi
}
# ==================== 启动服务 ==================== echo "✅ 启动并设置 Docker 开机自启..."
start_services() { sudo systemctl enable docker
echo "" sudo systemctl start docker
echo "🚀 启动 EasyAI 服务..."
if docker compose version &>/dev/null; then # 将当前用户添加到 docker 组,以便无需 sudo 运行 Docker 命令
sudo docker compose pull && sudo docker compose up -d if ! getent group docker | grep -qw "$USER"; then
else echo "👥 将当前用户 ($USER) 添加到 docker 组..."
sudo docker-compose pull && sudo docker-compose up -d sudo usermod -aG docker "$USER"
echo "🔔 请注销并重新登录,以便更改生效。"
fi fi
echo "🎉 EasyAI 应用启动成功" fi
}
# ==================== 执行 HTTPS 配置 ==================== # Docker Compose 检查和安装 (优先使用 docker-compose-plugin)
run_https_setup() { if command -v docker &> /dev/null && docker compose version &> /dev/null; then
if [ "$DEPLOY_HTTPS" = true ] && [ -n "$DEPLOY_DOMAIN" ]; then echo "✅ Docker Compose (插件版) 已安装,跳过安装步骤"
echo "" elif command -v docker-compose &> /dev/null && ! command -v docker &> /dev/null; then
echo "🔒 执行 HTTPS 配置(请确保服务器已放行 80、443 端口)..." echo "⚠️ 检测到旧版 Docker Compose 独立安装,但未检测到 Docker 插件版。"
if [ -f "./https.sh" ]; then echo "建议在安装 Docker CE 时一起安装 docker-compose-plugin。"
# https.sh 依赖 easyai-proxy.conf需使用生成的域名配置文件 else
export EASYAI_PROXY_CONF="${DEPLOY_DOMAIN}.conf" echo "⚙️ 安装 Docker Compose (插件版)..."
bash ./https.sh PLUGIN_INSTALL_SUCCESS=1
# 如果 Docker CE 安装成功docker-compose-plugin 应该已经安装了。
# 这里是额外的检查,以防万一。
if [[ "$OS_FAMILY" == "Ubuntu" ]]; then
sudo apt-get install -y docker-compose-plugin || PLUGIN_INSTALL_SUCCESS=0
elif [[ "$OS_FAMILY" == "CentOS" ]]; then
sudo yum install -y docker-compose-plugin || PLUGIN_INSTALL_SUCCESS=0
else
echo "❌ 未知操作系统,无法安装 Docker Compose 插件版。"
PLUGIN_INSTALL_SUCCESS=0
fi
# 检查插件版安装是否成功
if [[ $PLUGIN_INSTALL_SUCCESS -eq 1 ]]; then
echo "✅ Docker Compose 插件版安装成功"
else
echo "⚠️ Docker Compose 插件版安装失败,尝试使用本地二进制文件安装..."
#将文件移动至/usr/bin目录下并重命名
sudo cp ./docker-compose-linux-x86_64 /usr/bin/docker-compose
# 添加执行权限
sudo chmod +x /usr/bin/docker-compose
# 验证安装
if command -v docker-compose &> /dev/null; then
echo "✅ Docker Compose 二进制文件安装成功"
else else
echo "⚠️ 未找到 https.sh请手动配置 HTTPS" echo "❌ Docker Compose 二进制文件安装失败,请手动检查。"
exit 1
fi fi
fi fi
} fi
# ==================== 主流程 ====================
main() {
init_project_dir
# 检查是否已有 .env 且非强制重新配置 echo "📌 Docker 运行状态:"
if [ -f .env ] && [ -z "$DEPLOY_FORCE_RECONFIG" ] && [ -z "$DEPLOY_ACCESS" ]; then sudo systemctl status docker --no-pager || true
echo "📁 检测到已有 .env 配置"
read -r -p "是否重新配置部署方式?[y/N]: " reconfigure
if [[ ! "$reconfigure" =~ ^[yY] ]]; then
echo "⏭️ 使用现有配置继续..."
DEPLOY_MODE="skip"
fi
fi
if [ "$DEPLOY_MODE" != "skip" ]; then echo "📌 Docker Compose 版本:"
run_deploy_questions # 优先使用 docker compose 命令(新版),如果不行再尝试 docker-compose旧版或别名
fi if command -v docker &> /dev/null && docker compose version &> /dev/null; then
docker compose version
elif command -v docker-compose &> /dev/null; then
docker-compose -v
else
echo "❌ 无法检测 Docker Compose 版本。"
fi
if [ "$DEPLOY_MODE" != "skip" ]; then echo "🎉 Docker 和 Docker Compose 已就绪!"
setup_env_files
else
[ ! -f .env.tools ] && cp .env.tools.sample .env.tools
[ ! -f .env.ASG ] && cp .env.ASG.sample .env.ASG
fi
if [ "$DEPLOY_DRY_RUN" = "1" ]; then echo "🚀 启动EasyAI"
echo "" # 对于新版 docker-compose-plugin命令是 'docker compose'
echo "⚠️ dry-run 模式:跳过 Docker 安装和服务启动" if command -v docker &> /dev/null && docker compose version &> /dev/null; then
echo " 配置文件已生成,可直接运行 ./start.sh 完成部署" sudo docker compose pull && sudo docker compose up -d
else else # 兼容旧版独立安装的 docker-compose
install_docker sudo docker-compose pull && sudo docker-compose up -d
start_services fi
run_https_setup echo "🎉EasyAI应用启动成功"
fi
echo ""
echo "================================"
echo " 部署完成"
echo "================================"
if [ "$DEPLOY_MODE" = "ip" ] && [ -n "$DEPLOY_IP" ]; then
echo "访问地址: http://${DEPLOY_IP}:3010"
elif [ "$DEPLOY_MODE" = "domain" ] && [ -n "$DEPLOY_DOMAIN" ]; then
echo "访问地址: http://${DEPLOY_DOMAIN} (配置 Nginx 后)"
[ "$DEPLOY_HTTPS" = true ] && echo "HTTPS 已启用"
fi
echo ""
}
main "$@"