ted1990 commited on
Commit
e485e52
·
verified ·
1 Parent(s): 0618e14

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +112 -74
Dockerfile CHANGED
@@ -1,84 +1,115 @@
1
  # 核心镜像:Node 22 slim 保证了环境的现代性与轻量化
2
  FROM node:22-slim
3
 
4
- # 1. 安装系统依赖
5
- # 包含:git (拉取依赖), openssh-client (解决构建报错), build-essential/g++/make (编译原生模块), python3 (运行同步脚本)
 
 
 
6
  RUN apt-get update && apt-get install -y --no-install-recommends \
7
-     git openssh-client build-essential python3 python3-pip \
8
-     g++ make ca-certificates \
9
-     && rm -rf /var/lib/apt/lists/*
 
 
 
 
 
 
10
 
11
- # 2. 安装 Hugging Face 命令行工具
12
- RUN pip3 install --no-cache-dir huggingface_hub --break-system-packages
13
 
14
- # 3. 构建环境优化
15
- # 修复 Git 证书问题并将所有 SSH 协议重定向为 HTTPS
16
- RUN update-ca-certificates && \
17
-     git config --global http.sslVerify false && \
18
-     git config --global url."https://github.com/".insteadOf ssh://git@github.com/
19
 
20
  # 4. 全局安装 OpenClaw
21
  RUN npm install -g openclaw@latest --unsafe-perm
22
 
23
- # 5. 设置环境变量
 
 
 
 
 
24
  ENV PORT=7860 \
25
-     OPENCLAW_GATEWAY_MODE=local \
26
-     HOME=/root
27
 
28
- # 6. 核心同步引擎 (sync.py)
29
- # 针对 OpenClaw 新版 MEMORY.md 机制进行了全路径覆盖
30
  RUN echo 'import os, sys, tarfile\n\
31
  from huggingface_hub import HfApi, hf_hub_download\n\
32
  from datetime import datetime, timedelta\n\
 
33
  api = HfApi()\n\
34
  repo_id = os.getenv("HF_DATASET")\n\
35
  token = os.getenv("HF_TOKEN")\n\
 
36
  \n\
37
  def restore():\n\
38
-     try:\n\
39
-         print(f"--- [SYNC] 启动恢复流程, 目标仓库: {repo_id} ---")\n\
40
-         if not repo_id or not token: \n\
41
-             print("--- [SYNC] 跳过恢复: 未配置 HF_DATASET 或 HF_TOKEN ---")\n\
42
-             return False\n\
43
-         files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token)\n\
44
-         now = datetime.now()\n\
45
-         for i in range(5):\n\
46
-             day = (now - timedelta(days=i)).strftime("%Y-%m-%d")\n\
47
-             name = f"backup_{day}.tar.gz"\n\
48
-             if name in files:\n\
49
-                 print(f"--- [SYNC] 发现备份文件: {name}, 正在下载... ---")\n\
50
-                 path = hf_hub_download(repo_id=repo_id, filename=name, repo_type="dataset", token=token)\n\
51
-                 with tarfile.open(path, "r:gz") as tar: tar.extractall(path="/root/.openclaw/")\n\
52
-                 print(f"--- [SYNC] 恢复成功! 数据已覆盖至 /root/.openclaw/ ---")\n\
53
-                 return True\n\
54
-         print("--- [SYNC] 未找到最近 5 天的备份包 ---")\n\
55
-     except Exception as e: print(f"--- [SYNC] 恢复异常: {e} ---")\n\
 
 
56
  \n\
57
  def backup():\n\
58
-     try:\n\
59
-         day = datetime.now().strftime("%Y-%m-%d")\n\
60
-         name = f"backup_{day}.tar.gz"\n\
61
-         print(f"--- [SYNC] 正在执行全量备份: {name} ---")\n\
62
-         with tarfile.open(name, "w:gz") as tar:\n\
63
-             # 路径说明:sessions(网关历史), workspace(记忆文件), agents(配置), memory(旧版目录)\n\
64
-             for target in ["sessions", "workspace", "agents", "memory", "openclaw.json"]:\n\
65
-                 full_path = f"/root/.openclaw/{target}"\n\
66
-                 if os.path.exists(full_path):\n\
67
-                     tar.add(full_path, arcname=target)\n\
68
-         api.upload_file(path_or_fileobj=name, path_in_repo=name, repo_id=repo_id, repo_type="dataset", token=token)\n\
69
-         print(f"--- [SYNC] 备份上传成功! ---")\n\
70
-     except Exception as e: print(f"--- [SYNC] 备份失败: {e} ---")\n\
 
 
 
 
 
 
 
71
  \n\
72
  if __name__ == "__main__":\n\
73
-     if len(sys.argv) > 1 and sys.argv[1] == "backup": backup()\n\
74
-     else: restore()' > /usr/local/bin/sync.py
 
 
 
75
 
76
- # 7. 容器入口脚本 (start-openclaw)
77
- # 负责恢复数据 -> 生成配置 -> 启动网关 -> 定时备份
78
  RUN echo "#!/bin/bash\n\
79
  set -e\n\
80
- mkdir -p /root/.openclaw/sessions\n\
81
- mkdir -p /root/.openclaw/workspace\n\
 
 
 
 
 
 
 
 
82
  \n\
83
  # 启动前执行数据恢复\n\
84
  python3 /usr/local/bin/sync.py restore\n\
@@ -86,30 +117,30 @@ python3 /usr/local/bin/sync.py restore\n\
86
  # 清理 API Base 地址\n\
87
  CLEAN_BASE=\$(echo \"\$OPENAI_API_BASE\" | sed \"s|/chat/completions||g\" | sed \"s|/v1/|/v1|g\" | sed \"s|/v1\$|/v1|g\")\n\
88
  \n\
89
- # 生成 openclaw.json 配置文件\n\
90
- cat > /root/.openclaw/openclaw.json <<EOF\n\
91
  {\n\
92
-   \"models\": {\n\
93
-     \"providers\": {\n\
94
-       \"siliconflow\": {\n\
95
-         \"baseUrl\": \"\$CLEAN_BASE\",\n\
96
-         \"apiKey\": \"\$OPENAI_API_KEY\",\n\
97
-         \"api\": \"openai-completions\",\n\
98
-         \"models\": [{ \"id\": \"\$MODEL\", \"name\": \"DeepSeek\", \"contextWindow\": 128000 }]\n\
99
-       }\n\
100
-     }\n\
101
-   },\n\
102
-   \"agents\": { \"defaults\": { \"model\": { \"primary\": \"siliconflow/\$MODEL\" } } },\n\
103
-   \"gateway\": {\n\
104
-     \"mode\": \"local\", \"bind\": \"lan\", \"port\": \$PORT,\n\
105
-     \"trustedProxies\": [\"0.0.0.0/0\", \"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"],\n\
106
-     \"auth\": { \"mode\": \"token\", \"token\": \"\$OPENCLAW_GATEWAY_PASSWORD\" },\n\
107
-     \"controlUi\": { \"allowInsecureAuth\": true }\n\
108
-   }\n\
109
  }\n\
110
  EOF\n\
111
  \n\
112
- # 启动定时备份进程 (每 3 小时执行一次,增强安全性)\n\
113
  (while true; do sleep 10800; python3 /usr/local/bin/sync.py backup; done) &\n\
114
  \n\
115
  # 启动 OpenClaw 网关\n\
@@ -117,5 +148,12 @@ openclaw doctor --fix\n\
117
  exec openclaw gateway run --port \$PORT\n\
118
  " > /usr/local/bin/start-openclaw && chmod +x /usr/local/bin/start-openclaw
119
 
 
 
 
 
120
  EXPOSE 7860
 
 
 
121
  CMD ["/usr/local/bin/start-openclaw"]
 
1
  # 核心镜像:Node 22 slim 保证了环境的现代性与轻量化
2
  FROM node:22-slim
3
 
4
+ # 安装 tini 作为 init 系统,正确处理信号和僵尸进程
5
+ RUN apt-get update && apt-get install -y --no-install-recommends tini \
6
+ && rm -rf /var/lib/apt/lists/*
7
+
8
+ # 1. 安装系统依赖(分行列出,便于维护)
9
  RUN apt-get update && apt-get install -y --no-install-recommends \
10
+ git \
11
+ openssh-client \
12
+ build-essential \
13
+ python3 \
14
+ python3-pip \
15
+ g++ \
16
+ make \
17
+ ca-certificates \
18
+ && rm -rf /var/lib/apt/lists/*
19
 
20
+ # 2. 安装 Hugging Face 命令行工具(不使用 --break-system-packages,兼容 Debian)
21
+ RUN pip3 install --no-cache-dir huggingface_hub
22
 
23
+ # 3. 构建环境优化(仅更新证书,不修改 Git 不安全配置)
24
+ RUN update-ca-certificates
 
 
 
25
 
26
  # 4. 全局安装 OpenClaw
27
  RUN npm install -g openclaw@latest --unsafe-perm
28
 
29
+ # 5. 创建普通用户(降低容器运行权限)
30
+ RUN useradd -m -u 1000 -s /bin/bash openclaw && \
31
+ mkdir -p /home/openclaw/.openclaw && \
32
+ chown -R openclaw:openclaw /home/openclaw/.openclaw
33
+
34
+ # 6. 设置环境变量(适配新用户路径)
35
  ENV PORT=7860 \
36
+ OPENCLAW_GATEWAY_MODE=local \
37
+ HOME=/home/openclaw
38
 
39
+ # 7. 核心同步引擎 (sync.py) - 优化备份逻辑:避免空打包
 
40
  RUN echo 'import os, sys, tarfile\n\
41
  from huggingface_hub import HfApi, hf_hub_download\n\
42
  from datetime import datetime, timedelta\n\
43
+ \n\
44
  api = HfApi()\n\
45
  repo_id = os.getenv("HF_DATASET")\n\
46
  token = os.getenv("HF_TOKEN")\n\
47
+ DATA_DIR = os.path.expanduser("~/.openclaw")\n\
48
  \n\
49
  def restore():\n\
50
+ try:\n\
51
+ print(f"--- [SYNC] 启动恢复流程, 目标仓库: {repo_id} ---")\n\
52
+ if not repo_id or not token: \n\
53
+ print("--- [SYNC] 跳过恢复: 未配置 HF_DATASET 或 HF_TOKEN ---")\n\
54
+ return False\n\
55
+ files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token)\n\
56
+ now = datetime.now()\n\
57
+ for i in range(5):\n\
58
+ day = (now - timedelta(days=i)).strftime("%Y-%m-%d")\n\
59
+ name = f"backup_{day}.tar.gz"\n\
60
+ if name in files:\n\
61
+ print(f"--- [SYNC] 发现备份文件: {name}, 正在下载... ---")\n\
62
+ path = hf_hub_download(repo_id=repo_id, filename=name, repo_type="dataset", token=token)\n\
63
+ with tarfile.open(path, "r:gz") as tar:\n\
64
+ tar.extractall(path=DATA_DIR)\n\
65
+ print(f"--- [SYNC] 恢复成功! 数据已覆盖至 {DATA_DIR} ---")\n\
66
+ return True\n\
67
+ print("--- [SYNC] 未找到最近 5 天的备份包 ---")\n\
68
+ except Exception as e:\n\
69
+ print(f"--- [SYNC] 恢复异常: {e} ---")\n\
70
  \n\
71
  def backup():\n\
72
+ try:\n\
73
+ # 检查是否存在需要备份的路径\n\
74
+ targets = ["sessions", "workspace", "agents", "memory", "openclaw.json"]\n\
75
+ existing = [t for t in targets if os.path.exists(os.path.join(DATA_DIR, t))]\n\
76
+ if not existing:\n\
77
+ print("--- [SYNC] 没有需要备份的数据,跳过备份 ---")\n\
78
+ return\n\
79
+ \n\
80
+ day = datetime.now().strftime("%Y-%m-%d")\n\
81
+ name = f"backup_{day}.tar.gz"\n\
82
+ print(f"--- [SYNC] 正在执行全量备份: {name} ---")\n\
83
+ with tarfile.open(name, "w:gz") as tar:\n\
84
+ for target in existing:\n\
85
+ full_path = os.path.join(DATA_DIR, target)\n\
86
+ tar.add(full_path, arcname=target)\n\
87
+ api.upload_file(path_or_fileobj=name, path_in_repo=name, repo_id=repo_id, repo_type="dataset", token=token)\n\
88
+ print(f"--- [SYNC] 备份上传成功! ---")\n\
89
+ os.remove(name) # 清理临时文件\n\
90
+ except Exception as e:\n\
91
+ print(f"--- [SYNC] 备份失败: {e} ---")\n\
92
  \n\
93
  if __name__ == "__main__":\n\
94
+ if len(sys.argv) > 1 and sys.argv[1] == "backup":\n\
95
+ backup()\n\
96
+ else:\n\
97
+ restore()\n\
98
+ ' > /usr/local/bin/sync.py
99
 
100
+ # 8. 容器入口脚本 (start-openclaw) - 增强健壮性
 
101
  RUN echo "#!/bin/bash\n\
102
  set -e\n\
103
+ \n\
104
+ # 强制检查必要环境变量\n\
105
+ : \"\${OPENAI_API_BASE:?环境变量 OPENAI_API_BASE 未设置}\"\n\
106
+ : \"\${OPENAI_API_KEY:?环境变量 OPENAI_API_KEY 未设置}\"\n\
107
+ : \"\${MODEL:?环境变量 MODEL 未设置}\"\n\
108
+ : \"\${OPENCLAW_GATEWAY_PASSWORD:?环境变量 OPENCLAW_GATEWAY_PASSWORD 未设置}\"\n\
109
+ \n\
110
+ # 确保数据目录存在且可写\n\
111
+ DATA_DIR=\"\$HOME/.openclaw\"\n\
112
+ mkdir -p \"\$DATA_DIR\"/{sessions,workspace}\n\
113
  \n\
114
  # 启动前执行数据恢复\n\
115
  python3 /usr/local/bin/sync.py restore\n\
 
117
  # 清理 API Base 地址\n\
118
  CLEAN_BASE=\$(echo \"\$OPENAI_API_BASE\" | sed \"s|/chat/completions||g\" | sed \"s|/v1/|/v1|g\" | sed \"s|/v1\$|/v1|g\")\n\
119
  \n\
120
+ # 生成 openclaw.json 配置文件(使用当前用户权限)\n\
121
+ cat > \"\$DATA_DIR/openclaw.json\" <<EOF\n\
122
  {\n\
123
+ \"models\": {\n\
124
+ \"providers\": {\n\
125
+ \"siliconflow\": {\n\
126
+ \"baseUrl\": \"\$CLEAN_BASE\",\n\
127
+ \"apiKey\": \"\$OPENAI_API_KEY\",\n\
128
+ \"api\": \"openai-completions\",\n\
129
+ \"models\": [{ \"id\": \"\$MODEL\", \"name\": \"DeepSeek\", \"contextWindow\": 128000 }]\n\
130
+ }\n\
131
+ }\n\
132
+ },\n\
133
+ \"agents\": { \"defaults\": { \"model\": { \"primary\": \"siliconflow/\$MODEL\" } } },\n\
134
+ \"gateway\": {\n\
135
+ \"mode\": \"local\", \"bind\": \"lan\", \"port\": \$PORT,\n\
136
+ \"trustedProxies\": [\"10.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\"], # 移除 0.0.0.0/0 增强安全性\n\
137
+ \"auth\": { \"mode\": \"token\", \"token\": \"\$OPENCLAW_GATEWAY_PASSWORD\" },\n\
138
+ \"controlUi\": { \"allowInsecureAuth\": true }\n\
139
+ }\n\
140
  }\n\
141
  EOF\n\
142
  \n\
143
+ # 启动定时备份进程每 3 小时执行一次,增强安全性\n\
144
  (while true; do sleep 10800; python3 /usr/local/bin/sync.py backup; done) &\n\
145
  \n\
146
  # 启动 OpenClaw 网关\n\
 
148
  exec openclaw gateway run --port \$PORT\n\
149
  " > /usr/local/bin/start-openclaw && chmod +x /usr/local/bin/start-openclaw
150
 
151
+ # 9. 切换到普通用户
152
+ USER openclaw
153
+
154
+ # 10. 暴露端口
155
  EXPOSE 7860
156
+
157
+ # 11. 使用 tini 作为 init 系统,启动入口脚本
158
+ ENTRYPOINT ["/usr/bin/tini", "--"]
159
  CMD ["/usr/local/bin/start-openclaw"]