前端容器化部署——实战学习nginx,积累面试经验

点击上方 前端Q,关注公众号

回复加群,加入前端Q技术交流群

前文有提到前端项目容器化部署和静态资源部署的两种方式,核心的区别就是在于部署的这个文件服务器在谁的手里管辖。如果说是纯上传静态资源就可以完成部署工作,那么服务器的管辖大概率在运维同学手里;如果说是容器化部署,那意味着我们可以自己管理自己的文件服务器——Nginx。

本文不会细致讲解从零到一的 Nginx 配置、高级玩法,更多是通过我个人遇到的一些实战场景,跟大家一起从真实的角度了解这个我们熟悉又陌生的朋友。

前言

尽管 nginx 相比于 html、css、js 这三剑客来说,并不是前端的必修课,但是它的存在对于整个前端项目来说也不容小觑,毕竟项目经开发完上线,它就要开始发力了。

了解 nginx 可以让我们更加清楚整个 web前端 的工作链路;基于对整生态的上游下熟知从而更加快速地定位一些问题;甚至可以在面试中应对某些开放性场景中表现得游刃有余...

登录场景

企业中,一般都会有一套统一的登录、鉴权的流程。这一套路程中,中间可能存在多个节点,每个节点都各司其职,最终完成一个用户的鉴权、跳登录的这么一个流程。如果此时前端项目的 nginx 不在你手上,你大概率可以不用管这些,只要有关登录失败的问题,直接找运维查日志再找他们就好...

但是如果前端部署的 nginx 是你自己在管理,那么你大概率需要了解这其中的登录上下游关系,并且根据相应的节点做一定的跳转处理,从而完成整个登录流程的接入。以至于出现一些登录异常的问题时,你也需要自己跑到 nginx 里查看对应的日志,来定位一些问题。

1e8d8d5f9fe1c158e5f2b484bedc804b.jpeg

如上图所示,我简单的ga了一个鉴权、跳登录的流程图。当前端页面发起一个 /user 的请求获取用户信息时,如果出现鉴权不通过需要跳转登录流程,那承载前端静态资源的 nginx 服务器就需要做一些关于登录的跳转配置了。

面试场景

关于面试场景,能拉上 nginx 来说的就太多了,我就简单例举几个能想到的例子吧。其实大厂面试官很喜欢问一些开放性的问题,就好比:页面白屏、登录失败、为什么会404、分析首屏加载慢的情况这种...相信经历过鹅厂面试的同学多多少少都遇到过,那么针对这些面试题,如果仅仅从纯前端技术的角度回答,确实显得有些苍白无力了...

为什么这么说?因为这类问题大多数都是比较全面性的问题,前端技术并不能完全覆盖其中。而且我相信面试官这样问的目的,也不仅仅是纯考察你的前端技术,我更愿意相信他们是想全面考察你对整个 web 应用的理解有多少。

