From 4ea5f6375d266821e36c3af6c161003f5dcd294a Mon Sep 17 00:00:00 2001 From: error403 Date: Tue, 10 Feb 2026 12:06:09 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=9E=84=E5=BB=BADocker=E9=95=9C=E5=83=8F?= =?UTF-8?q?=EF=BC=8C=E5=AE=9E=E7=8E=B0=E5=AE=B9=E5=99=A8=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E4=BA=A4=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 15 +++ DOCKER-README.md | 221 +++++++++++++++++++++++++++++++++++++++++ Dockerfile | 48 +++++++++ build-docker-run.sh | 41 ++++++++ next.config.js | 26 +++++ nginx.conf | 26 +++++ package-lock.json | 10 ++ test-docker-fix.sh | 235 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 622 insertions(+) create mode 100644 .dockerignore create mode 100644 DOCKER-README.md create mode 100644 Dockerfile create mode 100644 build-docker-run.sh create mode 100644 nginx.conf create mode 100644 test-docker-fix.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b78f2ef --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +node_modules +npm-debug.log +.next +out +dist +.git +.gitignore +README.md +.env +.env.local +.env.development +.env.production +Dockerfile +docker-compose.yml +.dockerignore \ No newline at end of file diff --git a/DOCKER-README.md b/DOCKER-README.md new file mode 100644 index 0000000..0f63696 --- /dev/null +++ b/DOCKER-README.md @@ -0,0 +1,221 @@ +# 🐳 OpenClaw101 容器化部署指南 + +## 🚀 快速部署 + +使用 `build-docker-run.sh` 脚本可以一键构建和运行 OpenClaw101 容器: + +```bash +# 1. 进入项目目录 +cd /repisitory/openclaw101 + +# 2. 运行部署脚本 +chmod +x build-docker-run.sh +sudo ./build-docker-run.sh +``` + +脚本会自动: +- ✅ 检查 Docker 服务状态 +- ✅ 清理旧的构建缓存 +- ✅ 构建 Docker 镜像 +- ✅ 显示运行命令和访问地址 + +## 📋 脚本详解 + +### 脚本功能 +`build-docker-run.sh` 是一个自动化部署脚本,简化了 OpenClaw101 的容器化部署流程。 + +### 可配置参数 + +#### 1. 镜像标签(可选参数) +```bash +# 使用默认标签(openclaw101:latest) +./build-docker-run.sh + +# 使用自定义标签 +./build-docker-run.sh openclaw101:v1.0 +./build-docker-run.sh myregistry.com/openclaw101:production +``` + +#### 2. 容器名称和端口(在脚本中修改) +脚本默认使用以下配置: +```bash +容器名称:openclaw101 +主机端口:3000 +容器端口:80 +``` + +如果需要修改这些配置,可以编辑脚本中的运行命令部分: +```bash +# 在脚本中找到这一行(约第24行) +echo " docker run -d -p 3000:80 --name openclaw101 $TAG" + +# 修改为: +# docker run -d -p 8080:80 --name my-openclaw101 $TAG +``` + +### 配置示例 + +#### 示例1:使用不同端口 +```bash +# 修改脚本中的端口映射 +# 原配置:-p 3000:80 +# 新配置:-p 8080:80 + +# 然后运行脚本 +./build-docker-run.sh +``` + +#### 示例2:使用不同容器名称 +```bash +# 修改脚本中的容器名称 +# 原配置:--name openclaw101 +# 新配置:--name my-openclaw-app + +# 然后运行脚本 +./build-docker-run.sh +``` + +#### 示例3:同时修改端口和名称 +```bash +# 修改脚本中的运行命令 +# 原配置:docker run -d -p 3000:80 --name openclaw101 $TAG +# 新配置:docker run -d -p 9090:80 --name openclaw-prod $TAG + +# 然后运行脚本 +./build-docker-run.sh openclaw101:production +``` + +## 🔧 手动运行命令 + +如果你需要更多控制,也可以直接使用 Docker 命令: + +### 1. 构建镜像 +```bash +# 使用默认标签 +docker build -t openclaw101:latest . + +# 使用自定义标签 +docker build -t myregistry.com/openclaw101:v1.0 . +``` + +### 2. 运行容器 +```bash +# 基本运行(使用脚本默认配置) +docker run -d -p 3000:80 --name openclaw101 openclaw101:latest + +# 自定义端口 +docker run -d -p 8080:80 --name openclaw101 openclaw101:latest + +# 自定义容器名称 +docker run -d -p 3000:80 --name my-openclaw-app openclaw101:latest + +# 后台运行并自动重启 +docker run -d -p 3000:80 --name openclaw101 --restart unless-stopped openclaw101:latest +``` + +### 3. 查看运行状态 +```bash +# 查看容器状态 +docker ps | grep openclaw101 + +# 查看日志 +docker logs -f openclaw101 + +# 查看资源使用 +docker stats openclaw101 +``` + +## 🌐 访问应用 + +部署完成后,通过以下地址访问: + +``` +http://localhost:3000 +``` + +如果修改了端口,请使用对应的端口号: +``` +http://localhost:8080 # 如果修改为8080端口 +``` + +## 🛠️ 管理容器 + +### 停止容器 +```bash +docker stop openclaw101 +``` + +### 启动容器 +```bash +docker start openclaw101 +``` + +### 重启容器 +```bash +docker restart openclaw101 +``` + +### 删除容器 +```bash +# 停止并删除容器 +docker stop openclaw101 && docker rm openclaw101 + +# 删除镜像 +docker rmi openclaw101:latest +``` + +### 进入容器 +```bash +# 进入容器shell +docker exec -it openclaw101 sh +``` + +## 📊 脚本输出示例 + +运行 `./build-docker-run.sh` 会显示以下信息: + +``` +🔨 开始构建 OpenClaw101 Docker 镜像(修复版)... +📦 镜像标签: openclaw101:latest +🧹 清理旧的构建缓存... +📦 构建 Docker 镜像... + +✅ 构建完成! +📊 镜像信息: +openclaw101 latest abc123def456 35MB 2 minutes ago + +🚀 运行命令: + docker run -d -p 3000:80 --name openclaw101 openclaw101:latest + +🔍 查看日志: + docker logs -f openclaw101 + +🌐 访问地址: http://localhost:3000 +``` + +## ⚠️ 注意事项 + +1. **Docker 服务**:确保 Docker 服务正在运行 +2. **端口冲突**:如果 3000 端口被占用,请修改脚本中的端口配置 +3. **容器名称冲突**:如果已存在名为 `openclaw101` 的容器,请修改容器名称 +4. **权限问题**:通常不需要 `sudo`,除非 Docker 安装配置需要 +5. **构建缓存**:脚本会自动清理旧的构建缓存,但不会影响现有容器 + +## 🔄 更新部署 + +如果需要更新应用: + +```bash +# 1. 停止并删除旧容器 +docker stop openclaw101 && docker rm openclaw101 + +# 2. 重新构建和运行 +./build-docker-run.sh +``` + +## 📞 支持 + +如有问题,请参考: +- [Docker 官方文档](https://docs.docker.com/) +- [脚本源代码](./build-docker-run.sh) +- [项目主文档](./README.md) \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..218e853 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +# ========================================== +# 阶段 1: 构建阶段 +# ========================================== +FROM node:20-alpine AS builder + +# 设置工作目录 +WORKDIR /app + +# 安装必要的构建工具(Alpine环境需要) +RUN apk add --no-cache libc6-compat + +# 先复制package文件(利用Docker缓存层) +COPY package*.json ./ + +# 安装所有依赖(包括开发依赖,构建需要TypeScript等) +RUN npm ci && npm cache clean --force + +# 复制源代码 +COPY . . + +# 验证 TypeScript 配置和路径别名 +# 如果这一步失败,会提前发现问题 +RUN echo "=== 验证 TypeScript 路径别名 ===" && \ + node -e "const ts = require('typescript'); const cfg = require('./tsconfig.json'); console.log('tsconfig paths:', JSON.stringify(cfg.compilerOptions?.paths, null, 2))" + +# 构建静态站点 +ENV NODE_ENV=production +RUN npm run build + +# ========================================== +# 阶段 2: 运行阶段(Nginx 托管) +# ========================================== +FROM nginx:1.25-alpine-slim AS runtime + +# 复制构建产物到 Nginx +COPY --from=builder /app/out /usr/share/nginx/html + +# 复制自定义 Nginx 配置 +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# 暴露端口 +EXPOSE 80 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/build-docker-run.sh b/build-docker-run.sh new file mode 100644 index 0000000..b1294a3 --- /dev/null +++ b/build-docker-run.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# OpenClaw101 Docker 构建脚本 +# 用法: ./build-docker-run.sh [tag] + +set -e + +# 默认标签 +TAG=${1:-"openclaw101:latest"} + +echo "🔨 开始构建 OpenClaw101 Docker 镜像..." +echo "📦 镜像标签: $TAG" + +# 检查 Docker 是否运行 +if ! docker info > /dev/null 2>&1; then + echo "❌ Docker 未运行,请启动 Docker 服务" + exit 1 +fi + +# 清理旧的构建缓存(可选) +echo "🧹 清理旧的构建缓存..." +docker builder prune -f + +# 构建镜像 +echo "📦 构建 Docker 镜像..." +docker build -t "$TAG" . + +# 显示构建结果 +echo "" +echo "✅ 构建完成!" +echo "📊 镜像信息:" +docker images | grep openclaw101 + +echo "" +echo "🚀 运行命令:" +echo " docker run -d -p 3000:80 --name openclaw101 $TAG" +echo "" +echo "🔍 查看日志:" +echo " docker logs -f openclaw101" +echo "" +echo "🌐 访问地址: http://localhost:3000" \ No newline at end of file diff --git a/next.config.js b/next.config.js index afa8e58..2caae56 100644 --- a/next.config.js +++ b/next.config.js @@ -1,3 +1,4 @@ +const path = require('path'); const withMDX = require('@next/mdx')({ extension: /\.mdx?$/, options: { @@ -13,6 +14,31 @@ const nextConfig = { unoptimized: true, }, pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'], + + // ========================================== + // 关键修复:配置 webpack 路径别名 + // 确保 @/* 路径在 Docker 环境中正确解析 + // ========================================== + webpack: (config) => { + // 确保 resolve 和 alias 对象存在 + if (!config.resolve) { + config.resolve = {}; + } + if (!config.resolve.alias) { + config.resolve.alias = {}; + } + + // 添加 @ 路径别名指向 src 目录 + config.resolve.alias['@'] = path.resolve(__dirname, 'src'); + + return config; + }, + + // 确保 TypeScript 路径别名也能被正确解析 + experimental: { + // 禁用某些可能导致问题的实验性功能 + turboMode: false, + }, }; module.exports = withMDX(nextConfig); diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..e00d4b5 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,26 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # Gzip 压缩 + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml; + + # 缓存静态资源 + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Next.js 静态导出路由处理 + location / { + try_files $uri $uri.html $uri/ =404; + } + + # 404 页面 + error_page 404 /404.html; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9bdc854..e6c3df3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -589,6 +589,7 @@ "resolved": "https://registry.npmjs.org/@mdx-js/loader/-/loader-3.1.1.tgz", "integrity": "sha512-0TTacJyZ9mDmY+VefuthVshaNIyCGZHJG2fMnGaDttCt8HmjUF7SizlHJpaCDoGnN635nK1wpzfpx/Xx5S4WnQ==", "license": "MIT", + "peer": true, "dependencies": { "@mdx-js/mdx": "^3.0.0", "source-map": "^0.7.0" @@ -648,6 +649,7 @@ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", "license": "MIT", + "peer": true, "dependencies": { "@types/mdx": "^2.0.0" }, @@ -960,6 +962,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -992,6 +995,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1157,6 +1161,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2086,6 +2091,7 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -3465,6 +3471,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -3644,6 +3651,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -3656,6 +3664,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -4277,6 +4286,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, diff --git a/test-docker-fix.sh b/test-docker-fix.sh new file mode 100644 index 0000000..d9eef5d --- /dev/null +++ b/test-docker-fix.sh @@ -0,0 +1,235 @@ +#!/bin/bash +# Docker 构建修复测试脚本 + +set -e + +# 获取脚本所在目录作为项目目录(兼容任何运行位置) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$SCRIPT_DIR" +IMAGE_TAG="openclaw101:v1.0-test" +CONTAINER_NAME="test-openclaw101" +TEST_PORT="${TEST_PORT:-3000}" + +echo "==============================================" +echo " OpenClaw101 Docker 构建修复测试" +echo "==============================================" +echo " 项目目录: $PROJECT_DIR" +echo " 测试端口: $TEST_PORT" +echo "" + +# 检查 Docker +echo "🔍 检查 Docker 状态..." +if ! command -v docker &> /dev/null; then + echo "❌ Docker 命令未找到,请确保 Docker 已安装" + exit 1 +fi + +if ! docker info > /dev/null 2>&1; then + echo "❌ Docker 服务未运行,请启动 Docker" + exit 1 +fi + +echo "✅ Docker 可用" +echo "" + +# 进入项目目录(确保在任何位置运行都能正确) +if [[ ! -f "$PROJECT_DIR/Dockerfile" ]]; then + echo "❌ 未找到 Dockerfile,请确保脚本位于项目根目录" + echo " 查找路径: $PROJECT_DIR/Dockerfile" + exit 1 +fi + +cd "$PROJECT_DIR" || exit 1 + +# 清理旧构建 +echo "🧹 清理旧构建..." +docker rm -f "$CONTAINER_NAME" 2>/dev/null || true +docker rmi -f "$IMAGE_TAG" 2>/dev/null || true +docker builder prune -f > /dev/null 2>&1 || true +echo "✅ 清理完成" +echo "" + +# 开始构建 +echo "🔨 开始构建 Docker 镜像..." +echo " 镜像标签: $IMAGE_TAG" +echo " Dockerfile: $PROJECT_DIR/Dockerfile" +echo "" + +if docker build -t "$IMAGE_TAG" .; then + echo "" + echo "✅ Docker 构建成功!" + echo "" +else + echo "" + echo "❌ Docker 构建失败" + echo "" + echo "💡 尝试使用备用方案(node:20-slim)..." + echo "" + + if docker build -f Dockerfile.slim -t "$IMAGE_TAG" .; then + echo "" + echo "✅ 备用方案构建成功!" + echo "" + else + echo "" + echo "❌ 备用方案也失败了" + echo "" + echo "请查看详细错误信息:" + echo " docker build -f Dockerfile.debug -t openclaw101:debug . 2>&1" + exit 1 + fi +fi + +# 显示镜像信息 +echo "📊 镜像信息:" +docker images | grep openclaw101 | grep -v "REPOSITORY" +echo "" + +# 检查端口占用(多种方式确保兼容性) +echo "🔍 检查端口 $TEST_PORT 占用..." + +port_in_use=0 +# 方法1: 使用 ss (推荐,现代Linux) +if command -v ss > /dev/null 2>&1; then + if ss -tuln 2>/dev/null | grep -q ":$TEST_PORT "; then + port_in_use=1 + fi +# 方法2: 使用 netstat +elif command -v netstat > /dev/null 2>&1; then + if netstat -tuln 2>/dev/null | grep -q ":$TEST_PORT "; then + port_in_use=1 + fi +# 方法3: 使用 lsof +elif command -v lsof > /dev/null 2>&1; then + if lsof -i :"$TEST_PORT" > /dev/null 2>&1; then + port_in_use=1 + fi +fi + +if [[ $port_in_use -eq 1 ]]; then + echo "❌ 端口 $TEST_PORT 已被占用,请先释放端口" + echo " 占用该端口的进程:" + if command -v lsof > /dev/null 2>&1; then + lsof -i :"$TEST_PORT" 2>/dev/null | grep -v "^COMMAND" | head -5 + elif command -v ss > /dev/null 2>&1; then + ss -tulnp 2>/dev/null | grep ":$TEST_PORT " | head -5 + fi + echo "" + echo "💡 您可以:" + echo " 1. 停止占用端口的进程" + echo " 2. 使用其他端口: TEST_PORT=3001 $0" + exit 1 +else + echo "✅ 端口 $TEST_PORT 可用" +fi +echo "" + +# 检查 Docker 中是否有容器占用该端口 +echo "🔍 检查 Docker 端口映射..." +if docker ps --format "table {{.Names}}\t{{.Ports}}" | grep -q ":$TEST_PORT-"; then + echo "⚠️ 发现 Docker 容器已映射端口 $TEST_PORT:" + docker ps --format "table {{.Names}}\t{{.Ports}}" | grep ":$TEST_PORT-" + echo "" + echo "💡 建议先清理现有容器:" + echo " docker rm -f \$(docker ps -q --filter \"publish=$TEST_PORT\")" + exit 1 +fi +echo "✅ Docker 端口检查通过" +echo "" + +# 运行测试容器 +echo "🚀 启动测试容器..." +if ! docker run -d -p "$TEST_PORT":80 --name "$CONTAINER_NAME" "$IMAGE_TAG" > /dev/null; then + echo "❌ 容器启动失败" + exit 1 +fi + +# 等待服务启动(智能轮询,支持健康检查) +echo "⏳ 等待服务启动..." +echo " 最大等待时间: 60秒" +echo "" + +max_wait=60 +interval=2 +elapsed=0 +health_check_url="http://localhost:$TEST_PORT" + +# 先等待容器状态变为 running +echo " [1/2] 等待容器启动..." +while [[ $elapsed -lt $max_wait ]]; do + container_status=$(docker inspect -f '{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "unknown") + + if [[ "$container_status" == "running" ]]; then + echo " ✅ 容器已启动 (${elapsed}s)" + break + elif [[ "$container_status" == "exited" ]] || [[ "$container_status" == "dead" ]]; then + echo " ❌ 容器异常退出" + echo "" + echo "📋 容器日志:" + docker logs --tail 50 "$CONTAINER_NAME" 2>&1 || true + docker rm -f "$CONTAINER_NAME" > /dev/null 2>&1 || true + exit 1 + fi + + sleep $interval + elapsed=$((elapsed + interval)) + echo " ⏳ 等待容器启动... (${elapsed}s/${max_wait}s)" +done + +if [[ $elapsed -ge $max_wait ]]; then + echo " ❌ 容器启动超时" + docker logs --tail 30 "$CONTAINER_NAME" 2>&1 || true + docker rm -f "$CONTAINER_NAME" > /dev/null 2>&1 || true + exit 1 +fi + +# 等待应用响应 HTTP 请求 +echo "" +echo " [2/2] 等待应用响应..." +elapsed=0 +while [[ $elapsed -lt $max_wait ]]; do + http_code=$(curl -s -o /dev/null -w "%{http_code}" "$health_check_url" 2>/dev/null || echo "000") + + if [[ "$http_code" =~ ^[23][0-9]{2}$ ]]; then + echo " ✅ 应用响应正常 (HTTP $http_code, ${elapsed}s)" + echo "" + echo "🎉 测试完成!构建修复成功!" + echo "" + echo "📋 使用说明:" + echo " 访问地址: $health_check_url" + echo " 查看日志: docker logs -f $CONTAINER_NAME" + echo " 停止容器: docker stop $CONTAINER_NAME" + echo " 删除容器: docker rm $CONTAINER_NAME" + echo "" + echo "==============================================" + echo " 测试完成" + echo "==============================================" + exit 0 + fi + + # 检查容器是否还在运行 + if [[ $(docker inspect -f '{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null) != "running" ]]; then + echo " ❌ 容器已停止" + echo "" + echo "📋 容器日志:" + docker logs --tail 50 "$CONTAINER_NAME" 2>&1 || true + exit 1 + fi + + sleep $interval + elapsed=$((elapsed + interval)) + echo " ⏳ 等待应用就绪... (${elapsed}s/${max_wait}s, last HTTP: $http_code)" +done + +# 超时处理 +echo "" +echo "⚠️ 应用启动超时(${max_wait}秒)" +echo "" +echo "📋 诊断信息:" +echo " 容器状态: $(docker inspect -f '{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "unknown")" +echo " 容器日志(最近20行):" +docker logs --tail 20 "$CONTAINER_NAME" 2>&1 || true +echo "" +echo "💡 您可以手动检查:" +echo " curl -v $health_check_url" +echo " docker exec -it $CONTAINER_NAME /bin/sh" From aab5da850d208299051ea2aa34106f10d8b9925e Mon Sep 17 00:00:00 2001 From: 403-Forbidde <103308297+403-Forbidde@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:10:02 +0800 Subject: [PATCH 2/3] Delete test-docker-fix.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 测试过程文件,不需要提交 --- test-docker-fix.sh | 235 --------------------------------------------- 1 file changed, 235 deletions(-) delete mode 100644 test-docker-fix.sh diff --git a/test-docker-fix.sh b/test-docker-fix.sh deleted file mode 100644 index d9eef5d..0000000 --- a/test-docker-fix.sh +++ /dev/null @@ -1,235 +0,0 @@ -#!/bin/bash -# Docker 构建修复测试脚本 - -set -e - -# 获取脚本所在目录作为项目目录(兼容任何运行位置) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_DIR="$SCRIPT_DIR" -IMAGE_TAG="openclaw101:v1.0-test" -CONTAINER_NAME="test-openclaw101" -TEST_PORT="${TEST_PORT:-3000}" - -echo "==============================================" -echo " OpenClaw101 Docker 构建修复测试" -echo "==============================================" -echo " 项目目录: $PROJECT_DIR" -echo " 测试端口: $TEST_PORT" -echo "" - -# 检查 Docker -echo "🔍 检查 Docker 状态..." -if ! command -v docker &> /dev/null; then - echo "❌ Docker 命令未找到,请确保 Docker 已安装" - exit 1 -fi - -if ! docker info > /dev/null 2>&1; then - echo "❌ Docker 服务未运行,请启动 Docker" - exit 1 -fi - -echo "✅ Docker 可用" -echo "" - -# 进入项目目录(确保在任何位置运行都能正确) -if [[ ! -f "$PROJECT_DIR/Dockerfile" ]]; then - echo "❌ 未找到 Dockerfile,请确保脚本位于项目根目录" - echo " 查找路径: $PROJECT_DIR/Dockerfile" - exit 1 -fi - -cd "$PROJECT_DIR" || exit 1 - -# 清理旧构建 -echo "🧹 清理旧构建..." -docker rm -f "$CONTAINER_NAME" 2>/dev/null || true -docker rmi -f "$IMAGE_TAG" 2>/dev/null || true -docker builder prune -f > /dev/null 2>&1 || true -echo "✅ 清理完成" -echo "" - -# 开始构建 -echo "🔨 开始构建 Docker 镜像..." -echo " 镜像标签: $IMAGE_TAG" -echo " Dockerfile: $PROJECT_DIR/Dockerfile" -echo "" - -if docker build -t "$IMAGE_TAG" .; then - echo "" - echo "✅ Docker 构建成功!" - echo "" -else - echo "" - echo "❌ Docker 构建失败" - echo "" - echo "💡 尝试使用备用方案(node:20-slim)..." - echo "" - - if docker build -f Dockerfile.slim -t "$IMAGE_TAG" .; then - echo "" - echo "✅ 备用方案构建成功!" - echo "" - else - echo "" - echo "❌ 备用方案也失败了" - echo "" - echo "请查看详细错误信息:" - echo " docker build -f Dockerfile.debug -t openclaw101:debug . 2>&1" - exit 1 - fi -fi - -# 显示镜像信息 -echo "📊 镜像信息:" -docker images | grep openclaw101 | grep -v "REPOSITORY" -echo "" - -# 检查端口占用(多种方式确保兼容性) -echo "🔍 检查端口 $TEST_PORT 占用..." - -port_in_use=0 -# 方法1: 使用 ss (推荐,现代Linux) -if command -v ss > /dev/null 2>&1; then - if ss -tuln 2>/dev/null | grep -q ":$TEST_PORT "; then - port_in_use=1 - fi -# 方法2: 使用 netstat -elif command -v netstat > /dev/null 2>&1; then - if netstat -tuln 2>/dev/null | grep -q ":$TEST_PORT "; then - port_in_use=1 - fi -# 方法3: 使用 lsof -elif command -v lsof > /dev/null 2>&1; then - if lsof -i :"$TEST_PORT" > /dev/null 2>&1; then - port_in_use=1 - fi -fi - -if [[ $port_in_use -eq 1 ]]; then - echo "❌ 端口 $TEST_PORT 已被占用,请先释放端口" - echo " 占用该端口的进程:" - if command -v lsof > /dev/null 2>&1; then - lsof -i :"$TEST_PORT" 2>/dev/null | grep -v "^COMMAND" | head -5 - elif command -v ss > /dev/null 2>&1; then - ss -tulnp 2>/dev/null | grep ":$TEST_PORT " | head -5 - fi - echo "" - echo "💡 您可以:" - echo " 1. 停止占用端口的进程" - echo " 2. 使用其他端口: TEST_PORT=3001 $0" - exit 1 -else - echo "✅ 端口 $TEST_PORT 可用" -fi -echo "" - -# 检查 Docker 中是否有容器占用该端口 -echo "🔍 检查 Docker 端口映射..." -if docker ps --format "table {{.Names}}\t{{.Ports}}" | grep -q ":$TEST_PORT-"; then - echo "⚠️ 发现 Docker 容器已映射端口 $TEST_PORT:" - docker ps --format "table {{.Names}}\t{{.Ports}}" | grep ":$TEST_PORT-" - echo "" - echo "💡 建议先清理现有容器:" - echo " docker rm -f \$(docker ps -q --filter \"publish=$TEST_PORT\")" - exit 1 -fi -echo "✅ Docker 端口检查通过" -echo "" - -# 运行测试容器 -echo "🚀 启动测试容器..." -if ! docker run -d -p "$TEST_PORT":80 --name "$CONTAINER_NAME" "$IMAGE_TAG" > /dev/null; then - echo "❌ 容器启动失败" - exit 1 -fi - -# 等待服务启动(智能轮询,支持健康检查) -echo "⏳ 等待服务启动..." -echo " 最大等待时间: 60秒" -echo "" - -max_wait=60 -interval=2 -elapsed=0 -health_check_url="http://localhost:$TEST_PORT" - -# 先等待容器状态变为 running -echo " [1/2] 等待容器启动..." -while [[ $elapsed -lt $max_wait ]]; do - container_status=$(docker inspect -f '{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "unknown") - - if [[ "$container_status" == "running" ]]; then - echo " ✅ 容器已启动 (${elapsed}s)" - break - elif [[ "$container_status" == "exited" ]] || [[ "$container_status" == "dead" ]]; then - echo " ❌ 容器异常退出" - echo "" - echo "📋 容器日志:" - docker logs --tail 50 "$CONTAINER_NAME" 2>&1 || true - docker rm -f "$CONTAINER_NAME" > /dev/null 2>&1 || true - exit 1 - fi - - sleep $interval - elapsed=$((elapsed + interval)) - echo " ⏳ 等待容器启动... (${elapsed}s/${max_wait}s)" -done - -if [[ $elapsed -ge $max_wait ]]; then - echo " ❌ 容器启动超时" - docker logs --tail 30 "$CONTAINER_NAME" 2>&1 || true - docker rm -f "$CONTAINER_NAME" > /dev/null 2>&1 || true - exit 1 -fi - -# 等待应用响应 HTTP 请求 -echo "" -echo " [2/2] 等待应用响应..." -elapsed=0 -while [[ $elapsed -lt $max_wait ]]; do - http_code=$(curl -s -o /dev/null -w "%{http_code}" "$health_check_url" 2>/dev/null || echo "000") - - if [[ "$http_code" =~ ^[23][0-9]{2}$ ]]; then - echo " ✅ 应用响应正常 (HTTP $http_code, ${elapsed}s)" - echo "" - echo "🎉 测试完成!构建修复成功!" - echo "" - echo "📋 使用说明:" - echo " 访问地址: $health_check_url" - echo " 查看日志: docker logs -f $CONTAINER_NAME" - echo " 停止容器: docker stop $CONTAINER_NAME" - echo " 删除容器: docker rm $CONTAINER_NAME" - echo "" - echo "==============================================" - echo " 测试完成" - echo "==============================================" - exit 0 - fi - - # 检查容器是否还在运行 - if [[ $(docker inspect -f '{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null) != "running" ]]; then - echo " ❌ 容器已停止" - echo "" - echo "📋 容器日志:" - docker logs --tail 50 "$CONTAINER_NAME" 2>&1 || true - exit 1 - fi - - sleep $interval - elapsed=$((elapsed + interval)) - echo " ⏳ 等待应用就绪... (${elapsed}s/${max_wait}s, last HTTP: $http_code)" -done - -# 超时处理 -echo "" -echo "⚠️ 应用启动超时(${max_wait}秒)" -echo "" -echo "📋 诊断信息:" -echo " 容器状态: $(docker inspect -f '{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "unknown")" -echo " 容器日志(最近20行):" -docker logs --tail 20 "$CONTAINER_NAME" 2>&1 || true -echo "" -echo "💡 您可以手动检查:" -echo " curl -v $health_check_url" -echo " docker exec -it $CONTAINER_NAME /bin/sh" From a144db36fb8a41f2ddc56c15cb75ba0e23addf63 Mon Sep 17 00:00:00 2001 From: 403-Forbidde <103308297+403-Forbidde@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:18:09 +0800 Subject: [PATCH 3/3] Update directory path in Docker README --- DOCKER-README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DOCKER-README.md b/DOCKER-README.md index 0f63696..0f65675 100644 --- a/DOCKER-README.md +++ b/DOCKER-README.md @@ -6,7 +6,7 @@ ```bash # 1. 进入项目目录 -cd /repisitory/openclaw101 +cd ~/openclaw101/ # 2. 运行部署脚本 chmod +x build-docker-run.sh @@ -218,4 +218,4 @@ docker stop openclaw101 && docker rm openclaw101 如有问题,请参考: - [Docker 官方文档](https://docs.docker.com/) - [脚本源代码](./build-docker-run.sh) -- [项目主文档](./README.md) \ No newline at end of file +- [项目主文档](./README.md)