DNS 已经切走了,服务还没起来

11 阅读6分钟

原计划里,切 DNS 是最后一道闸门,排在第 9 阶段。

1 实测 → 2 规划 → 3 打包 → 4 配置 → 5 上传 → 6 启动
      → 7 建站 → 8 证书 → 9 切 DNS → 10 联调 → 11 加固
                              ↑ 不可逆,放最后

这么安排的主要原因是:域名一旦指向新机,旧机就断了流量,中途出问题只能靠改回 A 记录来回滚。

我当时的计划,是把第 1 阶段的实测做完,再一步步往上推。

但我还卡在第 1 阶段做实测的时候,三个域名的 A 记录已经全部改到新机上了。

我用公共 DNS 交叉验证确认过。

nslookup h5.example.com    223.5.5.5   →  <新机IP>
nslookup api.example.com   223.5.5.5   →  <新机IP>
nslookup admin.example.com 223.5.5.5   →  <新机IP>

新机上是这个样子:目录没建、镜像没传、容器一个都没起来。

也就是说,服务此刻正处于中断状态,这个很危险。

很多人遇到这种情况会直接慌,然后开始乱序操作。

先花 30 秒把它拆开看,会发现它其实是同一件事的两面。

坏消息是,域名已经指向新机,可新机上服务不可达,三个入口全废。

好消息是,证书签发不再受 DNS 阻拦了。第 8 阶段本来要绕路,现在可以直接做。

好消息这一条值得展开一下。

Let's Encrypt 的 HTTP-01 验证要求域名解析到本机。

解析不到,验证请求就到不了你的服务器,证书签不下来。

原方案里这一步被卡在「DNS 还没切」,所以我准备了三条绕路:搬运旧证书、改 DNS-01 加 TXT 记录、先切再签。

现在 DNS 已经切了,这个阻碍自动消失。原本要绕的路,不用绕了。

重排之后,顺序变成这样。

第 1 到第 8 阶段照旧往下做,第 9 阶段的切 DNS 从待办变成了已完成,第 10 和第 11 阶段继续往后排。

DNS 从最后一道闸,变成了一个已完成项。

这个拆解的价值在于,它把「完蛋了」拆成了「有一件事变好了,有一件事变急了」。

慌了会乱,拆开了就能排优先级。

然后是第一个陷阱:我一开始看到的那个 502 是假的。

确认中断之后,我做的第一件事是从本地探测。

curl -s -o /dev/null -w "%{http_code}\n" http://h5.example.com/
# 502

502。看起来坐实了「服务挂了」。

但这个证据不能用。理由就在响应里:错误信息带了 os error 10061。

10061 是 Windows 的 socket 错误码,WSAECONNREFUSED,意思是连接被拒绝。而目标服务器跑的是 Linux。

一个 Windows 的错误码,怎么会出现在访问 Linux 服务器的响应里?

答案是,这个请求根本没出我的机器。它被本地的代理或者沙箱截走了,直接返回了一个错误。

这条 502 描述的是我本机的状态,不是服务器的状态。

这里有一条通用规则,我记到现在。

你看到的错误,未必来自你以为的那一层。

判断一条证据能不能用,先问一句:这个错误码可能由哪个环节产生?

os error 10061 这种带操作系统特征的信息,是识别本地污染最快的线索。

同理,看到 ECONNREFUSED (os error 111),那才是 Linux 侧的拒绝。

排除掉被污染的证据之后,真正能定性的是在服务器本机跑这两组命令。

# ① 面板里到底有没有我的站点
find /opt/1panel -name "*.conf" 2>/dev/null | xargs grep -l "example.com" 2>/dev/null | head
ls /opt/1panel/www/sites/

# ② 本机对三个域名的真实响应(不走公网、不经过任何代理)
for h in h5 api admin; do
  printf "%-8s " "$h"
  curl -s -o /dev/null -w "127.0.0.1 → %{http_code}  " --max-time 5 \
       -H "Host: $h.example.com" http://127.0.0.1/
  curl -sk -o /dev/null -w "https → %{http_code}\n" --max-time 5 \
       --resolve $h.example.com:443:127.0.0.1 https://$h.example.com/
done

第二条命令里的两个技巧值得单独说。

第一个技巧是在 curl 里带上 -H "Host: 域名"。

请求打到 http://127.0.0.1/ ,等于伪造一个 Host 头。这等价于域名已经解析到本机,绕开 DNS。

另一个是 --resolve 域名:443:127.0.0.1,只对这一条请求把域名指到本机。它不动全局 DNS,用来在 HTTPS 层做验证。

这两条都不经过公网,所以不可能被本地代理污染。

结果怎么读,一共四种情况。

本机请求返回 000,说明本地 Web 层根本没监听,也就是容器没起。

返回 404,说明 Web 层活着,但站点还没建。

返回 200 或者 301,同时 https 那一侧返回 000,说明 HTTP 通了,HTTPS 还没配。

两边都是 200,服务就已经恢复了。

确认中断属实之后,剩下的问题是:从哪一步开始做?

这时候最容易犯的错,是从头按顺序再做一遍。

可中断恢复的正确排序依据是依赖关系,不是阶段编号。

服务器建目录 → 本地打包(源码+产物+镜像)→ 上传 → 配置定稿 → 启动容器
                                                              ↑
                                                        恢复的临界点

判断标准就一句话:哪一步做完,服务就恢复了?

在这个架构里,答案是容器启动。

对外提供服务的三个容器一旦起来,本机的 127.0.0.1 就通了。站点建好之后,公网也就通了。

于是优先级排成这样。

立刻要做的,是建目录、上传、配置定稿、启动容器。这几件不能延后,它们是恢复的临界点。

紧接着是建站点、签证书,也不能延后,否则公网仍然不可达。

可以慢一步的,是第三方平台联调,也就是登录和支付。它不影响「能不能访问」。

排在最末的,才是安全加固、备份、日志轮转。

「第三方联调可以慢」这一条,是这次重排里最重要的决定。

它通常需要外部平台配合,耗时不可控。要是把它和「恢复服务」混在一起做,中断时间会被它拖长。

还有一条纪律。

在中断状态下,禁止做任何顺手优化。

那 30 分钟里唯一的 KPI 就是恢复。任何顺手改的配置,都会变成新的变量。

这段我固化成了清单,以后直接照着走。

先交叉验证 DNS 的真实指向,两个公共 DNS 返回一致才算数。

接着怀疑本地探测的结果,错误码带 OS 特征的,本机验证重来一遍。

然后在服务器本机定性,把没监听、没建站、没证书这三种情况分开。

再按依赖排出临界点,明确哪一步做完服务就回来。

非阻塞项一律延后,包括外部联调、加固、备份。

恢复之后立刻补基线,同机其他站点的状态码要和中断前一致。

至于那个 502 到底被本机哪个环节截走的,我到现在也没精确查到,只能确认它没出机器。