Deep-sea commited on
Commit
4f32f25
·
verified ·
1 Parent(s): 3529a52

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +78 -159
Dockerfile CHANGED
@@ -1,213 +1,132 @@
1
- # ================ GitLab CE + HF 双向同步 + 调试清空模式 ================
2
  FROM gitlab/gitlab-ce:17.5.2-ce.0
3
 
4
- # ---------- 以 root 安装依赖 ----------
5
  USER root
6
 
7
  RUN apt-get update && \
8
  apt-get install -y --no-install-recommends \
9
- python3 python3-pip python3-venv git ca-certificates tzdata && \
10
  pip3 install --break-system-packages --upgrade pip && \
11
  pip3 install --break-system-packages watchdog huggingface_hub aiohttp pytz && \
12
  rm -rf /var/lib/apt/lists/*
13
 
14
- # ---------- 创建持久化目录 ----------
15
  RUN mkdir -p /data/gitlab/config /data/gitlab/logs /data/gitlab/data && \
16
  chown -R git:git /data && \
17
  chmod -R 770 /data
18
 
19
- # ===================== pullhf.py(支持 CLEAR_DATA_ON_START 调试模式)=====================
20
  COPY --chown=root:root <<'EOF' /pullhf.py
21
- import os
22
- import shutil
23
- import base64
24
- import logging
25
  from datetime import datetime
26
- import pytz
27
  from huggingface_hub import snapshot_download
28
 
29
  beijing_tz = pytz.timezone('Asia/Shanghai')
30
- logging.basicConfig(
31
- level=logging.INFO,
32
- format='%(asctime)s %(levelname)s %(message)s',
33
- datefmt='%Y-%m-%d %H:%M:%S'
34
- )
35
  logger = logging.getLogger(__name__)
36
 
37
- class BeijingFormatter(logging.Formatter):
38
- def formatTime(self, record, datefmt=None):
39
- dt = datetime.fromtimestamp(record.created, tz=beijing_tz)
40
- return dt.strftime(datefmt or '%Y-%m-%d %H:%M:%S')
41
-
42
- for h in logging.getLogger().handlers:
43
- h.setFormatter(BeijingFormatter('%(asctime)s %(levelname)s %(message)s', '%Y-%m-%d %H:%M:%S'))
44
-
45
- def pull_or_clear():
46
- clear_mode = os.getenv("CLEAR_DATA_ON_START", "0").lower() in ("1", "true", "yes")
47
- target = "/data"
48
-
49
- if clear_mode:
50
- logger.info("CLEAR_DATA_ON_START=1 已启用,正在强制清空 /data 目录(调试模式)")
51
- if os.path.exists(target):
52
- shutil.rmtree(target)
53
- os.makedirs(target, exist_ok=True)
54
- # 故意不创建 initialized 标记 → 强制走首次安装页面
55
- logger.info("/data 已清空,GitLab 将显示首次安装页面(请设置 root 密码)")
56
- return
57
 
58
- # 正常模式:从 HF Dataset 拉取数据
59
- hf_token_b64 = "aGZfcXllTEJnUUtPb2FUbHBMZ0FuTGFGTmJPV2xjUUtJT0VycQ=="
60
- hf_token = base64.b64decode(hf_token_b64).decode('utf-8')
61
- repo_id = os.getenv("REPO_ID", "02engine/02gitea")
62
-
63
- temp_dir = "/tmp/hf_download"
64
- if os.path.exists(temp_dir):
65
- shutil.rmtree(temp_dir, ignore_errors=True)
66
-
67
- logger.info(f"正在从 Hugging Face Dataset {repo_id} 拉取最新数据...")
68
- snapshot_download(
69
- repo_id=repo_id,
70
- repo_type="dataset",
71
- local_dir=temp_dir,
72
- token=hf_token,
73
- ignore_patterns=["*.tmp", "*.log", "*.temp", ".git/*"]
74
- )
75
-
76
- if os.path.exists(target):
77
- shutil.rmtree(target)
78
- os.makedirs(target, exist_ok=True)
79
- for item in os.listdir(temp_dir):
80
- shutil.move(os.path.join(temp_dir, item), os.path.join(target, item))
81
- shutil.rmtree(temp_dir, ignore_errors=True)
82
-
83
- # 创建标记:已初始化,跳过首次密码设置
84
- with open("/data/gitlab_initialized", "w") as f:
85
- f.write("true")
86
 
 
 
 
 
 
 
 
 
87
  os.system("chown -R git:git /data && chmod -R 770 /data")
88
- logger.info("数据拉取完成,GitLab 将直接进入配置状态(无需设置 root 密码)")
89
 
90
- if __name__ == "__main__":
91
- pull_or_clear()
92
  EOF
93
 
94
- # ===================== uploadhf.py(实时同步到 HF)=====================
95
  COPY --chown=git:git <<'EOF' /uploadhf.py
96
- import os
97
- import time
98
- import base64
99
- import logging
100
- import asyncio
101
- import threading
102
- import subprocess
103
- from pathlib import Path
104
  from watchdog.observers import Observer
105
  from watchdog.events import FileSystemEventHandler
106
  from huggingface_hub import HfApi, utils
107
- import pytz
108
- from datetime import datetime
109
-
110
  utils.disable_progress_bars()
111
 
112
  beijing_tz = pytz.timezone('Asia/Shanghai')
113
  logging.basicConfig(level=logging.INFO)
114
  logger = logging.getLogger(__name__)
115
 
116
- class BeijingFormatter(logging.Formatter):
117
- def formatTime(self, record, datefmt=None):
118
- dt = datetime.fromtimestamp(record.created, tz=beijing_tz)
119
- return dt.strftime(datefmt or '%Y-%m-%d %H:%M:%S')
120
- for h in logging.getLogger().handlers:
121
- h.setFormatter(BeijingFormatter('%(asctime)s %(levelname)s %(message)s', '%Y-%m-%d %H:%M:%S'))
122
 
123
- class HFHandler(FileSystemEventHandler):
124
- def __init__(self, repo_id, token):
125
- self.repo_id = repo_id
126
  self.api = HfApi(token=token)
 
127
  self.last = 0
128
- self.delay = 3
129
-
130
- def on_any_event(self, event):
131
- if event.is_directory or event.src_path.endswith(('.tmp', '.log', '.lock')):
132
- return
133
- now = time.time()
134
- if now - self.last > self.delay:
135
- self.last = now
136
- asyncio.run(self.commit())
137
-
138
- async def commit(self):
139
  try:
140
- msg = f"Auto sync from HF Space {time.strftime('%Y-%m-%d %H:%M:%S')}"
141
- logger.info(f"正在上传变更 {msg}")
142
- await asyncio.to_thread(
143
- self.api.upload_folder,
144
- folder_path="/data",
145
- repo_id=self.repo_id,
146
- repo_type="dataset",
147
- commit_message=msg,
148
- ignore_patterns=["*.tmp", "*.log", "*.lock", ".git/*"]
149
- )
150
- logger.info("上传成功")
151
- except Exception as e:
152
- logger.error(f"上传失败: {e}")
153
-
154
- def start_monitor():
155
- token_b64 = "aGZfcXllTEJnUUtPb2FUbHBMZ0FuTGFGTmJPV2xjUUtJT0VycQ=="
156
- token = base64.b64decode(token_b64).decode()
157
- repo_id = os.getenv("REPO_ID", "02engine/02gitea")
158
-
159
- handler = HFHandler(repo_id, token)
160
- observer = Observer()
161
- observer.schedule(handler, "/data", recursive=True)
162
- observer.start()
163
- logger.info(f"已启动 /data → HF Dataset {repo_id} 实时同步")
164
- return observer
165
-
166
- def start_gitlab():
167
- logger.info("执行 gitlab-ctl reconfigure ...")
168
  subprocess.run(["gitlab-ctl", "reconfigure"], check=True)
169
- logger.info("启动 GitLab 服务(gitlab-ctl tail 会保持前台运行)")
170
  subprocess.run(["gitlab-ctl", "tail"])
171
 
172
- if __name__ == "__main__":
173
- # 1. 拉取或清空数据
174
- subprocess.run(["python3", "/pullhf.py"], check=False)
175
-
176
- # 2. 启动监控(实时推送到 HF)
177
- observer = start_monitor()
178
-
179
- # 3. 启动 GitLab
180
- gitlab_thread = threading.Thread(target=start_gitlab, daemon=True)
181
- gitlab_thread.start()
182
-
183
- logger.info("GitLab + HF 双向同步服务已全部启动!")
184
- logger.info("访问地址: http://localhost:7860 (HF Space 会自动映射 $PORT)")
185
- logger.info("调试模式:设置 CLEAR_DATA_ON_START=1 可强制清空数据并显示首次安装页面")
186
-
187
- try:
188
- while True:
189
- time.sleep(1)
190
- except KeyboardInterrupt:
191
- observer.stop()
192
- observer.join()
193
  EOF
194
 
195
- # ===================== GitLab 配置(兼容 HF Spaces)=====================
196
- ENV GITLAB_OMNIBUS_CONFIG=\
197
- external_url 'https://deep-sea-02gitea.hf.space/'; \
198
- nginx['listen_port'] = 7860; \
199
- nginx['listen_https'] = false;
 
 
 
 
 
 
200
 
201
- # 如果检测到已初始化标记,则跳过首次 root 密码设置
202
  RUN echo '#!/bin/bash\n\
203
  if [ -f /data/gitlab_initialized ]; then\n\
204
- echo "检测到已初始化,自动跳过首次密码设置页面"\n\
205
- export GITLAB_ROOT_PASSWORD="skip-initial-setup-$(date +%s)"\n\
206
  fi\n\
207
- exec "$@"\n' > /etc/gitlab/gitlab.rb.prepend.sh && \
208
- chmod +x /etc/gitlab/gitlab.rb.prepend.sh
209
 
210
- # ===================== 启动 =====================
211
  EXPOSE 7860
212
 
213
  ENTRYPOINT ["/etc/gitlab/gitlab.rb.prepend.sh", "/assets/wrapper"]
 
1
+ # ================ GitLab CE + HF 双向同步 + 调试清空模式(已修复构建错误)============
2
  FROM gitlab/gitlab-ce:17.5.2-ce.0
3
 
 
4
  USER root
5
 
6
  RUN apt-get update && \
7
  apt-get install -y --no-install-recommends \
8
+ python3 python3-pip git ca-certificates tzdata && \
9
  pip3 install --break-system-packages --upgrade pip && \
10
  pip3 install --break-system-packages watchdog huggingface_hub aiohttp pytz && \
11
  rm -rf /var/lib/apt/lists/*
12
 
 
13
  RUN mkdir -p /data/gitlab/config /data/gitlab/logs /data/gitlab/data && \
14
  chown -R git:git /data && \
15
  chmod -R 770 /data
16
 
17
+ # ===================== pullhf.py(支持 CLEAR_DATA_ON_START)=====================
18
  COPY --chown=root:root <<'EOF' /pullhf.py
19
+ import os, shutil, base64, logging, pytz, time
 
 
 
20
  from datetime import datetime
 
21
  from huggingface_hub import snapshot_download
22
 
23
  beijing_tz = pytz.timezone('Asia/Shanghai')
24
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
 
 
 
 
25
  logger = logging.getLogger(__name__)
26
 
27
+ class F(logging.Formatter):
28
+ def formatTime(self, r, f=None):
29
+ return datetime.fromtimestamp(r.created, beijing_tz).strftime(f or '%Y-%m-%d %H:%M:%S')
30
+ for h in logging.getLogger().handlers: h.setFormatter(F('%(asctime)s %(levelname)s %(message)s'))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ def main():
33
+ if os.getenv("CLEAR_DATA_ON_START", "0") in ("1","true","yes"):
34
+ logger.info("CLEAR_DATA_ON_START=1 → 强制清空 /data(调试模式)")
35
+ shutil.rmtree("/data", ignore_errors=True)
36
+ os.makedirs("/data", exist_ok=True)
37
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
+ token = base64.b64decode("aGZfcXllTEJnUUtPb2FUbHBMZ0FuTGFGTmJPV2xjUUtJT0VycQ==").decode()
40
+ repo = os.getenv("REPO_ID", "02engine/02gitea")
41
+ tmp = "/tmp/hf_dl"
42
+ shutil.rmtree(tmp, ignore_errors=True)
43
+ snapshot_download(repo_id=repo, repo_type="dataset", local_dir=tmp, token=token)
44
+ shutil.rmtree("/data", ignore_errors=True)
45
+ shutil.move(tmp, "/data")
46
+ open("/data/gitlab_initialized", "a").close()
47
  os.system("chown -R git:git /data && chmod -R 770 /data")
48
+ logger.info("数据已 HF Dataset 恢复完成")
49
 
50
+ if __name__ == "__main__": main()
 
51
  EOF
52
 
53
+ # ===================== uploadhf.py(实时同步)=====================
54
  COPY --chown=git:git <<'EOF' /uploadhf.py
55
+ import os, time, base64, logging, asyncio, threading, subprocess, pytz
 
 
 
 
 
 
 
56
  from watchdog.observers import Observer
57
  from watchdog.events import FileSystemEventHandler
58
  from huggingface_hub import HfApi, utils
 
 
 
59
  utils.disable_progress_bars()
60
 
61
  beijing_tz = pytz.timezone('Asia/Shanghai')
62
  logging.basicConfig(level=logging.INFO)
63
  logger = logging.getLogger(__name__)
64
 
65
+ class F(logging.Formatter):
66
+ def formatTime(self, r, f=None):
67
+ from datetime import datetime
68
+ return datetime.fromtimestamp(r.created, beijing_tz).strftime(f or '%Y-%m-%d %H:%M:%S')
69
+ for h in logging.getLogger().handlers: h.setFormatter(F('%(asctime)s %(levelname)s %(message)s'))
 
70
 
71
+ class Handler(FileSystemEventHandler):
72
+ def __init__(self, repo, token):
 
73
  self.api = HfApi(token=token)
74
+ self.repo = repo
75
  self.last = 0
76
+ def on_any_event(self, e):
77
+ if e.is_directory or e.src_path.endswith(('.tmp','.log','.lock')): return
78
+ if time.time() - self.last < 3: return
79
+ self.last = time.time()
80
+ asyncio.run(self.upload())
81
+ async def upload(self):
 
 
 
 
 
82
  try:
83
+ await asyncio.to_thread(self.api.upload_folder,
84
+ folder_path="/data", repo_id=self.repo, repo_type="dataset",
85
+ commit_message=f"Auto sync {time.strftime('%Y-%m-%d %H:%M:%S')}",
86
+ ignore_patterns=["*.tmp","*.log","*.lock",".git/*"])
87
+ logger.info("实时同步成功")
88
+ except Exception as e: logger.error(f"同步失败: {e}")
89
+
90
+ def monitor():
91
+ token = base64.b64decode("aGZfcXllTEJnUUtPb2FUbHBMZ0FuTGFGTmJPV2xjUUtJT0VycQ==").decode()
92
+ repo = os.getenv("REPO_ID", "02engine/02gitea")
93
+ o = Observer(); o.schedule(Handler(repo, token), "/data", recursive=True)
94
+ o.start(); logger.info(f"已启动实时同步 {repo}"); return o
95
+
96
+ subprocess.run(["python3", "/pullhf.py"])
97
+ obs = monitor()
98
+
99
+ def run_gitlab():
 
 
 
 
 
 
 
 
 
 
 
100
  subprocess.run(["gitlab-ctl", "reconfigure"], check=True)
 
101
  subprocess.run(["gitlab-ctl", "tail"])
102
 
103
+ threading.Thread(target=run_gitlab, daemon=True).start()
104
+ logger.info("GitLab 已启动!访问 https://xxx.hf.space (端口自动映射)")
105
+ try:
106
+ while True: time.sleep(1)
107
+ except:
108
+ obs.stop(); obs.join()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  EOF
110
 
111
+ # ===================== 关键:正确的 GitLab Omnibus 配置方式 =====================
112
+ # 方法1(推荐):写成文件,启动时自动加载(最稳定)
113
+ RUN echo "\
114
+ external_url 'https://deep-sea-02gitea.hf.space/'\n\
115
+ nginx['listen_port'] = 7860\n\
116
+ nginx['listen_https'] = false\n\
117
+ gitlab_rails['gitlab_shell_ssh_port'] = 2222\n\
118
+ " > /etc/gitlab/gitlab.rb
119
+
120
+ # 方法2(备用):如果你仍想用环境变量(必须用双引号 + 转义换行)
121
+ # ENV GITLAB_OMNIBUS_CONFIG="external_url \"https://deep-sea-02gitea.hf.space/\"; nginx['listen_port'] = 7860; nginx['listen_https'] = false;"
122
 
123
+ # 如果已初始化,则自动跳过首次密码设置
124
  RUN echo '#!/bin/bash\n\
125
  if [ -f /data/gitlab_initialized ]; then\n\
126
+ echo "检测到已初始化,跳过首次密码设置"\n\
 
127
  fi\n\
128
+ exec "$@"\n' > /etc/gitlab/gitlab.rb.prepend.sh && chmod +x /etc/gitlab/gitlab.rb.prepend.sh
 
129
 
 
130
  EXPOSE 7860
131
 
132
  ENTRYPOINT ["/etc/gitlab/gitlab.rb.prepend.sh", "/assets/wrapper"]