From 8ebd2d54f6798647d9f07276a3fc956f23d7626b Mon Sep 17 00:00:00 2001 From: fscarmen <62703343+fscarmen@users.noreply.github.com> Date: Sun, 16 Nov 2025 01:38:44 +0000 Subject: [PATCH] =?UTF-8?q?Switched=20the=20image=20from=20supervisord=20t?= =?UTF-8?q?o=20s6-overlay=20because=20it=20provides=20a=20much=20smaller?= =?UTF-8?q?=20memory=20footprint.=20s6-overlay=20vs=20supervisord=20?= =?UTF-8?q?=E2=80=94=20Memory=20Footprint=20Comparison?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit s6-overlay: Uses only 1–2 MB of RAM. Its service processes typically consume around 200 KB RSS each. Extremely lightweight, written in C, minimal overhead. supervisord: Consumes roughly 10–15 MB of RAM in real-world usage. Implemented in Python, so it naturally has a higher baseline memory footprint (≈8–10× s6-overlay). --- Dockerfile | 29 ++++++++++++++-- docker_init.sh | 94 ++++++++++++++++++++++++++------------------------ sing-box.sh | 1 + 3 files changed, 76 insertions(+), 48 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8589c02..114e4eb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,24 @@ -# 使用 Alpine 镜像 +# 构建阶段 +FROM alpine:latest AS builder +ARG TARGETARCH +ENV ARCH=$TARGETARCH + +# 安装构建依赖 +RUN set -ex &&\ + apk add --no-cache wget xz + +# 下载并解压 s6-overlay +RUN set -ex &&\ + case "$ARCH" in \ + amd64) S6_ARCH=x86_64 ;; \ + arm64) S6_ARCH=aarch64 ;; \ + armv7) S6_ARCH=armhf ;; \ + *) S6_ARCH=x86_64 ;; \ + esac &&\ + wget -qO- https://github.com/just-containers/s6-overlay/releases/latest/download/s6-overlay-noarch.tar.xz | tar -C / -Jx &&\ + wget -qO- https://github.com/just-containers/s6-overlay/releases/latest/download/s6-overlay-$S6_ARCH.tar.xz | tar -C / -Jx + +# 运行阶段 FROM alpine:latest ARG TARGETARCH ENV ARCH=$TARGETARCH @@ -6,12 +26,15 @@ ENV ARCH=$TARGETARCH # 设置工作目录 WORKDIR /sing-box +# 从构建阶段复制 s6-overlay 文件 +COPY --from=builder / / + # 复制初始化脚本 COPY docker_init.sh /sing-box/init.sh -# 安装依赖并生成证书 +# 安装运行时依赖并生成证书 RUN set -ex &&\ - apk add --no-cache supervisor wget nginx bash openssl &&\ + apk add --no-cache wget nginx bash openssl &&\ mkdir -p /sing-box/cert /sing-box/conf /sing-box/subscribe /sing-box/logs &&\ chmod +x /sing-box/init.sh &&\ rm -rf /var/cache/apk/* diff --git a/docker_init.sh b/docker_init.sh index 82ed4ae..c9f1b30 100644 --- a/docker_init.sh +++ b/docker_init.sh @@ -34,7 +34,7 @@ check_latest_sing-box() { # 获取最终版本号 local VERSION=$(wget --no-check-certificate --tries=2 --timeout=3 -qO- https://api.github.com/repos/SagerNet/sing-box/releases | awk -F '["v]' -v var="tag_name.*$FORCE_VERSION" '$0 ~ var {print $5; exit}') - VERSION=${VERSION:-'v1.12.0-beta.15'} + VERSION=${VERSION:-'1.13.0-alpha.27'} echo "$VERSION" } @@ -730,45 +730,34 @@ EOF ARGO_RUNS="cloudflared tunnel --edge-ip-version auto --no-autoupdate --no-tls-verify --metrics 0.0.0.0:$METRICS_PORT --url https://localhost:$START_PORT" fi - # 生成 supervisord 配置文件 - mkdir -p /etc/supervisor.d - SUPERVISORD_CONF="[supervisord] -user=root -nodaemon=true -logfile=/dev/null -pidfile=/run/supervisord.pid + # 生成 s6-overlay 服务脚本(替代 supervisord) + mkdir -p /etc/services.d/nginx /etc/services.d/sing-box + cat > /etc/services.d/nginx/run << 'EOF' +#!/usr/bin/env sh +exec /usr/sbin/nginx -g 'daemon off;' +EOF + cat > /etc/services.d/sing-box/run << EOF +#!/usr/bin/env sh +exec ${WORK_DIR}/sing-box run -C ${WORK_DIR}/conf/ +EOF + chmod +x /etc/services.d/nginx/run /etc/services.d/sing-box/run -[program:nginx] -command=/usr/sbin/nginx -g 'daemon off;' -autostart=true -autorestart=true -stderr_logfile=/dev/null -stdout_logfile=/dev/null + # 命名隧道模式时,argo 作为 s6 服务;Quick Tunnel 模式维持原先的前置后台拉起逻辑 + if [ -z "$METRICS_PORT" ]; then + mkdir -p /etc/services.d/argo + cat > /etc/services.d/argo/run << EOF +#!/usr/bin/env sh +exec ${WORK_DIR}/${ARGO_RUNS} 2>/dev/null +EOF + chmod +x /etc/services.d/argo/run -[program:sing-box] -command=${WORK_DIR}/sing-box run -C ${WORK_DIR}/conf/ -autostart=true -autorestart=true -stderr_logfile=/dev/null -stdout_logfile=/dev/null" - -[ -z "$METRICS_PORT" ] && SUPERVISORD_CONF+=" - -[program:argo] -command=${WORK_DIR}/$ARGO_RUNS -autostart=true -autorestart=true -stderr_logfile=/dev/null -stdout_logfile=/dev/null -" - - echo "$SUPERVISORD_CONF" > /etc/supervisor.d/daemon.ini - - # 如使用临时隧道,先运行 cloudflared 以获取临时隧道域名 - if [ -n "$METRICS_PORT" ]; then - ${WORK_DIR}/$ARGO_RUNS >/dev/null 2>&1 & - sleep 15 - local ARGO_DOMAIN=$(wget -qO- http://localhost:$METRICS_PORT/quicktunnel | awk -F '"' '{print $4}') + else + # 如使用临时隧道,先运行 cloudflared 以获取临时隧道域名 + nohup ${WORK_DIR}/${ARGO_RUNS} >/dev/null 2>&1 & + until grep -q 'trycloudflare\.com' <<< "$ARGO_DOMAIN" ; do + sleep 1 + local ARGO_DOMAIN=$(wget -qO- http://localhost:$METRICS_PORT/quicktunnel | awk -F '"' '{print $4}') + done fi # 获取自签证书指纹。argo 回源的是由 Google Trust Services(谷歌信任服务)作为中间 CA(CN=WE1)签发,受信任的证书(非自签名) @@ -1304,11 +1293,26 @@ update_sing-box() { local LOCAL=$(${WORK_DIR}/sing-box version | awk '/version/{print $NF}') if [ -n "$ONLINE" ]; then if [[ "$ONLINE" != "$LOCAL" ]]; then - wget https://github.com/SagerNet/sing-box/releases/download/v$ONLINE/sing-box-$ONLINE-linux-$SING_BOX_ARCH.tar.gz -O- | tar xz -C ${WORK_DIR} sing-box-$ONLINE-linux-$SING_BOX_ARCH/sing-box && - mv ${WORK_DIR}/sing-box-$ONLINE-linux-$SING_BOX_ARCH/sing-box ${WORK_DIR}/sing-box && - rm -rf ${WORK_DIR}/sing-box-$ONLINE-linux-$SING_BOX_ARCH && - supervisorctl restart sing-box - info " Sing-box v${ONLINE} 更新成功!" + cp -f ${WORK_DIR}/sing-box /tmp/sing-box.bak + wget https://github.com/SagerNet/sing-box/releases/download/v$ONLINE/sing-box-$ONLINE-linux-$SING_BOX_ARCH.tar.gz -O- | tar xz -C /tmp sing-box-$ONLINE-linux-$SING_BOX_ARCH/sing-box + mv /tmp/sing-box-$ONLINE-linux-$SING_BOX_ARCH/sing-box ${WORK_DIR}/sing-box + local SING_BOX_PID_OLD=$(ps aux | grep '[s]ing-box run' | awk '{print $1}') + kill -9 ${SING_BOX_PID_OLD} + sleep 1 + local SING_BOX_PID_NEW=$(ps aux | grep '[s]ing-box run' | awk '{print $1}') + until [[ "${SING_BOX_PID_NEW}" =~ ^[0-9]+$ ]]; do + (( i++ )) + [ "$i" -gt 5 ] && break + sleep 1 + local SING_BOX_PID_NEW=$(ps aux | grep '[s]ing-box run' | awk '{print $1}') + done + if [[ "${SING_BOX_PID_NEW}" =~ ^[0-9]+$ ]]; then + info " Sing-box v${ONLINE} 更新成功!" + else + cp -f /tmp/sing-box.bak ${WORK_DIR}/sing-box + warning " Sing-box v${ONLINE} 运行不成功,使用回旧版本 v${LOCAL} 更新成功!" + fi + rm -rf ${WORK_DIR}/sing-box-$ONLINE-linux-$SING_BOX_ARCH /tmp/sing-box.bak else info " Sing-box v${ONLINE} 已是最新版本!" fi @@ -1331,6 +1335,6 @@ case "$ACTION" in ;; * ) install - # 运行 supervisor 进程守护,并让其成为真正的 PID 1 - exec supervisord -c /etc/supervisord.conf + # 用 s6-overlay 作为 PID 1 承载守护 + exec /init esac \ No newline at end of file diff --git a/sing-box.sh b/sing-box.sh index f9ace70..a84d791 100644 --- a/sing-box.sh +++ b/sing-box.sh @@ -2308,6 +2308,7 @@ install_sing-box() { sing-box_variables [ -n "$PORT_NGINX" ] && check_nginx [ ! -d ${WORK_DIR}/logs ] && mkdir -p ${WORK_DIR}/logs + [ ! -d ${TEMP_DIR} ] && mkdir -p $TEMP_DIR ssl_certificate hint "\n $(text 2) " && wait sing-box_json