一、先看全景架构图
先上图,你先有整体感。
1)用户访问系统的全链路图
XML
┌──────────────────────────────┐
│ 用户浏览器 │
│ 访问: https://portal.xxx.com │
└──────────────┬───────────────┘
│
│ 1. 通过域名访问
▼
┌──────────────────────────────┐
│ DNS / 本地 hosts │
│ portal.xxx.com -> 入口IP │
└──────────────┬───────────────┘
│
│ 2. 解析到入口IP
▼
┌──────────────────────────────┐
│ Nginx / Ingress入口层 │
│ 根据域名/路径决定转给谁 │
└───────┬────────────────┬─────┘
│ │
3a. / 页面资源 │ 3b. /api 接口请求
│ │
▼ ▼
┌──────────────────┐ ┌────────────────────┐
│ Front 服务 │ │ Gateway 服务 │
│ (静态文件服务) │ │ (API统一入口) │
└────────┬─────────┘ └─────────┬──────────┘
│ │
│ 返回 index.html/js │ 4. 按接口路由转发
▼ ▼
┌──────────────────┐ ┌────────────────────┐
│ 浏览器渲染页面 │ │ Backend 服务群 │
│ 执行前端JS代码 │ │ user/order/auth... │
└────────┬─────────┘ └─────────┬──────────┘
│ │
│ 5. 前端继续调接口 │ 6. 查库/执行业务
│ ▼
│ ┌────────────────────┐
│ │ 数据库/缓存 │
│ │ MySQL/Redis/ES等 │
│ └────────────────────┘
│
▼
┌──────────────────┐
│ 页面显示真实数据 │
└──────────────────┘
2)如果放到 Kubernetes 里,关系图是这样的
XML
集群外部
────────────────────────────────────────────────────────
浏览器
|
| https://portal.xxx.com
v
[外部LB / 公网IP / 内网IP]
|
v
[Ingress Controller(Nginx)]
────────────────────────────────────────────────────────
Kubernetes 集群内部
────────────────────────────────────────────────────────
┌─────────────────────────────┐
│ Ingress规则 │
│ host: portal.xxx.com │
│ / -> front-service │
│ /api/* -> gateway-service │
└────────────┬────────────────┘
│
┌──────────────┴──────────────┐
│ │
v v
┌──────────────────┐ ┌──────────────────┐
│ front-service │ │ gateway-service │
│ ClusterIP服务 │ │ ClusterIP服务 │
└─────────┬────────┘ └─────────┬────────┘
│ │
v v
┌──────────────────┐ ┌──────────────────┐
│ front Pod 1 │ │ gateway Pod 1 │
│ nginx+静态文件 │ └──────────────────┘
├──────────────────┤ ┌──────────────────┐
│ front Pod 2 │ │ gateway Pod 2 │
│ nginx+静态文件 │ └─────────┬────────┘
└──────────────────┘ │
│ 路由到内部服务
v
┌─────────────────────────────┐
│ backend service群 │
├─────────────────────────────┤
│ user-service -> user Pod │
│ order-service -> order Pod │
│ auth-service -> auth Pod │
└─────────────────────────────┘
二、先把每个角色讲明白
1. 前端 Front 是什么?
前端是你用户能看到和点击的页面,例如:
- 登录页
- 首页
- 菜单栏
- 表格
- 按钮
- 图表
你开发时可能写的是:
- Vue
- React
- HTML/CSS/JS
但部署后,一般会被打包成:
index.htmlmain.jsapp.css- 图片资源
所以你可以先记住一句:
大多数前端项目,部署后本质上就是静态文件。
2. 后端 Backend 是什么?
后端负责真正的业务逻辑:
- 用户登录
- 查询订单
- 保存表单
- 权限校验
- 访问数据库
比如你在页面点"查询用户",前端不是自己知道用户数据,而是调用后端接口:
GET /api/user/list
后端返回 JSON 数据,前端再渲染出来。
3. Gateway 是什么?
Gateway 是"后端统一入口"。
它的作用就像一个总服务台:
- 前端所有接口都先打到这里
- 它再决定转给哪个后端服务
- 还可以统一做 token 校验、限流、日志、灰度等
比如它会判断:
/api/user/**-> user-service/api/order/**-> order-service/api/auth/**-> auth-service
所以前端一般不直接调 user-service、order-service,而是统一调 gateway。
4. Nginx 是什么?
Nginx 非常常见,它通常扮演以下几个角色:
角色 A:静态文件服务器
把前端打包好的 HTML/JS/CSS 返回给浏览器。
角色 B:反向代理
把请求转发给后端。
角色 C:负载均衡
后面有多个实例时,Nginx 可以轮流转发。
角色 D:K8s 的入口控制器
在 K8s 里,常常由 Nginx Ingress Controller 负责把外部请求引入集群内部。
5. Kubernetes(K8s)是什么?
K8s 不是业务代码,它是"容器编排平台"。
它帮你管理这些服务怎么运行:
- front 怎么部署
- gateway 怎么部署
- backend 怎么部署
- 挂了怎么自动重启
- 流量怎么负载均衡
- 怎么滚动发布
- 怎么扩容
可以理解为:
K8s 是整个系统的"基础设施管理者"。
三、一个请求是怎么一步一步走通的?
这个最关键,我给你拆成两个阶段:
阶段 A:先把页面打开
用户在浏览器输入:
https://portal.xxx.com
第 1 步:浏览器先解析域名
浏览器并不认识 portal.xxx.com,它只认识 IP。
所以要先查:
portal.xxx.com对应哪个 IP?
这个过程可能来自:
- 公司 DNS
- 公网 DNS
- 你本机的 hosts 文件
比如解析结果:
portal.xxx.com -> 10.10.10.20
第 2 步:请求打到入口层
浏览器向 10.10.10.20 发请求。
这个 IP 通常不是某个具体业务 Pod 的 IP,而是:
- 负载均衡器 IP
- Ingress 暴露的 IP
- Nginx 所在机器 IP
请求先到:
Nginx / Ingress
它是系统的统一入口。
第 3 步:Ingress/Nginx 根据规则分流
比如它有这样的规则:
portal.xxx.com的/路径 ->front-serviceportal.xxx.com的/api/路径 ->gateway-service
此时你访问的是 /,所以被转给 front。
第 4 步:Front 返回前端静态资源
front 服务里通常放着:
index.htmlapp.jsstyle.css
Nginx 把这些文件返回给浏览器。
浏览器下载这些资源后,就把页面渲染出来了。
这时候你看到的页面,其实只是"页面壳子",很多真实数据还没加载。
阶段 B:页面加载后,再去请求数据
比如你打开用户管理页面,前端 JS 代码会继续发请求:
GET /api/user/list
第 5 步:接口请求再次来到 Ingress/Nginx
请求路径现在是:
/api/user/list
Ingress/Nginx 一看是 /api/ 开头,就知道这是接口请求,不是静态页面请求。
于是把它转给:
gateway-service
第 6 步:Gateway 判断该转给哪个后端
Gateway 根据路由规则判断:
/api/user/** -> user-service
所以这个请求会被转发给:
user-service
第 7 步:Backend 处理业务
user-service 收到请求后:
- 验证参数
- 查数据库
- 组装返回结果
比如查 MySQL 后返回:
[ {"id":1,"name":"张三"}, {"id":2,"name":"李四"} ]
第 8 步:数据沿路返回到浏览器
返回链路是:
user-service -> gateway -> ingress/nginx -> 浏览器
浏览器拿到 JSON 后,前端 JS 把它渲染成表格。
于是你就看到页面上出现了真实的数据。
四、完整请求链路图
我给你画一个更完整的图。
XML
【用户访问页面】
浏览器
|
| 1. 输入 https://portal.xxx.com
v
DNS / hosts
|
| 2. portal.xxx.com -> 10.10.10.20
v
Ingress / Nginx
|
| 3. 判断 path = /
v
front-service
|
| 4. 转发到某个 front Pod
v
front Pod (nginx + index.html/js/css)
|
| 5. 返回静态资源
v
浏览器
|
| 6. 浏览器执行前端JS
| 7. 请求 /api/user/list
v
Ingress / Nginx
|
| 8. 判断 path = /api/*
v
gateway-service
|
| 9. 转发到某个 gateway Pod
v
gateway Pod
|
| 10. 路由 /api/user/* -> user-service
v
user-service
|
| 11. 转发到某个 user Pod
v
user Pod
|
| 12. 查询 MySQL / Redis
v
数据库
|
| 13. 返回结果
v
user Pod -> gateway Pod -> Ingress/Nginx -> 浏览器
|
| 14. 前端渲染数据
v
页面展示最终内容
五、为什么前端看上去"能调接口"?
本质上是因为前端 JS 代码里写了接口地址。
例如:
axios.get('/api/user/list')
这里的 /api/user/list 表示:
- 还是请求当前域名
- 但路径走
/api
如果当前页面是:
https://portal.xxx.com
那么浏览器最终发出去的其实是:
https://portal.xxx.com/api/user/list
这样做的好处是:
- 跟页面同域名
- 不容易跨域
- 由 Nginx/Ingress 统一分流
这就是很多项目喜欢这样配的原因:
/走 front/api走 gateway
六、为什么本地开发经常要配 hosts?
这个点特别重要。
1)hosts 是什么?
你电脑上的一个文件,用来"手工指定域名 -> IP 的映射关系"。
比如你写:
10.10.10.20 portal.xxx.com
意思是:
以后你电脑访问
portal.xxx.com时,不要去问 DNS 了,直接认为它就是10.10.10.20
2)为什么要配?
通常有几个原因:
原因 1:测试域名没有正式 DNS
很多测试环境并没有在公司 DNS 或公网 DNS 中配置好。
所以你只能自己本地写。
原因 2:需要访问指定环境
比如:
- 开发环境入口 IP:
10.10.10.20 - 测试环境入口 IP:
10.10.10.30
你可以通过改 hosts,让同一个域名指向不同环境。
原因 3:很多功能必须依赖域名
例如:
- Cookie 是按域名生效的
- HTTPS 证书绑定域名
- 登录回调地址需要固定域名
- Nginx / Ingress 会根据 Host 做路由
如果你直接访问 IP:
http://10.10.10.20
很多时候会有问题,因为系统不是按 IP 配的,而是按域名配的。
3)为什么不能随便用 IP?
比如 Ingress 规则可能是:
host: portal.xxx.com
只有你请求头里的 Host 是 portal.xxx.com,它才知道该把请求转给 front-service。
如果你直接访问 IP:
http://10.10.10.20
Host 就不是 portal.xxx.com,Ingress 很可能匹配不到规则。
所以:
hosts 的作用是让你本地电脑"假装认识这个域名",并把它指向指定 IP。
七、K8s 里面这些对象到底是什么?
这是你以后看部署配置一定会遇到的。
1)Pod:真正跑容器的地方
Pod 是 K8s 里最小的运行单元。
比如:
- front Pod
- gateway Pod
- user Pod
你可以把 Pod 理解成一个"小运行实例"。
但 Pod 的 IP 不稳定,重建后可能变,所以一般不会直接让别人访问 Pod IP。
2)Deployment:管理一组 Pod
Deployment 用来管理 Pod 的数量和升级。
例如:
- front 部署 2 个副本
- gateway 部署 2 个副本
- user-service 部署 3 个副本
好处:
- 某个 Pod 挂了,自动补
- 发版时可以滚动更新
- 可以随时扩容缩容
例如:
XML
front Deployment
├─ front Pod 1
└─ front Pod 2
gateway Deployment
├─ gateway Pod 1
└─ gateway Pod 2
3)Service:给 Pod 提供一个稳定访问入口
因为 Pod IP 会变,所以 K8s 提供 Service。
Service 像一个稳定的门牌号:
front-servicegateway-serviceuser-service
别人不需要关心 Pod 有几个,也不需要记 Pod IP,只要访问 Service 名字即可。
例如在集群内部:
http://gateway-service http://user-service
K8s 会自动帮你把流量转发到后面的 Pod。
4)Ingress:把外部流量引进来
Ingress 负责定义:
- 哪个域名
- 哪个路径
- 转发到哪个 Service
host: portal.xxx.com paths: / -> front-service:80 /api -> gateway-service:8080
它是 K8s 的"外部入口路由规则"。
八、用 yaml 思维理解部署关系
我不写太复杂,只写小白能看懂的版本。
1)front Deployment
意思是:部署前端服务的 Pod。
XML
apiVersion: apps/v1
kind: Deployment
metadata:
name: front
spec:
replicas: 2
template:
spec:
containers:
- name: front
image: nginx-front:1.0
你可以这样理解:
- 创建一个叫
front的部署 - 跑 2 个实例
- 容器镜像是
nginx-front:1.0 - 里面放的是前端静态文件
2)front Service
XML
apiVersion: v1
kind: Service
metadata:
name: front-service
spec:
selector:
app: front
ports:
- port: 80
targetPort: 80
意思是:
- 创建一个服务名叫
front-service - 它后面关联的是 front Pod
- 别人访问
front-service:80,就能访问 front Pod
3)gateway Service
XML
apiVersion: v1
kind: Service
metadata:
name: gateway-service
spec:
selector:
app: gateway
ports:
- port: 8080
targetPort: 8080
意思是:
- 创建一个
gateway-service - 它指向 gateway Pod
- 集群内部访问它就能访问网关
4)Ingress 路由规则
XML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: portal-ingress
spec:
rules:
- host: portal.xxx.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: front-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: gateway-service
port:
number: 8080
你把它翻译成人话就是:
- 如果访问域名
portal.xxx.com - 路径是
/,去 front-service - 路径是
/api,去 gateway-service
这就是前后端走通的关键连接点。
九、Gateway 怎么找到具体 backend?
在 gateway 里,也会有自己的路由配置。
比如:
XML
routes:
- id: user
uri: http://user-service:8080
predicates:
- Path=/api/user/**
- id: order
uri: http://order-service:8080
predicates:
- Path=/api/order/**
翻译成人话:
/api/user/**的请求,转发到user-service/api/order/**的请求,转发到order-service
所以 gateway 访问 backend 时,不是靠公网域名,而是靠 K8s Service 名称。
十、为什么说 K8s 内部靠 Service 互相调用?
因为 Pod 不稳定,而 Service 稳定。
例子
假设 user-service 后面有 3 个 Pod:
- user Pod A
- user Pod B
- user Pod C
Gateway 只需要访问:
http://user-service:8080
K8s 会自动选择某一个 Pod 来处理:
gateway -> user-service -> user Pod A gateway -> user-service -> user Pod B gateway -> user-service -> user Pod C
这就是服务发现和负载均衡。
十一、Nginx、Ingress、Gateway 容易混,怎么区分?
这个你一定要记住。
1)Ingress
这是 K8s 的"资源对象",用来写路由规则。
你可以理解成"规则配置"。
比如:
- 什么域名进来
- 什么路径转哪个 service
2)Ingress Controller(常见是 Nginx)
这是"真正执行 Ingress 规则的程序"。
你可以理解成:
- Ingress 是配置文件
- Nginx Ingress Controller 是执行这些配置的代理程序
3)业务 Nginx
有时 front 本身也会是一个 Nginx 容器,用来托管前端静态文件。
所以你在项目里经常会看到两个"nginx"的感觉:
一个是入口 Nginx
负责接收外部请求,按域名/路径分发。
一个是 front 容器里的 Nginx
负责返回前端静态资源。
这两个角色可能是同一种软件,但职责不同。
4)Gateway
这是业务 API 层面的总入口,不只是做简单转发,还会做:
- token 鉴权
- 统一异常
- 灰度
- 限流
- 监控埋点
所以它比普通 Nginx 更"懂业务接口"。
十二、你可以这样理解整套系统分层
XML
第1层:用户访问层
浏览器 / App
第2层:域名解析层
DNS / hosts
第3层:集群入口层
LB / Ingress / Nginx
第4层:页面和API入口层
Front / Gateway
第5层:业务服务层
User Service / Order Service / Auth Service
第6层:数据层
MySQL / Redis / MQ / ES
十三、最常见的两种部署方式
方式 A:同域名,按路径转发
XML
https://portal.xxx.com -> 前端页面
https://portal.xxx.com/api/* -> 后端接口
优点
- 不容易跨域
- 配置简单
- 用户只感知一个域名
路由方式
/-> front/api/-> gateway
这是很多后台管理系统最喜欢的方式。
方式 B:前后端不同域名
XML
https://portal.xxx.com
https://api.xxx.com
优点
- 接口边界更清晰
- 前后端彻底分离
- 更适合大系统
缺点
- 可能有跨域问题
- 需要配置 CORS
十四、为什么前端访问后端有时会报跨域?
浏览器有"同源策略"。
同源要求这三项都相同:
- 协议相同
- 域名相同
- 端口相同
比如页面来自:
https://portal.xxx.com
它去请求:
https://api.xxx.com
域名不同,所以跨域。
这时后端要正确配置跨域响应头,否则浏览器会拦截。
所以很多项目喜欢用:
https://portal.xxx.com/api/*
这样前端和接口同源,不容易出跨域问题。
十五、给你一个"最真实的项目视角"
假设你们项目中有这些组件:
- front
- gateway
- user-backend
- order-backend
- nginx ingress
- mysql
- redis
那你可以这样理解:
用户访问首页时:
浏览器 -> 域名 -> Ingress/Nginx -> front -> 返回静态页面
页面查用户信息时:
浏览器 -> /api/user/info -> Ingress/Nginx -> gateway -> user-backend -> mysql
页面查订单列表时:
浏览器 -> /api/order/list -> Ingress/Nginx -> gateway -> order-backend -> mysql
登录校验时:
浏览器 -> /api/auth/login -> Ingress/Nginx -> gateway -> auth-backend
gateway 和 backend 的通信方式:
gateway -> user-service gateway -> order-service gateway -> auth-service
都是通过 K8s Service 名称。
十六、你以后怎么排查"访问不通"?
这个特别实用,我给你一个排查顺序。
如果页面打不开,按这条链路查:
1. 域名能不能解析?
ping portal.xxx.com nslookup portal.xxx.com
2. 本地 hosts 有没有配错?
检查:
- 域名写对没
- IP 对不对
3. Ingress / Nginx 是否正常?
- 入口 IP 是否正确
- Ingress 是否有规则
- Nginx 是否启动正常
4. front-service 是否存在?
kubectl get svc
5. front Pod 是否正常?
kubectl get pods kubectl logs xxx
6. 前端静态文件是否真的打进镜像了?
有时 Nginx 正常,但 index.html 不存在,也会 404。
如果页面打开了,但接口报错,按这条链路查:
1. 浏览器请求的接口地址对不对?
打开 F12 -> Network,看实际请求的是哪个 URL。
2. /api 有没有被转发到 gateway?
看 Ingress 规则。
3. gateway 是否正常?
- Pod 是否 Running
- 日志里有没有报错
4. gateway 路由是否正确?
例如:
/api/user/**是否配到了user-service
5. backend service 是否存在?
kubectl get svc
6. backend pod 是否正常?
kubectl get pods kubectl logs
7. 数据库是否可连接?
很多接口报 500,本质是数据库连接失败。
十七、最适合小白记住的一张脑图
你把下面这段记住,很多问题就能自己想通:
XML
1. 浏览器访问的是"域名",不是 Pod
2. 域名要先解析成 IP(DNS 或 hosts)
3. 请求先到 Ingress/Nginx 入口
4. 入口按路径把 / 给 front,把 /api 给 gateway
5. front 返回静态页面
6. 页面里的 JS 再去调用接口
7. gateway 再把接口转给各个 backend
8. backend 查库后返回数据
9. K8s 用 Deployment 管理 Pod,用 Service 提供稳定访问,用 Ingress 接外部流量
十八、最后给你一个"人话版总结"
你可以把整套系统想成一个商场:
- 域名:商场名字
- DNS/hosts:导航地图,告诉你商场在哪
- Ingress/Nginx:商场大门和导购台
- Front:展示大厅,给你看页面
- Gateway:总服务台,专门接收办事请求
- Backend:后面的各业务办公室
- MySQL/Redis:档案室和缓存柜
- K8s:整个商场运营管理系统
流程就是:
- 你先找到商场地址(域名解析)
- 进商场大门(Ingress/Nginx)
- 先看到展示大厅(Front)
- 真要办业务时去总服务台(Gateway)
- 总服务台带你去不同办公室(Backend)
- 办公室查档案室(数据库)
- 办完再把结果告诉你
