惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
罗磊的独立博客
宝玉的分享
宝玉的分享
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
V2EX
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tailwind CSS Blog
博客园_首页
量子位
月光博客
月光博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 司徒正美
人人都是产品经理
人人都是产品经理
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
S
SegmentFault 最新的问题
雷峰网
雷峰网
小众软件
小众软件
博客园 - 聂微东
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
Jina AI
Jina AI
Hugging Face - Blog
Hugging Face - Blog

Under the Sun with Paddy

WordPress 平稳换主题:从本地验证到稳态的四阶段 – Under the Sun with Paddy 网站防护架构图:四层防线与它们的静默失败 – Under the Sun with Paddy WordPress 主题更换后的服务器运维与排错实录 – Under the Sun with Paddy 自”妍” WordPress 主题性能实测 – Paddy ‘s Blog 为什么做了一个报纸风格的 WordPress Markdown 主题 - Under the Sun with Paddy 88×31 – Under the Sun with Paddy 傻孩子我怕你啊,禁止被资本主义异化 – Under the Sun with Paddy [Agent 考古] Ciatto 2025 解读:LLM 住进 BDI 解释器,计划生成与 believes achieved 退化 – Under the Sun with Paddy [Agent 考古] 意图编辑权:从 BDI 到 LLM Agent,谁有权决定机器何时停下来 – Under the Sun with Paddy [Agent 考古] 25,000 次任务实测:多 Agent 协作协议质量排序与治理悖论 – Under the Sun with Paddy [Agent 考古] TouringMachines 与 INTERRaP:混合架构如何调和 Agent 的反应与慎思 – Under the Sun with Paddy [Agent 考古] KQML、FIPA、JADE 协议史:Agent 互操作失败全记录与 MCP/A2A 预测 – Under the Sun with Paddy [Agent 考古] 多 Agent 冲突仲裁三方案:均衡约定、PERSUADER 劝说与行为抽象 – Under the Sun with Paddy [Agent 考古] STEAM 与 ARCHON:联合意图理论如何落地真实工业多智能体系统 – Under the Sun with Paddy [Agent 考古] 合同网协议详解:Smith 1980 任务招标五步流程与囚徒困境的 Python 复现 – Under the Sun with Paddy [Agent 考古] 什么是 Agent?Wooldridge & Jennings 弱概念四性质与强概念定义详解 – Under the Sun with Paddy [Agent 考古] 意图即带承诺的选择:1990 年,”不放弃”第一次有了形式定义 – Under the Sun with Paddy [Agent 考古] 从进程栈到 Z 规范:BDI 意图架构的四代演化 – Under the Sun with Paddy 打开即沦陷:keyv 蠕虫与 AI 编码助手时代的供应链暗战 – Under the Sun with Paddy [Agent 考古] 意图即承诺,智能体即社会——自主性的第一个可计算答案 (阶段三导航) – Under the Sun with Paddy 雷池WAF + fail2ban + AbuseIPDB 完整实战:从日志解析到自动封禁上报 – Under the Sun with Paddy 嚼别人嚼过的口香糖,AI 时代人的价值 – Under the Sun with Paddy 比尔·盖茨长文警告原文翻译:《动荡的 AI 时代已经到来,我们现在的选择至关重要》 – Under the Sun with Paddy [Agent 考古] 自知、自觉、自止——终章定论:Agent 不需要意识,但必须知道自己的边界、理由和终点 – Under the Sun with Paddy [Agent 考古] 多头注意力共享目标、参数即隐式模型、CoT 是概率采样——LLM 被三条“反叛伏线”夹击 – Under the Sun with Paddy [Agent 考古] 别再给机器人建“世界模型”了!Brooks用代码证明:世界本身就是最好的模型 – Under the Sun with Paddy [Agent 考古] 别再给机器人装“大脑”了!1986 年的“三无”架构证明:越不思考,活得越久。 – Under the Sun with Paddy [Agent 考古] 你的大脑里住着一个小人吗——Minsky 说:不,住着成百上千个”笨蛋” – Under the Sun with Paddy [Agent 考古] 600 条规则,一个反向推理引擎——专家系统的顶峰是怎么建成又怎么暴露边界的 – Under the Sun with Paddy [Agent 考古] 秘书要求他离开房间——一个程序为什么让人想跟它说心里话 – Under the Sun with Paddy
雷池 WAF 一键升级失败解决:手动离线升级注意事项 – Under t...
Paddy · 2026-08-24 · via Under the Sun with Paddy

