升级了项目的部署方式,坑死我了!

大家好,我是程序员鱼皮。如标题所言,最近这两天,我对我们公司部分项目的部署方式进行了改造升级。

由于部署方式的调整可能会影响到线上用户的正常访问,所以只能挑在用户少的时间(凌晨)进行调整和测试。

结果没想到踩了不少坑,直到昨天半夜我还在跟其他团队的技术同学一起找 Bug:

这篇文章给大家分享下我们项目部署方式升级的形式、过程以及遇到的一些坑点,说不定以后大家也会用到~

为什么要进行升级?

最开始的时候,我们的项目几乎都是部署到服务器上的,而且很多项目是共用一台服务器,像这样:

为啥要这么做呢?

答案很简单,成本低啊!因为我正好有几台配置很高的服务器,这些服务器如果只部署 1 - 2 个项目,CPU、内存、带宽都用不满,妥妥的浪费资源。

而且现在小公司或个人部署项目可以直接使用宝塔 Linux 面板,非常方便。

所以除非必要,我们尽量不会使用额外产生费用的 CDN、按量计费的容器平台等等。

转眼从我创业到现在已经过去了一年多,为什么我们现在要重新调整项目的部署方式呢?

主要的几个原因:

1)随着业务增长,单体项目未必能够满足诉求,我们可能要将同一个项目部署在多个节点上,实现负载均衡和容错,手动部署就太麻烦了。这就需要能够灵活扩缩容机器节点的能力和流水线部署的能力。

2)项目部署在同一服务器,如果服务器宕机,将同时影响多个项目。

3)项目之间存在资源竞争,比如某个项目正在做大力推广、占用大量带宽资源,其他项目的可用带宽就很少了,访问会很慢。

4)权限风险。一旦给开发者开通服务器的访问权限,将能改动所有项目,还有误操作的可能性。

基于这些原因,再加上出现过一些事故,我们决定升级项目的部署方式。

部署方式变更

以前,我们的部署方式如下图:

用户要请求网站时,先通过 DNS 域名解析,找到服务器对应的 IP,经过高防服务器后请求发送到 Nginx Web 服务器。然后 Nginx 根据请求路径判断,如果要访问文件,找到前端网站文件;如果请求的是接口,反向代理到后端服务。

升级后,我们的部署方式如下图:

主要有 3 个改动:

1)接入有安全防护和资源加速能力的 CDN,可以提高前端网站的加载速度。

2)后端使用容器平台进行部署,拥有动态扩缩容、负载均衡的能力。

3)前后端部署分离,不再依赖 Nginx 进行转发,而是区分不同的请求域名,通过 DNS 解析到不同的 CDN 上。

CDN 平台我是同时使用了腾讯云 CDN 和蓝易云 CDN,不同的项目选择了不同的 CDN。蓝易云 CDN(tsycdn.com)虽然不像腾讯云那么有名,但是性价比更高,能够有效防止 DDOS 攻击。在我网站被频繁攻击的那段时间,他们也帮了我不少。

而且最打动我的还是他们的技术支持,能耐心陪我一起改几个小时的 Bug,没谁了:

容器平台的话,我们将一部分服务放在了微信云托管上,可以很方便地配置流水线,实现提交代码到 GitHub 后自动发布和部署:

还可以查看服务日志、资源占用情况:

虽然微信云托管平台感觉很久没更新了,配置容器的灵活性也没那么高,但是能够满足大多数开发者的使用诉求了。

升级过程

1、后端服务迁移

既然后端服务要部署到容器平台,肯定要把项目制作为 Docker 镜像。

方法很简单,在后端项目根目录创建一个 Dockerfile ,编写构建镜像的命令即可。

比如 Spring Boot 项目可以使用类似下面的配置:

bash 复制代码
# 选择基础镜像
FROM maven:3.8.1-jdk-8-slim as builder
​
# 解决容器时期与真实时间相差 8 小时的问题
RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai > /etc/timezone
​
# 复制代码到容器内
WORKDIR /app
COPY pom.xml .
COPY src ./src
​
# 打包构建
RUN mvn package -DskipTests
​
# 容器启动时运行 jar 包
CMD ["java","-jar","/app/target/server.jar","--spring.profiles.active=prod"]

