ECS上线Go服务两次返工记录

举报
yd_272744321 发表于 2026/11/02 11:07:36 2026/11/02
【摘要】 我在华为云ECS上线一个Go转码服务时,连续踩了两个坑:Docker写满系统盘、ELB健康检查一直异常。这里是我当天的操作记录,包含具体报错、命令、配置、耗时和额外费用,也写了我现在固定执行的发布清单。

故障背景

9月18日我把内部图片转码服务从旧VM迁到华为云北京四区,目标还是先把单机跑稳,再接共享型ELB。机器规格没变,s7n.xlarge.2,4 vCPU 8 GiB,系统盘40GiB高IO,数据盘100GiB普通IO,系统是 Huawei Cloud EulerOS 2.0 SP13,内核 5.10.0-60.18.0.50.r1082。我在飞书里记的按需价是:ECS 0.86元/小时,5M带宽EIP 0.31元/小时,公网流量0.8元/GB,这些数字后面都拿来对账了。

我9:06开机,9:14装完 Docker CE 24.0.7 和 Compose v2.24.5,9:22把 repo 里 commit 7e3c9a1 对应的 compose.yaml 拷上去,命令是 docker compose up -d --remove-orphans。原计划10:00前切流,实际12:18才恢复,窗口被拉到3小时12分。那份compose里我把 restart: always 写死了,排障时容器每次闪退都会马上拉起,日志增长速度接近每分钟120MB,我上线前真没估到这件事会反咬一口。

我那天对着群消息硬扛了快半小时。

第一个坑:Docker先启动把系统盘写满

10:18开始接口502,Nginx容器还活着,Go容器每20秒重启一次。docker ps -a 里它在 Restarting (1) 8 seconds ago 和 Exited (1) 3 seconds ago 来回跳,docker inspect transcode-api --format '{{.RestartCount}}' 连续看了三次,从17涨到24。docker logs --tail=80 transcode-api 除了应用自己的panic,还夹着存储层报错:

failed to register layer: write /var/lib/docker/overlay2/3f1f.../diff/usr/lib/libicudata.so: no space left on device
Error response from daemon: failed to create shim task: OCI runtime create failed
open /var/lib/docker/tmp/GetImageBlob312779148: no space left on device

我第一反应是镜像坏了,连续跑了两次 docker compose pull --ignore-pull-failures,还把镜像tag从 v1.9.3 改成 v1.9.2。一点用没有。10:27我做了个失败操作,直接 docker system prune -af --volumes,只腾出1.1GiB;我还补了一次 journalctl --vacuum-size=300M,5分钟后又被刷满。现在回头看,这两步都只是在延迟报错,没有碰到根因。

/dev/vda1   40G   39G  512M  99% /
/dev/vdb   100G  84M  100G   1% /data

du -sh /var/lib/docker /var/log/journal
31G  /var/lib/docker
6.4G /var/log/journal

定位清楚后我没再赌运气,按顺序拆开做。先 systemctl stop docker,避免overlay2继续写。然后迁移目录我踩了一次坑:第一遍用了 rsync -aP,重启后两层镜像起不来,报 failed to verify layer sha256:... diffID mismatch。第二遍我改成 rsync -aHAX --numeric-ids /var/lib/docker/ /data/docker/,这才把硬链接、xattr和uid都带过去。接着写 /etc/docker/daemon.json,把 data-root 固定到数据盘,同时限日志大小,防止再次把系统盘挤爆。

cat > /etc/docker/daemon.json <<'EOF'
{
  "data-root": "/data/docker",
  "log-driver": "json-file",
  "log-opts": {"max-size":"100m","max-file":"3"}
}
EOF
mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/size.conf <<'EOF'
[Journal]
SystemMaxUse=500M
RuntimeMaxUse=200M
EOF
systemctl restart systemd-journald
systemctl start docker