背景

雷池(SafeLine)近期版本更新到了 9.4.0(2026-08-17 发布),更新和优化了大量的检测逻辑,所以打算更新雷池。

但按照官方教程执行一键升级失败,提示”未安装 Docker Compose,是否自动安装”,迷迷糊糊选择”是”之后就显示更新失败,并且服务中断了半小时。

最终我选择了离线镜像升级方案。

本文记录了升级过程中遇到的几个典型错误及完整的排查解决过程,希望能为遇到类似问题的朋友提供参考。

升级环境

项目配置
操作系统Ubuntu 22.04 / 24.04
Docker已安装
Docker Compose独立二进制 docker-compose(非 docker compose 插件)
雷池安装目录/data/safeline

为何在线升级会失败?

版本要求明确,但文档指引存在歧义。 雷池官方手动安装文档没有明确指明 Docker Compose 的版本要求,示例命令清一色是 docker compose up -d(无横线,v2 插件形式)。但我就要用 docker-compose(带横线,v1 独立二进制)—— 你又没说不可以 QaQ。

docker compose 与 docker-compose 是两种不同的工具:

  • docker compose:随新版 Docker 一起安装的插件,官方主推的现代版本。
  • docker-compose:需要单独下载的独立二进制文件,但我爱用咋地 QaQ。

脚本检测机制存在 Bug(缺陷好吧只是缺陷)。 雷池的在线升级脚本(manager.py)在检测 Compose 版本时,用了一条只匹配 v2 输出格式的正则,导致 v1 用户被误判为”未安装 Compose”,进而触发”是否自动安装 Docker”的询问。迷迷糊糊选了”是”之后,脚本执行 get-docker.sh 并在末尾 systemctl restart docker 硬重启 Docker daemon,所有运行中的容器瞬间被杀 —— 服务中断。

根因深挖:manager.py 的正则缺陷(选读)

bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/manager.sh)" 中真正的升级逻辑代码 manager.py 的 precheck_docker_compose() 函数用以下正则提取 Compose 版本号:

t = re.findall(r'^Docker Compose version v?(\d+)\.', version_output)

这条正则只匹配 v2 的输出格式 Docker Compose version v2.x.x,完全不匹配 v1 的输出格式 docker-compose version 1.29.2(小写、带横线、无 v 前缀)。

脚本逻辑是:如果正则匹配结果为空,就判定”Compose 未安装”,然后弹出”是否自动安装 Docker”的询问。用户一旦选”是”,install_docker() 就会执行 get-docker.sh,并在末尾通过 start_docker() 调用:

systemctl enable docker && systemctl daemon-reload && systemctl restart docker

systemctl restart docker 会硬重启 Docker daemon,所有运行中的容器被强制停止。如果 get-docker.sh 安装过程中出现网络超时或依赖冲突,Docker 服务可能起不来,所有容器全部下线 —— 这就是服务中断的真正原因。

简而言之:不是你的 docker-compose 有问题,是脚本的正则不认你的 docker-compose。

问题已经在文章发布前 提交雷池官方

官方离线升级步骤

根据雷池官方文档,离线升级需要执行以下操作:

# 1. 进入安装目录
cd /data/safeline

# 2. 备份旧编排文件,下载新版
mv compose.yaml compose.yaml.old
wget "https://waf-ce.chaitin.cn/release/latest/compose.yaml" --no-check-certificate -O compose.yaml