这里有个比较坑的地方,要注意容器环境的时间,有可能会和真实时间相差 8 小时,导致日志时间、以及插入到数据库的时间错误。

2、配置 CDN

配置 CDN 的关键是配置源站的地址。CDN 相当于是缓存,如果用户需要的数据在 CDN 上找不到,CDN 节点就会请求源站来获取数据,所以源站配置一定不能错。

上图中的回源设置,是指 CDN 请求源站的方式,包括协议、域名端口号等。

这里有 2 个注意事项:

1)避免给源站添加任何的重定向逻辑,否则可能重定向时直接暴露了源站地址。

比如 cdn 地址是 "yupi.icu",源站地址是 "base.yupi.icu",一般源站地址是要隐藏起来的,否则用户就可以绕过 CDN 直接攻击你的源站。如果源站配置了重定向逻辑,比如将后缀 "/" 路由到 "/aaa"。那么用户在访问 "yupi.icu/" 时,可能会被自动重定向到 "base.yupi.icu/aaa"!暴露了!

2)如果 CDN 站点开启了 HTTPS,回源协议尽量用 HTTP,否则可能会出现因为相同证书子域名 SSL 配置不一致导致的 421 错误(Misdirected Request),这个错误可以说是非常冷门了,不自己上线个项目,大概率听都没听说过。

3、配置 DNS

打通 CDN 到源站(容器平台)的访问后,最后一步就是配置 DNS,让用户访问的域名(比如 www.code-nav.cn)解析到 CDN。

需要注意的是,DNS 的解析生效时长在全国各地是不等的,所以有可能更改解析后,北京的用户访问不了、上海的用户能访问。所以不要急着把老服务下线掉!

本来以为很顺利,结果呢,CDN 访问源站竟然失败了,源站返回了 444 错误码(连接已关闭)!又是一个冷门的错误!

这个错误可把我折腾坏了,为啥我的服务器会拒绝国内 CDN 节点的连接呢?首先第一个猜测就是服务器封禁了 IP,于是查了高防、查了服务器防火墙、还咨询了云服务商的客服,结果都说没有封禁 IP。。。

于是,我去看了下 Nginx 的日志:

arduino 复制代码
CDN 节点的 IP - - [29/Apr/2024:00:06:41 +0800] "GET /favicon.ico HTTP/1.1" 444 0 "https://www.code-nav.cn/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"

Nginx 既然已经收到了请求,说明大概率是 Nginx 配置拒绝了连接。但是我翻烂了 Nginx 的配置,也没找到在哪配置了 IP 封禁。。。

最后你猜怎么着?我突然想起来几年前,我曾经在这个服务器上购买过 Nginx 防火墙。虽然它早已过期,但貌似还能帮我自动封禁一些 IP。。。估计是因为昨天配 CDN 时我为了测试验证,使得访问源站频率过高导致的。

于是我把 Nginx 防火墙卸载了,就没有这个错误了。

用 4 个字来形容,我想到了 "阴魂不散"。


以上就是本期分享。当然,实际的升级过程,可比我这篇文章描述地还要麻烦,因为还涉及到一些平台(比如微信公众平台)的白名单配置。而且我们升级肯定是需要灰度的,先拿访问量最低的项目去验证流程,再陆续迁移其他项目。

相关推荐
桃园码工7 分钟前
15_HTML5 表单属性 --[HTML5 API 学习之旅]
前端·html5·表单属性
Yan.love22 分钟前
开发场景中Java 集合的最佳选择
java·数据结构·链表
椰椰椰耶25 分钟前
【文档搜索引擎】搜索模块的完整实现
java·搜索引擎
大G哥26 分钟前
java提高正则处理效率
java·开发语言
小_太_阳1 小时前
Scala_【1】概述
开发语言·后端·scala·intellij-idea
百万蹄蹄向前冲1 小时前
2024不一样的VUE3期末考查
前端·javascript·程序员
智慧老师1 小时前
Spring基础分析13-Spring Security框架
java·后端·spring
lxyzcm1 小时前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
轻口味1 小时前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami1 小时前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json