这次返工业务停了36分钟,系统盘占用从98%掉到43%,docker info | grep 'Docker Root Dir' 看到是 /data/docker,同一批6个镜像重拉耗时7分40秒,Go容器状态终于稳定成 Up 12 minutes,重启计数停在26不再涨。

我当时差点直接取消发布窗口。

第二个坑:安全组漏了健康检查端口

11:07我把服务挂到ELB,监听80转发后端8080,健康检查路径 /healthz,间隔5秒,超时2秒,健康阈值2,不健康阈值3。控制台一直是后端不健康。容器里 curl -s -o /dev/null -w '%{http_code} %{time_total}\n' localhost:8080/healthz 连续跑20次都返回 200,耗时在0.003到0.008秒。我一度怀疑是Gin中间件把UA拦掉,临时把白名单加了 ELB-HealthChecker,还把日志级别改成debug,最后确认这是白改。

[root@ecs]# tcpdump -i eth0 port 8080 -nn -c 10
listening on eth0, link-type EN10MB
0 packets captured
0 packets received by filter
0 packets dropped by kernel

抓包没有任何探活包,方向就清楚了。我去翻安全组,入方向当时只放了22、80、443,8080和18080都没开。我还犯了个低级错误,图省事写过 0.0.0.0/0:80,以为ELB回源能通,实际内网ELB回源网段是 100.125.0.0/16,规则根本不匹配。补完规则后我又等了差不多2分钟,ELB状态才从 Abnormal 变成 Normal。

协议 TCP 端口 8080  源 100.125.0.0/16
协议 TCP 端口 18080 源 100.125.0.0/16

hcloud vpc security-group-rule create --direction ingress --protocol tcp --port-range-min 8080 --port-range-max 8080 --remote-ip-prefix 100.125.0.0/16 --security-group-id sg-xxxx
hcloud vpc security-group-rule create --direction ingress --protocol tcp --port-range-min 18080 --port-range-max 18080 --remote-ip-prefix 100.125.0.0/16 --security-group-id sg-xxxx

这一段排查花了47分钟,群里业务方问了我三次要不要回滚,我每次都只能回“还在查网络层”。那天因为反复重建容器和压测,多跑了18.6GB公网流量,按0.8元/GB算是14.88元,月底账单能对上。

我现在的固定发布步骤

我现在不边配边试,照清单过一遍,平均12分钟做完,慢点也不超过18分钟,主要耗在等ELB健康状态刷新。清单里每一项都是那天返工换来的。

  • 开机5分钟内先看 lsblk、df -h、cat /etc/fstab,确认 /data 已挂载,再启动Docker;如果看到 /data 没挂,我直接停手,不往下走。
  • 发布前跑 docker system df,镜像层超过20GiB就清一次,至少留15GiB给当天回滚镜像;我把阈值写在变更单里,避免现场靠记忆。
  • 核对 /etc/docker/daemon.json 的 data-root=/data/docker 和日志限额 100m*3,再看 du -sh /var/log/journal,超过500M就清理,不等它逼近系统盘红线。
  • 安全组按“来源网段+端口”逐条过,我固定检查 100.125.0.0/16、8080、18080,规则加完后用 hcloud ... list 反查一次,确认不是控制台缓存假成功。
  • ELB建好先在ECS抓包5秒,看得到探活包再切;切流后压1000次 /healthz,命令是 seq 1 1000 | xargs -n1 -P20 -I{} curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/healthz | grep -c 500,目标是5xx为0。

还没解决的部分

我现在还是会手工点控制台改安全组,这一步很容易抖手。下周我准备把规则模板化,变量就三个:SG_ID、BACKEND_PORTS=8080,18080、SOURCE_CIDR=100.125.0.0/16,脚本执行完再拉一次规则列表做diff。

发布前自检脚本目前只有磁盘和端口检查,ELB探活链路还没自动验证,我在试API轮询健康状态,目标是把“容器健康但ELB不健康”这种情况在切流前就拦住。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。