From 9747bbe7cb8b0ce48e985e1b9025119c380b764e Mon Sep 17 00:00:00 2001 From: hukdoesn Date: Wed, 30 Jul 2025 11:58:47 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20fix:=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=EF=BC=9A=201.=20docker=E5=AE=B9=E5=99=A8=E9=87=8D=E5=90=AFdind?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=201.=20=E6=96=B0=E5=A2=9E=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E5=90=AF=E5=8A=A8=E8=84=9A=E6=9C=AC=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 276 +++++++++++++++++++++--------------------- ci-entrypoint-dind.sh | 44 ++++++- start.sh | 269 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 447 insertions(+), 142 deletions(-) create mode 100755 start.sh diff --git a/README.md b/README.md index 844a052..9316165 100644 --- a/README.md +++ b/README.md @@ -110,143 +110,7 @@ LiteOps采用前后端分离的架构设计: 2. 减少人为操作错误,标准化流程 3. 提供清晰的构建状态和日志,出问题能快速定位 -## 🚀 快速部署 - -#### 1. 获取部署文件 - -你需要获取以下部署文件: - -- `start-containers.sh` - 一键部署脚本 -- `liteops_init.sql` - 数据库初始化文件 -- `liteops` - Docker镜像 - -#### 2. 获取Docker镜像 - -```bash -# 拉取LiteOps镜像 -docker pull liteops/liteops:[最新版本号] -``` - -#### 3. 准备部署文件 - -创建部署目录并放置必要文件: - -```bash -# 创建部署目录 -mkdir liteops-deploy -cd liteops-deploy - -# 将以下文件放入此目录: -# - start-containers.sh -# - liteops_init.sql -``` - -#### 4. 一键部署 - -使用提供的启动脚本进行自动化部署: - -```bash -# 给启动脚本执行权限 -chmod +x start-containers.sh - -# 执行一键部署 -./start-containers.sh -``` -#### 5. 不使用一键部署方式,自定义数据库 - -##### 方案A:配置文件挂载方式 - -```bash -# 1. 先启动MySQL容器(可自定义mysql) -docker run -d \ - --name liteops-mysql \ - -e MYSQL_ROOT_PASSWORD=your_password \ - -p 3306:3306 \ - mysql:8.0 - -# 等待MySQL启动完成后导入初始化数据(会自动创建liteops数据库) -docker exec -i liteops-mysql mysql -uroot -pyour_password < liteops_init.sql - -# 2. 在宿主机创建配置文件 -mkdir -p ./liteops-config -cat > ./liteops-config/config.txt << EOF -[client] -host = 数据库IP # 如果使用Docker网络,填写容器名 -port = 3306 -database = liteops -user = root -password = your_password # 替换为您的实际密码 -default-character-set = utf8mb4 -EOF - -# 3. 启动LiteOps容器,挂载配置文件 -docker run -d \ - --name liteops \ - --privileged \ - -p 80:80 \ - -p 8900:8900 \ - -v $(pwd)/liteops-config/config.txt:/app/backend/conf/config.txt \ - liteops/liteops:[最新版本] -``` - -配置文件 `config.txt`: -```ini -[client] -host = 数据库IP -port = 3306 -database = liteops -user = root -password = your_password -default-character-set = utf8mb4 -``` - -启动脚本会自动完成以下操作: - -#### 6. 验证部署 - -部署完成后,你可以通过以下方式验证: - -```bash -# 检查容器状态 -docker ps - -# 检查日志 -docker logs liteops -🐳 启动 Docker in Docker 环境... -🚀 启动 Docker daemon (轻量级CI/CD模式)... -⏳ 等待 Docker daemon 启动... -time="2025-06-13T02:15:10.086745884Z" level=warning msg="CDI setup error /etc/cdi: failed to monitor for changes: no such file or directory" -time="2025-06-13T02:15:10.086771075Z" level=warning msg="CDI setup error /var/run/cdi: failed to monitor for changes: no such file or directory" -✅ Docker daemon 启动成功 -🔍 验证 Docker 功能... -✅ Docker daemon 版本: 28.2.2 -✅ 存储驱动: vfs -🎉 Docker in Docker 环境启动完成 (轻量级CI/CD模式) -Starting nginx... -Starting nginx: nginx. -Starting backend service... -INFO: Started server process [188] -INFO: Waiting for application startup. -INFO: ASGI 'lifespan' protocol appears unsupported. -INFO: Application startup complete. -INFO: Uvicorn running on http://0.0.0.0:8900 (Press CTRL+C to quit) -docker logs liteops-mysql -``` - -### 访问应用 - -部署成功后,你可以通过以下地址访问: - -- **前端界面**:http://localhost -- **后端API**:http://localhost:8900/api/ -- **MySQL数据库**:localhost:3306 - -### 默认登录信息 - -- **用户名**:admin -- **密码**:admin123 (初始密码,可自行修改) - -## 📋 源码部署 +## 📋 源码部署 (推荐) 如果你想从源码运行 LiteOps,可以按照以下步骤操作: @@ -308,7 +172,26 @@ npm run dev npm run build ``` -### 4. 访问应用 +### 4. 一键启动脚本(可选) + +为了方便启动,我提供了一个启动脚本来同时启动前后端服务: + +```bash +# 给启动脚本执行权限 +chmod +x start.sh + +# 执行一键启动(同时启动前端和后端) +./start.sh +``` + +启动脚本会: +- 检查端口占用情况(8900、8000端口) +- 自动安装缺失的依赖 +- 自动启动后端服务(端口8900) +- 自动启动前端开发服务器(端口8000) +- 支持优雅停止(Ctrl+C时自动清理进程) + +### 5. 访问应用 - **开发模式**: - 前端:http://localhost:8000 @@ -323,6 +206,123 @@ npm run build - 确保 MySQL 服务正常运行,并已导入初始化 SQL 文件 - 修改前端 API 地址配置以匹配后端服务地址 +## 🚀 Docker快速部署(比较臃肿,使用了DinD模式,懂哥可自定义Dockerfile构建) + +如果你希望快速体验LiteOps而不想配置开发环境,可以使用Docker方式部署: + +### 1. 获取部署文件 + +你需要获取以下部署文件: + +- `start-containers.sh` - 一键部署脚本 +- `liteops_init.sql` - 数据库初始化文件 +- `liteops` - Docker镜像 + +### 2. 获取Docker镜像 + +```bash +# 拉取LiteOps镜像 +docker pull liteops/liteops:[最新版本号] +``` + +### 3. 准备部署文件 + +创建部署目录并放置必要文件: + +```bash +# 创建部署目录 +mkdir liteops-deploy +cd liteops-deploy + +# 将以下文件放入此目录: +# - start-containers.sh +# - liteops_init.sql +``` + +### 4. 一键部署 + +使用提供的启动脚本进行自动化部署: + +```bash +# 给启动脚本执行权限 +chmod +x start-containers.sh + +# 执行一键部署 +./start-containers.sh +``` +### 5. 不使用一键部署方式,自定义数据库 + +#### 方案A:配置文件挂载方式 + +```bash +# 1. 先启动MySQL容器(可自定义mysql) +docker run -d \ + --name liteops-mysql \ + -e MYSQL_ROOT_PASSWORD=your_password \ + -p 3306:3306 \ + mysql:8.0 + +# 等待MySQL启动完成后导入初始化数据(会自动创建liteops数据库) +docker exec -i liteops-mysql mysql -uroot -pyour_password < liteops_init.sql + +# 2. 在宿主机创建配置文件 +mkdir -p ./liteops-config +cat > ./liteops-config/config.txt << EOF +[client] +host = 数据库IP # 如果使用Docker网络,填写容器名 +port = 3306 +database = liteops +user = root +password = your_password # 替换为您的实际密码 +default-character-set = utf8mb4 +EOF + +# 3. 启动LiteOps容器,挂载配置文件 +docker run -d \ + --name liteops \ + --privileged \ + -p 80:80 \ + -p 8900:8900 \ + -v $(pwd)/liteops-config/config.txt:/app/backend/conf/config.txt \ + liteops/liteops:[最新版本] +``` + +配置文件 `config.txt`: +```ini +[client] +host = 数据库IP +port = 3306 +database = liteops +user = root +password = your_password +default-character-set = utf8mb4 +``` + +### 6. 验证部署 + +部署完成后,你可以通过以下方式验证: + +```bash +# 检查容器状态 +docker ps + +# 检查日志 +docker logs liteops +``` + +### 访问应用 + +部署成功后,你可以通过以下地址访问: + +- **前端界面**:http://localhost +- **后端API**:http://localhost:8900/api/ +- **MySQL数据库**:localhost:3306 + +### 默认登录信息 + +- **用户名**:admin +- **密码**:admin123 (初始密码,可自行修改) + ## 项目当前状态 LiteOps目前处于很多功能未完善状态,虽然核心功能已经初步实现,但仍有许多需求和功能有待完善,。我希望通过开源的方式收集更多的需求和建议,使这个项目能够更好地服务于实际开发场景。 diff --git a/ci-entrypoint-dind.sh b/ci-entrypoint-dind.sh index 482a441..e7a9d92 100644 --- a/ci-entrypoint-dind.sh +++ b/ci-entrypoint-dind.sh @@ -7,6 +7,17 @@ set -euo pipefail echo "🐳 启动 Docker in Docker 环境..." +# 检测是否为容器重启 +RESTART_FLAG="/tmp/.docker-restart-flag" +if [ -f "$RESTART_FLAG" ]; then + echo "🔄 检测到容器重启,执行清理..." + CONTAINER_RESTART=true +else + echo "🆕 首次启动容器" + CONTAINER_RESTART=false + touch "$RESTART_FLAG" +fi + # 检查是否在特权模式下运行 if [ ! -w /sys/fs/cgroup ]; then echo "❌ 错误: 容器必须在特权模式下运行才能使用 Docker in Docker" @@ -45,23 +56,48 @@ cat > /etc/docker/daemon.json << 'EOF' "insecure-registries": [], "exec-opt": ["native.cgroupdriver=cgroupfs"], "max-concurrent-downloads": 3, - "max-concurrent-uploads": 3 + "max-concurrent-uploads": 3, + "live-restore": false } EOF # 启动轻量级Docker daemon echo "🚀 启动 Docker daemon (轻量级CI/CD模式)..." -# 清理可能存在的旧进程 -pkill dockerd 2>/dev/null || true +# 清理存在的旧进程和文件 +echo "🧹 清理旧的Docker进程和文件..." +# 停止所有Docker相关进程 +pkill -f dockerd 2>/dev/null || true +pkill -f containerd 2>/dev/null || true +pkill -f docker-proxy 2>/dev/null || true + +# 等待进程完全停止 +sleep 2 + +# 强制清理残留进程 +pkill -9 -f dockerd 2>/dev/null || true +pkill -9 -f containerd 2>/dev/null || true +pkill -9 -f docker-proxy 2>/dev/null || true + +# 清理所有相关文件和socket rm -f /var/run/docker.sock /var/run/docker.pid 2>/dev/null || true +rm -f /var/run/containerd/containerd.sock 2>/dev/null || true +rm -f /var/run/containerd/containerd.pid 2>/dev/null || true +rm -rf /var/run/containerd/* 2>/dev/null || true + +# 清理可能的锁文件 +rm -f /var/lib/docker/.docker-lock 2>/dev/null || true +rm -f /var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db-lock 2>/dev/null || true + +# 重新创建必要的目录 +mkdir -p /var/run/containerd +mkdir -p /var/lib/containerd # 启动dockerd dockerd \ --host=unix:///var/run/docker.sock \ --userland-proxy=false \ --experimental=false \ - --live-restore=false \ --iptables=false \ --ip-forward=false \ --pidfile=/var/run/docker.pid \ diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..fcd7960 --- /dev/null +++ b/start.sh @@ -0,0 +1,269 @@ +#!/bin/bash + +# ============================================================================= +# LiteOps 一键启动脚本 +# ============================================================================= + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # 无颜色 + +# 打印带颜色的信息 +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +print_step() { + echo -e "\n${PURPLE}=== $1 ===${NC}" +} + +# 端口检查函数 +check_port() { + local port=$1 + local service_name=$2 + + if lsof -Pi :$port -sTCP:LISTEN -t >/dev/null 2>&1; then + print_error "端口 $port 已被占用!" + print_info "检查占用进程:" + + # 显示占用进程的详细信息 + local pid=$(lsof -Pi :$port -sTCP:LISTEN -t 2>/dev/null | head -1) + if [ ! -z "$pid" ]; then + local process_info=$(ps -p $pid -o pid,ppid,cmd --no-headers 2>/dev/null) + if [ ! -z "$process_info" ]; then + echo -e " ${CYAN}PID${NC}: $pid" + echo -e " ${CYAN}进程${NC}: $process_info" + fi + fi + + print_warning "解决方案:" + echo -e " 1. 停止占用端口的进程: ${CYAN}kill $pid${NC}" + echo -e " 2. 或使用强制停止: ${CYAN}kill -9 $pid${NC}" + echo -e " 3. 或查看所有占用进程: ${CYAN}lsof -i :$port${NC}" + echo "" + return 1 + else + print_info "端口 $port ($service_name) 可用" + return 0 + fi +} + +# 全局变量 +BACKEND_PID="" +FRONTEND_PID="" +BACKEND_PORT=8900 +FRONTEND_PORT=8000 + +# 清理函数 +cleanup() { + print_step "正在清理进程..." + + if [ ! -z "$BACKEND_PID" ]; then + print_info "停止后端服务 (PID: $BACKEND_PID)" + kill $BACKEND_PID 2>/dev/null || true + wait $BACKEND_PID 2>/dev/null || true + fi + + if [ ! -z "$FRONTEND_PID" ]; then + print_info "停止前端服务 (PID: $FRONTEND_PID)" + kill $FRONTEND_PID 2>/dev/null || true + wait $FRONTEND_PID 2>/dev/null || true + fi + + # 清理可能残留的端口占用进程 + if command -v lsof &> /dev/null; then + print_info "清理端口占用..." + lsof -ti:$BACKEND_PORT | xargs kill -9 2>/dev/null || true + lsof -ti:$FRONTEND_PORT | xargs kill -9 2>/dev/null || true + else + print_info "跳过端口清理(lsof命令不可用)" + fi + + print_success "清理完成" + exit 0 +} + +# 注册信号处理 +trap cleanup SIGTERM SIGINT + +# 检查环境 +print_step "检查环境" + +# 检查Python +if ! command -v python3 &> /dev/null; then + print_error "Python3 未安装或不在PATH中" + exit 1 +fi + +# 检查Node.js和npm +if ! command -v node &> /dev/null; then + print_error "Node.js 未安装或不在PATH中" + exit 1 +fi + +if ! command -v npm &> /dev/null; then + print_error "npm 未安装或不在PATH中" + exit 1 +fi + +# 检查项目结构 +if [ ! -d "backend" ]; then + print_error "backend 目录不存在,请确保在项目根目录运行此脚本" + exit 1 +fi + +if [ ! -d "web" ]; then + print_error "web 目录不存在,请确保在项目根目录运行此脚本" + exit 1 +fi + +print_success "环境检查通过" + +# 检查端口占用 +print_step "检查端口占用" + +# 检查是否有lsof命令 +if ! command -v lsof &> /dev/null; then + print_warning "未检测到lsof命令,跳过端口检查" + print_info "如需端口检查功能,请安装lsof:" + echo -e " ${CYAN}macOS${NC}: brew install lsof" + echo -e " ${CYAN}Ubuntu/Debian${NC}: sudo apt-get install lsof" + echo -e " ${CYAN}CentOS/RHEL${NC}: sudo yum install lsof" +else + if ! check_port $BACKEND_PORT "后端服务"; then + exit 1 + fi + + if ! check_port $FRONTEND_PORT "前端服务"; then + exit 1 + fi + + print_success "端口检查通过" +fi + +# 检查后端依赖 +print_step "检查后端依赖" +if [ ! -f "backend/requirements.txt" ]; then + print_error "backend/requirements.txt 不存在" + exit 1 +fi + +cd backend +if ! python3 -c "import uvicorn, django" &> /dev/null; then + print_warning "后端依赖未完整安装,开始安装..." + pip3 install -r requirements.txt + if [ $? -ne 0 ]; then + print_error "后端依赖安装失败" + exit 1 + fi + print_success "后端依赖安装完成" +else + print_success "后端依赖已安装" +fi +cd .. + +# 检查前端依赖 +print_step "检查前端依赖" +cd web +if [ ! -d "node_modules" ]; then + print_warning "前端依赖未安装,开始安装..." + npm install + if [ $? -ne 0 ]; then + print_error "前端依赖安装失败" + exit 1 + fi + print_success "前端依赖安装完成" +else + print_success "前端依赖已安装" +fi +cd .. + +# 启动后端服务 +print_step "启动后端服务" +cd backend +print_info "启动后端服务在端口$BACKEND_PORT..." +python3 -m uvicorn backend.asgi:application --host 0.0.0.0 --port $BACKEND_PORT & +BACKEND_PID=$! +cd .. + +# 等待后端启动 +print_info "等待后端服务启动..." +sleep 3 + +# 检查后端是否启动成功 +if kill -0 $BACKEND_PID 2>/dev/null; then + print_success "后端服务启动成功 (PID: $BACKEND_PID)" +else + print_error "后端服务启动失败" + exit 1 +fi + +# 启动前端服务 +print_step "启动前端服务" +cd web +print_info "启动前端开发服务器在端口$FRONTEND_PORT..." +npm run dev & +FRONTEND_PID=$! +cd .. + +# 等待前端启动 +print_info "等待前端服务启动..." +sleep 3 + +# 检查前端是否启动成功 +if kill -0 $FRONTEND_PID 2>/dev/null; then + print_success "前端服务启动成功 (PID: $FRONTEND_PID)" +else + print_error "前端服务启动失败" + cleanup + exit 1 +fi + +# 启动完成 +print_step "启动完成" +print_success "LiteOps 开发环境已成功启动!" +echo "" +print_info "访问地址:" +echo -e " ${CYAN}前端界面${NC}: http://localhost:$FRONTEND_PORT" +echo -e " ${CYAN}后端API${NC}: http://localhost:$BACKEND_PORT" +echo "" +print_info "默认登录信息:" +echo -e " ${CYAN}用户名${NC}: admin" +echo -e " ${CYAN}密码${NC}: admin123" +echo "" +print_warning "按 Ctrl+C 停止所有服务" + +# 等待信号 +while true; do + # 检查进程是否还在运行 + if ! kill -0 $BACKEND_PID 2>/dev/null; then + print_error "后端服务意外停止" + cleanup + exit 1 + fi + + if ! kill -0 $FRONTEND_PID 2>/dev/null; then + print_error "前端服务意外停止" + cleanup + exit 1 + fi + + sleep 5 +done