Spaces:
Runtime error
Runtime error
File size: 7,492 Bytes
64b378e 490d7c8 83c2581 64b378e 104f18f 3074d8e 93b38bc 0bf8440 83c2581 93b38bc 0bf8440 91b07df 93b38bc 0bf8440 0f9dd17 b6222b3 490d7c8 0bf8440 93b38bc 0bf8440 93b38bc 0bf8440 93b38bc 0bf8440 93b38bc 0bf8440 93b38bc 0bf8440 93b38bc 0bf8440 93b38bc 0bf8440 64b378e 490d7c8 9d4129b 490d7c8 6fbefb9 490d7c8 83c2581 9d4129b 4595a4f 9d4129b 78cca53 cb5290a f801149 9f5c21a 9d4129b 0839e2c 9d4129b 4595a4f 490d7c8 fbbb73f 490d7c8 fbbb73f c014448 9d4129b 64b378e 3074d8e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | # 核心镜像选择
FROM node:22-slim
# 1. 基础依赖补全
RUN apt-get update && apt-get install -y --no-install-recommends \
git openssh-client build-essential python3 python3-pip \
g++ make ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# 2. 安装 HF 数据交互工具
RUN pip3 install --no-cache-dir huggingface_hub --break-system-packages
# 3. 构建环境与 Git 协议优化
RUN update-ca-certificates && \
git config --global http.sslVerify false && \
git config --global url."https://github.com/".insteadOf ssh://git@github.com/
# 4. OpenClaw 核心安装
RUN npm install -g openclaw@latest --unsafe-perm
# 5. 安装飞书频道插件(预装)
RUN npm install -g @openclaw/feishu --unsafe-perm
# 6. 环境变量预设
ENV PORT=7860 \
OPENCLAW_GATEWAY_MODE=local \
HOME=/root
# 7. Python 同步引擎 (sync.py) - 增强版(json配置+压缩数据,直接覆盖配置)
RUN echo 'import os, sys, tarfile\n\
from huggingface_hub import HfApi, hf_hub_download\n\
from datetime import datetime, timedelta\n\
import json\n\
import shutil\n\
\n\
api = HfApi()\n\
repo_id = os.getenv("HF_DATASET")\n\
token = os.getenv("HF_TOKEN")\n\
OPENCLAW_DIR = "/root/.openclaw"\n\
\n\
BACKUP_FILES = [\n\
"agents",\n\
"credentials",\n\
"openclaw.json",\n\
"workspace/IDENTITY.md",\n\
"workspace/USER.md",\n\
"workspace/SOUL.md",\n\
"workspace/AGENTS.md",\n\
"workspace/TOOLS.md",\n\
"workspace/MEMORY.md",\n\
"workspace/skills",\n\
]\n\
\n\
def restore():\n\
try:\n\
files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token)\n\
now = datetime.now()\n\
restored = False\n\
for i in range(5):\n\
day = (now - timedelta(days=i)).strftime("%Y-%m-%d")\n\
config_name = f"backup_{day}_config.json"\n\
data_name = f"backup_{day}_data.tar.gz"\n\
\n\
# 1. 恢复数据包(如果存在)\n\
if data_name in files:\n\
data_path = hf_hub_download(repo_id=repo_id, filename=data_name, repo_type="dataset", token=token)\n\
with tarfile.open(data_path, "r:gz") as tar:\n\
tar.extractall(path=OPENCLAW_DIR)\n\
print(f"Restored data from {data_name}")\n\
restored = True\n\
\n\
# 2. 恢复配置文件(如果存在),直接覆盖现有配置\n\
if config_name in files:\n\
config_path = hf_hub_download(repo_id=repo_id, filename=config_name, repo_type="dataset", token=token)\n\
target_config_path = os.path.join(OPENCLAW_DIR, "openclaw.json")\n\
# 确保目标目录存在\n\
os.makedirs(os.path.dirname(target_config_path), exist_ok=True)\n\
shutil.copy2(config_path, target_config_path)\n\
print(f"Restored config from {config_name} (overwritten)")\n\
restored = True\n\
\n\
if restored:\n\
print("Restore completed.")\n\
return True\n\
\n\
print("No backup found in last 5 days")\n\
return False\n\
except Exception as e:\n\
print(f"Restore Error: {e}")\n\
return False\n\
\n\
def backup():\n\
try:\n\
day = datetime.now().strftime("%Y-%m-%d")\n\
config_name = f"backup_{day}_config.json"\n\
data_name = f"backup_{day}_data.tar.gz"\n\
\n\
# 1. 备份配置文件(直接上传 JSON,不压缩)\n\
config_path = os.path.join(OPENCLAW_DIR, "openclaw.json")\n\
if os.path.exists(config_path):\n\
with open(config_path, "rb") as f:\n\
api.upload_file(\n\
path_or_fileobj=f,\n\
path_in_repo=config_name,\n\
repo_id=repo_id,\n\
repo_type="dataset",\n\
token=token\n\
)\n\
print(f"Config backup {config_name} uploaded.")\n\
\n\
# 2. 备份其他文件(打包为 tar.gz)\n\
with tarfile.open(data_name, "w:gz") as tar:\n\
for f in BACKUP_FILES:\n\
if f == "openclaw.json":\n\
continue # 已单独处理\n\
path = os.path.join(OPENCLAW_DIR, f)\n\
if os.path.exists(path):\n\
tar.add(path, arcname=f)\n\
print(f"Backed up: {f}")\n\
if os.path.exists(data_name):\n\
api.upload_file(\n\
path_or_fileobj=data_name,\n\
path_in_repo=data_name,\n\
repo_id=repo_id,\n\
repo_type="dataset",\n\
token=token\n\
)\n\
print(f"Data backup {data_name} uploaded.")\n\
\n\
print(f"Backup {day} completed.")\n\
except Exception as e:\n\
print(f"Backup Error: {e}")\n\
\n\
if __name__ == "__main__":\n\
if len(sys.argv) > 1 and sys.argv[1] == "backup": backup()\n\
else: restore()' > /usr/local/bin/sync.py
#RK|# 8. 启动控制逻辑
RUN cat > /usr/local/bin/start-openclaw << 'SCRIPT'
#!/bin/bash
set -e
mkdir -p /root/.openclaw/sessions
# 阶段 1: 清理可能存在的重复插件(使用全局 npm 安装的版本)
rm -rf /root/.openclaw/extensions/feishu
# 阶段 2: 执行启动前恢复(会清理旧的 feishu 配置)
python3 /usr/local/bin/sync.py restore
# 处理地址逻辑
CLEAN_BASE=$(echo "$OPENAI_API_BASE" | sed "s|/chat/completions||g" | sed "s|/v1/|/v1|g" | sed "s|/v1$|/v1|g")
# 阶段 3: 仅当配置文件不存在时才生成默认配置
if [ ! -f /root/.openclaw/openclaw.json ]; then
echo "No existing openclaw.json found, generating default configuration..."
cat > /root/.openclaw/openclaw.json <<EOF
{
"models": {
"providers": {
"$MODEL_PROVIDER": {
"baseUrl": "$OPENAI_API_BASE",
"apiKey": "$OPENAI_API_KEY",
"api": "openai-completions",
"models": [{
"id": "$MODEL",
"name": "$MODEL_NAME",
"contextWindow": $MODEL_CONTEXT
}]
}
}
},
"agents": {
"defaults": {
"model": {
"primary": "$MODEL_PROVIDER/$MODEL"
}
}
},
"gateway": {
"mode": "local",
"bind": "lan",
"port": $PORT,
"trustedProxies": ["0.0.0.0/0", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
"auth": {
"mode": "token",
"token": "$OPENCLAW_GATEWAY_TOKEN"
},
"remote": {
"token": "$OPENCLAW_GATEWAY_TOKEN"
},
"controlUi": {
"allowInsecureAuth": true,
"dangerouslyAllowHostHeaderOriginFallback": true,
"dangerouslyDisableDeviceAuth": true
}
}
}
EOF
else
echo "Existing openclaw.json found, skipping generation."
fi
# 阶段 4: doctor 自动检测并配置 feishu 插件
openclaw doctor --fix
# 阶段 5: 配置 feishu 频道(doctor 之后)
if [ -n "$FEISHU_APP_ID" ] && [ -n "$FEISHU_APP_SECRET" ]; then
openclaw config set channels.feishu.enabled true
openclaw config set channels.feishu.accounts.main.appId "$FEISHU_APP_ID"
openclaw config set channels.feishu.accounts.main.appSecret "$FEISHU_APP_SECRET"
fi
# 增量备份循环 (每 3小时)
(while true; do sleep 10800; python3 /usr/local/bin/sync.py backup; done) &
exec openclaw gateway run --port $PORT
SCRIPT
RUN chmod +x /usr/local/bin/start-openclaw
EXPOSE 7860
CMD ["/usr/local/bin/start-openclaw"]
|