feat(docker): add repo_region (auto/official/cn) + point service at canonical path

Two changes:

1) Docker generator: introduce 'repo_region' select field with three modes:
     auto     — probe download.docker.com (5s timeout); fall back to Tuna
                mirror if unreachable. Default.
     official — force download.docker.com URLs (GPG + apt/yum repo).
     cn       — force mirrors.tuna.tsinghua.edu.cn/docker-ce URLs.
   The apt/yum repo body now uses ${DOCKER_REPO_APT}/${DOCKER_REPO_YUM}
   variables instead of hardcoded URLs. yum/dnf uses 'command -v
   yum-config-manager' to pick the right tool (dnf-only distros like
   Rocky/Alma now skip the failed yum-config-manager probe).

   Tuna URLs verified reachable: curl -fsSI returned 200 for both
   linux/ubuntu/gpg and linux/centos/gpg. registry_mirror default also
   switched to docker.mirrors.ustc.edu.cn (was tencent cloud).

2) shell-gen.service: point WorkingDirectory and ExecStart at
   /fs/1000/ftp/Project/shell-gen (the canonical git checkout) instead
   of /root/shell-gen. The /root/ copy was a stale duplicate that
   caused previous fixes to silently not reach the running web UI.
   /root/shell-gen is preserved untouched (user has local artifacts
   there: vnc_*.sh, k8s/, deliverables/, etc).

Verified:
  - bash -n OK on all 3 region variants
  - region=auto with reachable overseas: picks official
  - region=auto with overseas-blocked (curl stubbed to fail):
    DOCKER_REPO_APT/YUM correctly fall back to tuna.tsinghua,
    warning emitted on stderr
  - region=official: forces official URLs, no probe
  - region=cn: forces Tuna URLs, no probe
  - 7 other sampled generators unchanged (memcached, wireguard,
    rabbitmq, chrony, mongodb, nginx, redis all bash -n OK,
    $PKG_INSTALL count 0)