# 3. 更新/补全 .env 环境变量
sed -i "s/IMAGE_TAG=.*/IMAGE_TAG=latest/g" ".env"
grep "SAFELINE_DIR" ".env" > /dev/null || echo "SAFELINE_DIR=$(pwd)" >> ".env"
grep "IMAGE_TAG" ".env" > /dev/null || echo "IMAGE_TAG=latest" >> ".env"
grep "MGT_PORT" ".env" > /dev/null || echo "MGT_PORT=9443" >> ".env"
grep "POSTGRES_PASSWORD" ".env" > /dev/null || echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" >> ".env"
grep "SUBNET_PREFIX" ".env" > /dev/null || echo "SUBNET_PREFIX=172.22.222" >> ".env"
grep "IMAGE_PREFIX" ".env" >/dev/null || echo "IMAGE_PREFIX=chaitin" >>".env"
grep "ARCH_SUFFIX" ".env" >/dev/null || echo "ARCH_SUFFIX=" >>".env"
grep "RELEASE" ".env" >/dev/null || echo "RELEASE=" >>".env"
grep "MGT_PROXY" ".env" >/dev/null || echo "MGT_PROXY=0" >>".env"

# 4. 加载离线镜像
docker load -i image.tar.gz

# 5. 停止旧容器并启动新容器
docker compose down --remove-orphans
docker compose up -d

遇到的错误及解决方案

错误现象根因解决方案
docker compose 命令不存在系统装的是 v1 独立二进制,v2 插件未安装统一改用 docker-compose(带横线)
网络删除失败(active endpoints)其他容器(如 WordPress)连接到 safeline-ce 网络忽略或手动断开
invalid reference formatcompose.yaml 中 postgres 镜像引用语法错误手动修正 image 字段
镜像前缀不匹配.env 中 IMAGE_PREFIX 指向华为云,本地标签是 chaitin改为 IMAGE_PREFIX=chaitin

错误一:docker compose 命令不存在

现象: 执行 docker compose down --remove-orphans 时报错:

docker: 'compose' is not a docker command.
See 'docker --help'

定位过程: 检查环境中的 Docker Compose 版本:

which docker-compose
# 输出:/usr/bin/docker-compose

docker-compose --version
# 输出:docker-compose version 1.29.2

原因: 系统中安装的是独立二进制 docker-compose(带横线,v1),而非新版 docker compose 插件(无横线、子命令形式,v2)。v1 的 1.29.2 实际是支持 --remove-orphans 这个 flag 的,真正不存在的不是参数,而是 docker compose(无横线)这个子命令本身。

解决方案: 所有命令统一使用 docker-compose(带横线):

docker-compose down --remove-orphans
docker-compose up -d

错误二:docker-compose down 网络删除失败

现象:

Removing network safeline-ce
ERROR: error while removing network: network safeline-ce has active endpoints (name:"wordpress" id:"a5710bbfdfb6")

原因: 服务器上存在其他容器(如 WordPress)连接到雷池创建的 safeline-ce 网络,导致网络无法删除。

影响: 此错误不影响升级。网络仍然存在,新启动的容器会直接复用该网络。

解决方案: 忽略该错误,继续执行 docker-compose up -d。若希望彻底清理,可先断开其他容器的网络连接:

docker network disconnect safeline-ce wordpress
docker network rm safeline-ce

错误三:invalid reference format(核心问题)

现象: 执行 docker-compose up -d 反复报错:

ERROR: invalid reference format

定位过程: 使用 docker-compose config 命令检查 Compose 解析后的实际配置:

docker-compose config

在输出中发现 postgres 服务的 image 字段异常:

postgres:
  image: $${IMAGE_PREFIX/safeline-postgres:15.18}

这是一个语法错误 —— 多了一个 $,且变量引用格式不正确(} 位置错位,把斜杠后面的内容也包进了变量名里)。其他服务的 image 字段均正常(如 chaitin/safeline-chaos:latest),唯独 postgres 服务异常。

原因: 新下载的 compose.yaml 中 postgres 的 image 行存在拼写错误,将正确的变量格式 ${IMAGE_PREFIX}/safeline-postgres:${IMAGE_TAG} 误写为 $${IMAGE_PREFIX/safeline-postgres:15.18}。在 Compose 中,$$ 是对 $ 的转义,会让变量替换整段失效,最终拼出来的镜像名既不是合法引用,也不是本地存在的标签,于是触发 invalid reference format