比如我自己,不认识 nginx 的时候,回答白屏、登录失败、加载慢等这种开放性问题,也只能从前端角度出发。诸如什么js执行出错、网络问题、服务器挂了啊等等,反正背过的没背过的八股文都一拥而上了。但是后来,实战玩过 nginx 后,了解了众多的上下游服务等链路,或许我在回答上可以多一些维度了。比如我从这些角度进行思考:

  1. nginx 进程问题。真实遇到 openresty 中存在死循环 lua 脚本导致 nginx 进程跑满 cpu,此时浏览器访问所有页面都无法加载(纯崩溃状态。

  2. 「配置错误」导致404。我们都知道当访问不存在的资源时就会获得 404 的状态码,但其实,并不是所有的 404 状态码都是资源不存在而导致的,可能是有坑人的配置(下文会详细讲。

  3. nginx 「重试配置」。当遇到请求慢的情况,也有可能是在 nginx 配置了 proxy_next_upstream ,当某个请求上游出错、超时等情况出现时,会尝试转发到下一个上游服务器。这也会导致请求慢的问题,毕竟多次请求的耗时是叠加的,对于用户端来说,请求总时间就长了。

  4. 登录失败——url 长度太长。用户携带了大量的 params 跳转登录,当业务服务器处理完成返回跳转原登录url时,如果 header 超出 nginx 配置的缓冲区大小也会出现登录错误。如:upstream sent too big header while reading response header from upstream 这种的 nginx 错误。

总之,当结合 nginx 的场景再去回答上述开放性面试题时,我相信整个回答的完整度、知识覆盖面等都会比仅仅从前端出发的角度要好,或许这也会为你的面试加上一丢丢的分数。所以,了解、学习 nginx 对于前端同学来说,还是有一定必要性的,不管是应对工作中的一些业务场景,或者是面试。

实战相关

如何用 nginx 部署

前面讲容器化部署的时候,我并没有展开来说,但其实这部分并不复杂,我这里简单提一下。首先我跟大家演示一下,真实前端项目部署上线后,是怎么运行起来的。开发时本地有 vite、webpack 给我们预制好的 dev server,那么当我们将项目打包成 dist 后,应该怎么搞呢?

我这里通过 vite create 搞了个初始化的项目,本地启动后如下图所示。(为了好区分,我特地加了一句:Nginx Test)

7c29aacae12870a5159e86c73b960176.jpeg

基于这个项目,运行打包命令后,我们便会得到一个 dist 包。产物中可以找到我自己加入得那一句 Nginx Test:

3fdc353c6778884c1d8580e7bd93eab1.jpeg

这时候,我就把对应的这个 dist 包,拉到我本地装了 nginx 的一个目录中。并且把 nginx 的配置做了下改动:

68edfeb1688a664f05a16413b5378b3c.jpeg

dd17ce878485a13f019766019063dbcc.jpeg

紧接着我通过 nginx -g "daemon off;" 命令运行 nginx。-g "daemon off;"这个参数大家不用关注也行,它只是我用于让 nginx 前台运行,方便随时停掉的而已(不然有守护进程,停掉比较麻烦。这时候,当我们访问 localhost 应该就能看到我们的 web 界面了(默认 80 端口:

3dd9cb90af188423b196d7ef48bfdef1.jpeg

那么,我们在容器化部署时,只需要遵循这样的配置方式,基于 nginx 的基础镜像,就可以打出一个前端项目的镜像包了。当我们基于该镜像启动容器时,运行 nginx 的启动命令,如无意外的情况我们的项目就成功部署好了。

简单看看 Dockerfile 的写法(详细大家可以去官方的nginx镜像仓库看看:

FROM nginx

COPY nginx.conf /etc/nginx/conf.d/
COPY ./dist/ /usr/share/nginx/html/

CMD ["/bin/bash", "-c", "nginx -g 'daemon off;'"]

上述的每一行你都可以在官方的镜像仓库中找到。东西不多,我带着大家一行行看下:

  1. 复制我们项目中的 nginx.conf 配置到一个位置;

  2. 复制 dist 包到一个位置;

  3. nginx 前台启动命令

这样,前端项目的容器化部署就搞定了。不过这一切操作,都不会包含上一篇文章提到的重启容器后静态资源丢失的处理,如需处理重启容器资源丢失问题,请参考上一篇文章的讲解。

真真假假 404

534b62659a62ae98f7ffe04e5983aae0.jpeg

这个熟悉页面一定是众多前端的噩梦!看到它就意味着有问题!不过不知道你有没有想过这么一个问题:怎么出现这个界面的呢?这个界面是由谁写的呢?或者更高级一点的,如 openresty,50x 报错的时候会返回如下的界面:

918160eb5a41175fac31f80ab724b5e2.jpeg

其实很多线上项目中,通常 web服务器 会因为某些异常状态而返回对应的一些页面(如上述 nginx 的404,openresty 的 50x。这些大部分都不是我们自己开发的(除非自己有需求开发并且配置到 nginx 上了),所以当我第一次在自己域名的项目中遇到一些奇怪的页面,还以为服务器被黑了呢...

那么回到 404 这个问题,我们都知道访问不存在的资源就会 404,那么如果项目是基于默认的 nginx 启动运行的,404 的时候就会返回上面那个大家都比较熟悉的页面。如果我对相应的配置改动一下,如:

error_page  404              /nb.html;
location = /nb.html {
    root   html;
}

当我们再次访问不存在资源时,页面就如我们配置那样返回了:

c9b13c35c8a8c1146c9b89aacd85dafb.jpeg

上述大概给大家介绍了一下通过 nginx 部署的项目,404 时候的一个表现。虽然我上面皮了一下,给 nginx 的 404 错误配置了一个为 nb.html 的页面作为返回,但线上一般是不会这么玩的是吧?所以我们每次在浏览器接收到的 404.html 的返回结果,就一定是遇到 「404资源不存在的问题吗」

如果你现在问我这个问题时,我会回答「是,但不全是」。为何这么说,我通过这个案例来说明。

前文我将 dist 包拉到 nginx 的 html 的目录时,大家可能也注意到了一个叫 50x.html 的文件是吧:

333b84d5e5224dfeba68d002918c6f69.jpeg

双击打开这个 html 时,他是长这样的:

7c1addf79c076c224b2e2b08d7dbb4b4.jpeg

这个页面大伙也有点熟悉对吧,如果我们 nginx 上接收到 50x 的报错,按照默认的配置来说便会返回这么一个页面。比如此时的我通过链接访问来模拟上游服务器返回 502 的错误码时前端接收到最终页面返回的情况。

aa23225366526ff7b48ab9907ea5171d.jpeg

接下来,如果我把这个 50x.html 的文件删了呢?大家可以猜想到结局吗?(这里我已经恢复了404改nb的配置)

61e286d9e330c9cbb58e104e9bcafcf5.jpeg

没错,实时如你所见,页面显示 404 了。其实你看到这里,也许你会觉得这不是扯淡吗?无稽之谈。但我想说的是,这确实是我实战中遇到的问题。因为我们团队内部对 nginx 基础镜像自己又包了点东西,打了一个自己的 nginx 镜像。但这个镜像中,50x.html 的位置放错了,所以每次上游服务器返回任何 50x 报错的时候,最终到页面上的都是404。

这个配置错误,或者说 50x.html 的位置错误,一定程度上影响了一开始我们排查问题时的思考方向。一直怀疑资源问题的我,直到我查看 error.log 时发现其实对应的请求状态是超时,或者 502时,再联合查看 access.log 后,发现居然是 50x.html 的文件不存在...

所以,如果现在你问我前端接收到 404 返回时,是不是一定是资源不存在的问题时,我会回答:是,又不全是。可能因为 nginx 配置问题,导致全部上游的服务器报错问题都会是 404 的返回结果。

dns缓存

如果你曾遇到过某个项目「每隔一段时间打开后出现 404」,但是重启服务又解决了;如果你的项目也是部署在 aws,并且域名解析到其 ingress 层;那么恭喜你,也许你成功踩到了 nginx 的 dns 缓存的坑了。

nginx 默认行为在启动时会解析所有在配置文件中定义的域名。这些解析结果会被缓存,并在整个 Nginx 运行期间使用。基于这一点,如果某个服务的 ip 在 nginx 运行期间的发生了变动,那么就会出现 404 的问题。因为当 nginx 请求上游服务时,依然访问的旧的 ip 地址...

be1ab8b1ac12e3362e9c7ecf5861f075.jpeg

如上图所示,服务器1 的 ip 改变后,再通过该 nginx 向上游发送请求时,就不能正确返回了。此时我们能做的只有重启 nginx(重启时会重新基于配置做 dns 解析),让 nginx 正确的”找到“这个上游服务器。

这其实也是我在实战中真实遇到的场景,并且这问题不太好定位解决。其一就是它的偶发性,aws 的 ingress 的 ip 并不是每时每刻都在变,所以当你想准确定位这个问题时,你却发现这其实很难复现问题。当每次遇到问题,紧急重启完 nginx 问题后问题就解决了,但是当你去追溯问题时你又发现复现不出来。于是你只能找到你的上游服务的开发者一起探讨...

其实你说坑也确实坑,自己菜也确实菜,毕竟从未遇到过,所以一开始解决起来还是有点耗时和棘手。如果说对 nginx 有更深的认知,或者对云厂商了解过多,或许这样的问题排查就不会这么棘手了。所以还是要不断在实战中积累经验,每踩过的一个坑,都不会白踩。

简单总结,如果现在再遇到面试有人问我 404 的原因,或许我不仅仅能回到资源不存在、nginx 配置问题、还能再补充多一个这样的场景:nginx dns 的缓存问题,当遇到上游服务 ip 变化时,依然会有 404 的问题。

总结

其实,历经容器化部署后,更加体会到 nginx 这类 web服务器 对于前端发展的重要性。当我写这篇文章的时候,不断回想起之前面试各大厂时遇到的一些开放性问题,如果结合 nginx 的维度来进行回答,将会更全面。并且在这个时候,自己也意识到为什么当时面试官会问这样的问题。

本文我仅仅例举了两个实战中碰到的问题,发散开来其实可以对应到种种开放性面试题。并且我还没有对所有遇到的问题做一个总结回顾,所以我是有理由相信 nginx 的知识对于整个前端的从业生涯来说是比较重要的。它可以使我们从更加全面的视野来看待前端,看待问题。

如果当前团队中采用的容器化部署前端项目的方式,并且你有机会能接触到 nginx 的配置,那我觉得你一定要亲自上手玩玩。菜如笔者,不断玩不断学习,也算是在不断积累经验的过程也能有一点点收获,并且可以通过实战的经验反哺到一些开放性面试题中,我觉得对自己的综合实力来说是有提升的。所以你也一定可以有所收获~

343bc586ff3d6c6f2265d6a466147966.png

往期推荐

产品:你能让网页也像QQ那种一样发出右下角消息吗

9430469a1c982aa9bf7d9fce2c90600f.png

GitHub + VitePress,或许是你做笔记的新路子

a707880d15f90ccae627346660af3684.png

(已开源)开发了一个纯前端在线代码编辑器、制作一个炫酷动画收藏网站

858bc319a17bf702b6b50e118634771b.png


最后

  • 欢迎加我微信,拉你进技术群,长期交流学习...

  • 欢迎关注「前端Q」,认真学前端,做个专业的技术人...

1dbeb01cb5f24b1994781d0f82268c17.jpeg

09c64bc4f99650981dc25178cfe1d17a.png

点个在看支持我吧

a6b172089392440aae3b45bba599f8a4.gif

当使用Nginx进行容器部署代理多个前端项目时,可以按照以下步骤进行操作: 1. 创建一个Nginx容器:首先,你需要创建一个Nginx容器来作为代理服务器。你可以使用Docker或者其他容器工具来创建和管理容器。 2. 配置Nginx:在Nginx容器中,你需要进行一些配置来实现代理多个前端项目的功能。你可以通过修改Nginx的配置文件来完成这一步骤。 3. 设置代理规则:在Nginx的配置文件中,你需要设置代理规则来将请求转发到不同的前端项目。你可以使用`location`指令来定义不同的路径和对应的代理目标。 4. 启动容器:完成配置后,你可以启动Nginx容器,并将其与前端项目的容器进行连接。这样,Nginx就可以接收到来自客户端的请求,并将其转发到正确的前端项目。 下面是一个示例的Nginx配置文件,用于代理两个前端项目: ``` http { server { listen 80; location /project1 { proxy_pass http://frontend1:8000; } location /project2 { proxy_pass http://frontend2:8000; } } } ``` 在上述配置中,Nginx会将以`/project1`开头的请求转发到名为`frontend1`的前端项目容器的`8000`端口,将以`/project2`开头的请求转发到名为`frontend2`的前端项目容器的`8000`端口。 请注意,上述示例仅为演示目的,实际配置可能因具体情况而有所不同。你需要根据你的前端项目和容器环境进行相应的调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值