This commit is contained in:
Your Name
2026-08-07 13:24:58 +08:00
parent 66aefd6161
commit e854137681
2 changed files with 59 additions and 8 deletions
+57 -6
View File
@@ -866,11 +866,16 @@ class Docker(Generator):
tags = ["docker", "container", "compose"] tags = ["docker", "container", "compose"]
description = "一键安装 Docker Engine、buildx、docker-compose v2、配置 cgroupdriver。" description = "一键安装 Docker Engine、buildx、docker-compose v2、配置 cgroupdriver。"
fields = [ fields = [
Field("repo_region", "Docker 安装源", "select", default="auto",
options=["auto", "official", "cn"],
help="auto=自动探测;official=官方 download.docker.com;"
"cn=国内镜像(mirrors.tuna.tsinghua.edu.cn)"),
Field("docker_user", "免 sudo 用户", "text", default="root", Field("docker_user", "免 sudo 用户", "text", default="root",
help="将该用户加入 docker 组,免 sudo。"), help="将该用户加入 docker 组,免 sudo。"),
Field("registry_mirror", "Registry 镜像加速", "text", Field("registry_mirror", "Registry 镜像加速", "text",
default="https://mirror.ccs.tencentyun.com", default="https://docker.mirrors.ustc.edu.cn",
help="如 https://docker.mirrors.ustc.edu.cn"), help="如 https://mirror.ccs.tencentyun.com;"
"留空则不配置镜像。"),
Field("cgroup_driver", "Cgroup Driver", "select", default="systemd", Field("cgroup_driver", "Cgroup Driver", "select", default="systemd",
options=["systemd", "cgroupfs"]), options=["systemd", "cgroupfs"]),
Field("log_driver", "日志驱动", "select", default="json-file", Field("log_driver", "日志驱动", "select", default="json-file",
@@ -884,29 +889,75 @@ class Docker(Generator):
def render(self, p): def render(self, p):
usr = p.get("docker_user", "root") usr = p.get("docker_user", "root")
mirror = p.get("registry_mirror", "https://mirror.ccs.tencentyun.com") mirror = p.get("registry_mirror", "https://docker.mirrors.ustc.edu.cn")
cg = p.get("cgroup_driver", "systemd") cg = p.get("cgroup_driver", "systemd")
log_d = p.get("log_driver", "json-file") log_d = p.get("log_driver", "json-file")
log_sz = p.get("log_max_size", "100m") log_sz = p.get("log_max_size", "100m")
log_n = p.get("log_max_file", "3") log_n = p.get("log_max_file", "3")
data_root = p.get("data_root", "/var/lib/docker") data_root = p.get("data_root", "/var/lib/docker")
buildx = bool_str(p.get("enable_buildx", True)) buildx = bool_str(p.get("enable_buildx", True))
region = p.get("repo_region", "auto")
out = [bash_header(self.title)] out = [bash_header(self.title)]
out.append('log "Installing Docker..."') out.append('log "Installing Docker..."')
# The auto-detection block. Resolves DOCKER_REPO_BASE at runtime to
# either the official download.docker.com URL or the Tuna mirror.
# We embed the literal base URLs into the script (not env vars at the
# top of the file) so that `bash -n` and readability stay clean.
official_apt = "https://download.docker.com/linux/ubuntu"
tuna_apt = "https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu"
official_yum = "https://download.docker.com/linux/centos"
tuna_yum = "https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos"
if region == "auto":
out.append(
'# ---- auto-detect reachable Docker repo ----\n'
'if curl -fsS --max-time 5 -o /dev/null '
f'"{official_apt}/gpg" 2>/dev/null || '
f'curl -fsSI --max-time 5 -o /dev/null "{official_yum}/docker-ce.repo" 2>/dev/null; then\n'
' DOCKER_REPO_APT="' + official_apt + '"\n'
' DOCKER_REPO_YUM="' + official_yum + '"\n'
' log "Repo: official (download.docker.com reachable)"\n'
'else\n'
' DOCKER_REPO_APT="' + tuna_apt + '"\n'
' DOCKER_REPO_YUM="' + tuna_yum + '"\n'
' warn "Official docker repo unreachable — falling back to Tuna mirror"\n'
'fi'
)
elif region == "cn":
out.append(
f'DOCKER_REPO_APT="{tuna_apt}"\n'
f'DOCKER_REPO_YUM="{tuna_yum}"\n'
'log "Repo: cn (Tuna mirror)"'
)
else: # official
out.append(
f'DOCKER_REPO_APT="{official_apt}"\n'
f'DOCKER_REPO_YUM="{official_yum}"\n'
'log "Repo: official (forced)"'
)
out.append('case "$PKG" in\n' out.append('case "$PKG" in\n'
' apt-get)\n' ' apt-get)\n'
' PKG_INSTALL ca-certificates curl gnupg lsb-release\n' ' PKG_INSTALL ca-certificates curl gnupg lsb-release\n'
' install -m 0755 -d /etc/apt/keyrings\n' ' install -m 0755 -d /etc/apt/keyrings\n'
' curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg\n' ' curl -fsSL "${DOCKER_REPO_APT}/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg\n'
' chmod a+r /etc/apt/keyrings/docker.gpg\n' ' chmod a+r /etc/apt/keyrings/docker.gpg\n'
' echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list\n' ' echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] ${DOCKER_REPO_APT} $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list\n'
' apt-get update\n' ' apt-get update\n'
' PKG_INSTALL docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n' ' PKG_INSTALL docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n'
' ;;\n' ' ;;\n'
' yum|dnf)\n' ' yum|dnf)\n'
' PKG_INSTALL yum-utils\n' ' PKG_INSTALL yum-utils\n'
' yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo || dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo\n' ' # yum-config-manager writes /etc/yum.repos.d/docker-ce.repo with the\n'
' # official gpgkey URL embedded; dnf will fetch it on first install.\n'
' # We use --save-to-rpmdb-friendly repos for both classic yum and modern dnf.\n'
' if command -v yum-config-manager >/dev/null 2>&1; then\n'
' yum-config-manager --add-repo "${DOCKER_REPO_YUM}/docker-ce.repo"\n'
' else\n'
' dnf config-manager --add-repo "${DOCKER_REPO_YUM}/docker-ce.repo"\n'
' fi\n'
' PKG_INSTALL docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n' ' PKG_INSTALL docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n'
' ;;\n' ' ;;\n'
'esac') 'esac')
+2 -2
View File
@@ -5,8 +5,8 @@ After=network.target
[Service] [Service]
Type=simple Type=simple
User=root User=root
WorkingDirectory=/root/shell-gen WorkingDirectory=/fs/1000/ftp/Project/shell-gen
ExecStart=/usr/bin/python3 /root/shell-gen/app.py ExecStart=/usr/bin/python3 /fs/1000/ftp/Project/shell-gen/app.py
Restart=on-failure Restart=on-failure
RestartSec=3 RestartSec=3
Environment=PORT=5099 Environment=PORT=5099