解决方案: 手动编辑 compose.yaml,修正 postgres 服务的镜像引用。

vim compose.yaml

找到 postgres: 服务部分,将:

    image: $${IMAGE_PREFIX/safeline-postgres:15.18}

改为(使用本地已加载的镜像标签):

    image: chaitin/safeline-postgres:15.2

保存退出后,再次验证:

docker-compose config | grep -A 2 postgres

确认输出中 image: chaitin/safeline-postgres:15.2

错误四:IMAGE_PREFIX 与本地镜像标签不匹配

现象: 修改 compose.yaml 后,docker-compose up -d 仍然报 invalid reference format

定位过程: 查看本地已加载的镜像标签:

docker images | grep safeline

发现镜像同时带有两套标签:

chaitin/safeline-*:latest
swr.cn-east-3.myhuaweicloud.com/chaitin-safeline/safeline-*:latest

而 .env 中初始配置为:

IMAGE_PREFIX=swr.cn-east-3.myhuaweicloud.com/chaitin-safeline

原因: compose.yaml 中其他服务使用 ${IMAGE_PREFIX}/safeline-*:${IMAGE_TAG} 引用镜像。当 IMAGE_PREFIX 指向华为云地址时,Compose 尝试使用华为云标签的镜像。虽然本地也有这些标签,但若标签不完全匹配,可能导致解析异常。

解决方案: 将 IMAGE_PREFIX 改为 chaitin,使用本地已有的简洁标签:

sed -i 's/^IMAGE_PREFIX=.*/IMAGE_PREFIX=chaitin/' .env

最终成功启动

完成以上修复后:

docker-compose up -d

输出:

Creating safeline-pg       ... done
Creating safeline-chaos    ... done
Creating safeline-detector ... done
Creating safeline-fvm      ... done
Creating safeline-tengine  ... done
Creating safeline-mgt      ... done
Creating safeline-luigi    ... done

查看容器状态:

docker-compose ps
# 所有服务均为 Up 状态

登录管理页面,版本已更新,配置、规则、日志全部保留。

经验总结

  1. 升级前务必备份/制作服务器镜像: 任何涉及底层组件(如 Docker)更新或使用官方脚本的操作都存在破坏性风险。在执行升级前,务必在云服务商控制台为服务器制作系统盘快照或镜像。这样即使升级彻底失败导致环境崩溃(例如本次脚本硬重启 Docker 导致服务中断),也能通过回滚镜像在几分钟内恢复业务,避免长时间的手忙脚乱。
  2. 确认 Docker Compose 命令格式: 使用 which docker-compose 确认系统中是 docker-compose(v1)还是 docker compose(v2),避免命令混淆。两者语法不同,不要混用。
  3. 善用 docker-compose config 预检查: 这是定位 Compose 配置问题的利器,能提前发现变量解析错误和语法问题。
  4. 检查 compose.yaml 中的语法错误: 官方提供的编排文件也可能存在拼写问题,尤其是 image 字段的变量引用格式。对 ${VAR} 与 $$(转义)的用法要格外敏感。
  5. 确保 .env 中的镜像前缀与本地标签一致: IMAGE_PREFIX 应匹配 docker load 加载的镜像标签前缀。离线升级时,建议统一用 chaitin 简短前缀。
  6. 网络残留错误不影响升级: docker-compose down 网络删除失败时,只要容器已停止,新容器会复用现有网络,不影响启动。
  7. 手动编辑比 sed 更可靠: 在复杂替换场景下,直接使用 vim 修改文件可以避免转义错误。
  8. 别盲目相信安装脚本的”自动安装”选项: 安装脚本若提示要自动安装 Docker,先停下来 —— 它很可能会重启 Docker daemon,把你正在运行的服务全杀掉。先在宿主机上手动把 Docker 和 Compose 准备好,再运行业务安装器。

参考资料