–auto-publish

用户让我重新写一篇关于部署自动化的文章。上一版本的问题是模板化表达太多,比如”相信我”、”安全性方面”、”让我带大家一起”这类话太多,还有空洞形容词如”丝滑”、”丝般顺滑”、”完美”等。

现在需要重新写,要点:
1. 自然的技术博客风格
2. 重点在问题、解决、效果
3. 产品信息自然融入
4. 禁止硬推广和模板化
5. 1500字以上

让我重新构思这篇文章:

开头:直接切入场景,不用”今天来分享”这种套路
问题:真实的发布痛点
解决:选型过程、最终方案
效果:具体的数据和改变
反思:客观呈现优缺点

要注意:
– 去掉”作为一个有十年工作经验的程序员”
– 去掉”让我带大家一起”
– 去掉”相信我”
– 去掉”安全性方面,请放心”这类话
– 去掉空洞形容词:丝滑、丝般顺滑、完美、极致等
– 保留技术细节但不要过度(IP地址等可以简化)
– 客观呈现,提到工具时不强行吹捧
– 结尾可以反思不足和后续计划

让我重新写:

# 一次发布事故后,我花了两周时间把部署流程彻底改了

## 事故

去年双十一前的那次故障,我现在还记忆犹新。

晚上十点多,正在家里准备休息,突然钉钉疯狂响——线上报警,核心接口大量504超时。赶紧爬起来开电脑,一顿排查,最后发现是发布时漏了一个数据库迁移脚本,导致用户下单接口直接报错。

故障持续了四十多分钟,影响了大概几千名用户。事后复盘,问题很清晰:我们每次发布都是纯手动操作——登录服务器、拖代码、执行SQL、逐台重启。那天晚上那位同事急着上线新功能,漏了一个步骤。

## 我们的情况

当时我负责的后端服务跑在5台ECS上,4核8G的配置,CentOS 7.9系统,Java Spring Boot应用部署在Tomcat里。每次发布,我们先在本地打war包,然后通过SSH连到每台服务器,停止Tomcat、替换war包、启动、跑数据库脚本。一套下来最少二三十分钟,大版本更新还要提前定停机窗口,通知所有人。

手动发布有两个要命的问题:一是环节多容易出错,二是出问题回滚极其困难。我记得有一次发版后发现严重bug,回滚花了将近一个小时,那一个小时线上一直报错,用户体验可想而知。

这次事故成了导火索。我下决心要把发布流程自动化。

## 尝试

一开始自然想到业界成熟的方案。Jenkins是最主流的,考察了一圈,功能确实强大,但我们团队就三个后端开发,Jenkins的复杂度有点杀鸡用牛刀的意思,光配置流水线就得花不少时间,而且界面实在不算现代。

GitLab CI也不错,集成在GitLab里很方便。但我们代码托管在Gitee,集成起来别扭。GitLab Runner还要单独部署,维护成本不低。

后来试了阿里云云效。服务器本身就托管在阿里云,云效的Agent可以直接通过控制台安装,配置起来确实省事。但免费版限制太多——流水线并发数、构建时长,每个月都得精打细算,有几次差点因为额度问题耽误发布。

兜兜转转,我决定自己写一套轻量级的自动发布脚本。核心思路很朴素:利用SSH批量执行命令,配合Shell脚本完成部署。这个方案完全可控,不受任何平台限制,出了问题排查也方便。

## 实现

前后花了大约两周时间,写了一套基于SSH的批量部署脚本。

核心逻辑是:本地打包后,通过Python脚本利用paramiko库连接所有服务器,分发war包,然后远程执行部署脚本。脚本会先停止Tomcat,备份当前版本,部署新版本,启动Tomcat,最后检查健康状态。任何一步失败都会自动回滚。

“`python
import paramiko
import subprocess
import os
from datetime import datetime

# 服务器配置,IP做了脱敏
servers = [
{‘host’: ‘172.16.1.101’, ‘port’: 22, ‘user’: ‘deploy’},
{‘host’: ‘172.16.1.102’, ‘port’: 22, ‘user’: ‘deploy’},
{‘host’: ‘172.16.1.103’, ‘port’: 22, ‘user’: ‘deploy’},
{‘host’: ‘172.16.1.104’, ‘port’: 22, ‘user’: ‘deploy’},
{‘host’: ‘172.16.1.105’, ‘port’: 22, ‘user’: ‘deploy’},
]

def deploy_to_server(server_info):
“””部署到单台服务器”””
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 使用密钥连接
pkey = paramiko.RSAKey.from_private_key_file(‘/path/to/private_key’)
ssh.connect(
hostname=server_info[‘host’],
port=server_info[‘port’],
username=server_info[‘user’],
pkey=pkey
)

# 执行部署命令
commands = [
‘systemctl stop tomcat’,
‘cd /app/tomcat/webapps && rm -rf ROOT ROOT.war’,
‘cp /tmp/deploy/ROOT.war .’,
‘systemctl start tomcat’,
]

for cmd in commands:
stdin, stdout, stderr = ssh.exec_command(cmd)
exit_code = stdout.channel.recv_exit_status()
if exit_code != 0:
error = stderr.read().decode()
raise Exception(f”命令执行失败: {cmd}, 错误: {error}”)

# 检查应用是否启动成功
time.sleep(15)
stdin, stdout, stderr = ssh.exec_command(‘curl -s http://localhost:8080/health’)
if ‘ok’ not in stdout.read().decode():
raise Exception(“健康检查失败”)

ssh.close()
“`

实际使用时,部署流程变成了一条命令:

“`bash
python deploy.py –version v1.2.3 –env production
“`

脚本会自动完成:本地编译 → 上传包到所有服务器 → 逐台部署 → 健康检查 → 记录版本。整个过程完全透明,出了任何问题都能看到具体在哪一步失败。

## 效果

上线后的效果很明显:

– 发布时间从20多分钟缩短到3分钟左右,主要是等待健康检查的时间
– 再也没有漏过任何部署步骤,所有操作都在脚本控制下
– 回滚变得非常简单,一条命令就能回滚到上一个版本
– 每次发布都有完整的日志记录,谁在什么时候发布了哪个版本,一目了然

最关键的是,那之后再也没有出现过因为发布导致的生产故障。当然,这不完全是自动化部署的功劳——流程规范了,人的失误自然就少了。

## 不足

自己写的脚本有几个问题:

– 缺乏可视化管理界面,团队其他同事用起来不太直观
– 没有内置的审批流程,有时候紧急发布容易绕开检查
– 告警机制比较简陋,只做了基本的邮件通知

这些是后续可以考虑改进的方向。

## 总结

这次改造并不复杂,前后两周的业余时间就完成了。但对团队的实际帮助很大——不仅是效率提升,更是把发布这件事从”人为操作”变成了”可控流程”。

如果你也面临类似的手动发布困扰,可以先从小脚本开始,未必要一步到位搭建完整的CI/CD体系。解决实际问题最重要。

–auto-publish

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Scroll to top