前言
本文主要介绍一次前端项目从云主机部署迁移至k8s上,升级时出现访问页面错乱的现象分析以及修复方案,这里的访问页面错乱指的是前端页面访问时css样式、js脚本加载失败引起的错乱。
正文
公司有个老项目一直采用云主机部署,也就是通过Jenkins构建后,打成一个zip包,再把这个zip包解压到一个固定云主机的特定的目录里的部署方式。
虽然公司很早就有k8s平台,也一直提倡将各个项目迁移到k8s上,但是本着服务稳定(能拖就拖)的精神,有个项目一直没有迁移,近期云主机要回收没办法了才开始将这个老项目部署到k8s上。
云主机部署
先说下云主机部署的方式,是通过Jenkins构建平台将项目打包好后,上传到一个特定的服务器A上,然后在要部署的项目的服务器B上把服务器A的zip包下载下来,进行解压,如果有相同的文件就会替换。
这种情况的好处就是历史版本的资源文件,例如js、css、图片等,都会保留,但也会带来历史文件不容易清理的情况。
通过云主机部署,每次上线流程如下,整体来说过程还是比较简单的。
k8s部署
既然要部署到k8s了,就开始准备Dockerfile、Deployment、Service、Ingress这些文件,等部署好后,通过Ingress的访问没问题后,将LB的流量切到Ingress上。
在迁移到k8s上这个流程还挺顺利的。
过了几天,又有一次迭代上线,因为是迁移到了k8s上,Jenkins的构建步骤也发生了写变化,部署流程如下:
访问异常
上线后,团队内访问测试没有问题,但是没过几分钟,客服、运营开始反馈部分用户出现页面错乱的现象,效果如图:
看着页面的样子,像是样式丢失了,团队内赶紧排查,结果没有一个人可以复现,冷静下来分析下原因:
- 反馈问题的是部分用户,而不是大量用户
- 说明是偶然现象
- 说明代码没有问题,要不然都会出问题
- 可能是缓存问题
分析后,感觉有90%的概率是缓存问题,联系了用户,让用户清理下浏览器缓存再试下,但是显示很残酷,清理缓存没有任何效果。
好在,在用户的协助下,发现了一个问题,有些css请求返回的内容不是样式文件,而是html代码。
问题分析
那么,为什么css请求返回的是html代码呢?
第一反应是,cdn在回源的时候,我们返回了错误的内容,由于是部分用户出现这种现象,所以是偶发的、不必现。
先解决客户问题,将cdn资源进行刷新,让用户能正常访问。
开始分析问题,首先是cdn回源时,我们为什么返回了html?查看了下镜像里的nginx.conf文件配置,如下:
server {
listen 80;
server_name _;
access_log /dev/stdout log;
error_log /dev/stdout;
charset utf-8;
location / {
root /home/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
}
通过这个配置文件发现了一些问题,如果在访问js、css等静态资源时,如果找不到则会返回index.html的内容,从而被cdn缓存,用户访问时也就没有了样式。
如何解决呢?简单的方式就是,如果是静态资源直接从目录里找,找不到直接返回404,cdn配置404缓存5s,这样访问不到的话,就会直接返回的状态码为404,而不是200。
修改如下:
location ~* .(css|js|png|gif|jpg|jpeg|svg|ico)$ {
root /home/html;
}
到这里,解决了cdn缓存内容不对的问题,还有个问题是,问什么会出现资源访问不到的情况?
看了下项目在k8s配置的更新策略,发现是滚动更新:
spec:
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
采用滚动更新的话,会出现一种情况,假如旧pod一共有2个,在更新时,新pod启动1个,旧pod下掉1个,此时存在新旧pod各存在一个的情况,这个时间,如果有用户请求进来的话,并且请求到了新的pod里的html,html引用的js、css等资源又请求到旧的pod里,就会出现404的情况。
出现404的另一个原因是,pod里只有本次构建产生的静态资源,相对于之前云主机部署,少了之前版本的静态资源。
这种情况如何解决呢?将这个前端项目的部署方式更改为蓝绿发布,这样等新的pod完全启动后,再将流量从旧的pod切过来,这样的话,如果用户访问的还是旧资源,因为cdn有缓存还是可以继续访问的,而新资源则重新回源也能继续访问。
总结
本文主要介绍一次前端项目从云主机部署迁移至k8s上,在升级版本时出现的一次页面错乱、资源访问不对的情况,以及针对这种情况进行排查分析的过程,一是更改nginx.conf 文件内容,而是部署模式更改为蓝绿发布,问题得到解决。
本文正在参加「金石计划」