← 返回首页 K8S Web / 文档 / 线上 K8S 集群架构

🏭 线上 K8S 集群架构(fke) DNS → 外层 NGINX 主备 VIP → K8S 集群 → 40+ namespace 分区全景 —— 一张图看懂公司线上环境

01总架构图(一图流)

👤 员工/用户浏览器
https://xxx.ergesanbaishou.com
▼
发起请求,查域名
① 公司 DNS · 域名解析层
*.ergesanbaishou.com 统一后缀 → 全部指向同一个 VIP
▼
解析结果 = VIP
② 外层 NGINX 主备 + VIP 漂移(keepalived)
集群外的高可用入口 —— 主挂备顶,VIP 秒级漂移,客户端不断流
NGINX-Master(主)NGINX-Backup(备)
VIP 虚拟 IP · 对外的稳定地址
▼
proxy_pass → K8S 节点 IP:入口端口(★透传 Host 头)
═══ K8S 集群边界 ═══
③ fke K8S 集群(Rancher 管理)
多节点(fke-m1 …) · 两扇"大门"并联(详见 04 节):
门A nginx-ingress(kube-infra · 30080/30443)
门B istio-ingressgateway(istio-system · 30538/30539)
▼
按 host + path 路由 → Service(ClusterIP)→ Pod
④ NS 大分区(40+ namespace · 12 类)
服务各回各家 ↓ 分区地图见下

🗺️ NS 分区地图(40+ namespace · 12 类分区)

🏢 业务app · app-dev · app-uat
auth · on-premises · fke-profile
🗄️ 数据fke-db(MySQL InnoDB Cluster 8.4.7)
fke-db-dev
🔌 中间件fke-middleware
🛠 CI/CDgitlab · jenkins-ci · argo
smart-ops-pipelines
code-server · pingcode
📦 镜像harbor
docker.ergesanbaishou.com 私仓
📊 可观测fke-monitor(监控)
fke-log(日志)
💾 存储longhorn-system
分布式块存储 · PVC 底座
🕸 网格/入口istio-system
knative-serving · oauth2-proxy
🤖 AI/MLkubeflow · kubeflow-components
datacollect-kubeflow
jobset-system
🎥 音视频livekit(实时音视频)
stunner · stunner-system
⚙️ K8S 系统kube-system · kube-public
kube-node-lease · default
kube-infra · fke-infra-dev
🐄 Ranchercattle-system
cattle-impersonation-system · local
📄 展开查看:纯文本版总图(适合复制/粘贴到笔记)
👤 浏览器 → ① DNS(*.ergesanbaishou.com → VIP)
  → ② 外层 NGINX 主备(keepalived VIP 漂移;proxy_pass → 节点:端口,★透传 Host)
  ═══ K8S 集群边界 ═══
  → ③ fke 集群(Rancher;双网关并存: kube-infra/nginx-ingress 30080·30443 + istio-gateway 30538·30539;host+path → svc → pod)
  → ④ NS 分区:
     业务: app app-dev app-uat auth on-premises fke-profile
     数据: fke-db fke-db-dev | 中间件: fke-middleware | 镜像: harbor
     CI/CD: gitlab jenkins-ci argo smart-ops-pipelines code-server pingcode
     可观测: fke-monitor fke-log | 存储: longhorn-system
     网格: istio-system knative-serving oauth2-proxy
     AI/ML: kubeflow kubeflow-components datacollect-kubeflow jobset-system
     音视频: livekit stunner stunner-system
     系统: kube-system kube-public kube-node-lease default kube-infra fke-infra-dev
     Rancher: cattle-system cattle-impersonation-system local
💡 读图顺序:一次 https 请求自上而下过 4 层,每层只干一件事:DNS 管找人(域名→IP) → NGINX 主备管入口高可用(单点不挂) → K8S 网关管路由(域名/路径→服务) → NS 管分区(服务各回各家)。任何一层出问题,排查就从自己那层下手,别越层猜。

02第①层:公司 DNS —— 域名怎么进来

公司统一域名后缀 *.ergesanbaishou.com(如私仓 docker.ergesanbaishou.com)。域名并不直接指向 K8S 节点,而是指向外层 NGINX 的 VIP —— 这样 K8S 集群怎么扩缩、节点 IP 怎么变,域名永远不用改。

# 在办公网任一机器上验证解析
nslookup xxx.ergesanbaishou.com        # 返回的 IP 应是 NGINX 的 VIP,而不是节点 IP
# 入口类 *.ergesanbaishou.com 域名通常都指向同一个 VIP —— 这就是"统一入口"的特征

03第②层:外层 NGINX 主备 + VIP —— 集群外的高可用入口

两台 NGINX(一主一备)通过 keepalived 共享一个 VIP(虚拟 IP):平时 VIP 在 Master 上,Master 挂了 VIP 自动漂到 Backup,客户端无感知不断流。所有进入 K8S 的 HTTP(S) 流量先到这里,再 proxy_pass 转发到 K8S 节点的入口端口。

组件职责关键点
NGINX-Master承接 VIP,反代到 K8Skeepalived 心跳互探;VIP 漂移秒级完成
NGINX-Backup热备,Master 挂则接管 VIP
VIP对外的"稳定 IP"域名解析到它,后端随便换
💡 2026-10 实测补充:这台 NGINX 是全公司统一入口,不只代理 K8S —— nginx -T 里还有大量直连物理机后端(192.168.3.x、10.18.x 各端口)的 proxy_pass,K8S 只是其后端之一;进 K8S 的流量统一走"节点 IP + NodePort"(30080/30538 两扇门),绝不会写 ClusterIP。完整实测见 04 节。
💡 与测试环境同构:测试集群的外层 NGINX 主从 + VIP 链路(k8s.ergesanbaishou.com → VIP → NodePort 31588)就是线上这套的缩小版,完整配置见 K8S 证书管理 与 Ingress 文档 02 节。★ 灵魂行永远是 proxy_set_header Host $host; —— 不透传域名,后端路由必 404。

04第③层:fke 集群与入口网关(双网关并存 · 2026-10 实测)

🚪 先搞懂:为什么说"双网关"?—— 大楼有两扇门

入口网关 = 集群的大门保安。外部流量不能随便打进某个 Pod(IP 会变、数量多、不安全),必须先过一扇"大门",由保安按域名 + 路径决定转给哪个 Service —— 这就是网关干的全部事。

线上这栋"楼"装了两套独立的门禁系统,是并联关系(不是串联 —— 门A 不会把流量再转发给门B):

                     外层 NGINX 主备(VIP)
                    ┌─────┴─────┐
          普通业务域名的流量      网格类平台的流量(如 kubeflow/knative)
                    │            │
                    ▼            ▼
        ┌──────────────────┐  ┌──────────────────────────┐
        │ 🚪 门A: nginx-ingress │  │ 🚪 门B: istio-ingressgateway   │
        │ ns: kube-infra        │  │ ns: istio-system              │
        │ NodePort 30080/30443  │  │ NodePort 30538/30539          │
        │ 按 Ingress 规则路由    │  │ 按 Gateway/VirtualService 路由 │
        └──────────┬───────────┘  └──────────┬─────────────────────┘
                   ▼                         ▼
              Service → Pod             Service → Pod
        (两扇门都通向楼内,只是"门禁系统"不同)
# 想知道哪些服务走哪扇门?(在 fke 上跑)
sudo kubectl get ingress -A     # 门A 的"访客名单":每条规则 = 一个域名/路径 → 后端服务
sudo kubectl get gateway -A     # 门B 的名单(Istio Gateway 资源)

🏨 网关按 ns 分吗?—— 不分!一扇大门服务所有 ns

实测全集群只有一个 istio-ingressgateway(Service 10.100.189.102,装在 istio-system)—— 它是集群级大门,所有 ns 共用。网关不按 ns 分,"路由规则"才按 ns 分:各业务 ns 提交自己的"门牌登记"(Istio 里叫 Gateway/VirtualService),网关汇总所有 ns 的登记形成一张总路由表 —— 大门一个,门牌无数。

              istio-ingressgateway(istio-system,全集群 1 个)
                            ▲
        ┌───────────┬───────┴──────┬───────────┐
        │ 登记       │ 登记         │ 登记       │   ← 各 ns 提交路由规则
   kubeflow ns    app ns       knative ns  ...
  (VirtualService)          (Gateway/VS)
        │           │              │
        ▼           ▼              ▼
     本 ns 的 Service → Pod

门A 是同一个模式:一个 controller(kube-infra)监听全集群所有 ns 的 Ingress 规则 —— 测试集群也一样(Ingress 写在 web ns,controller 装在 ingress-nginx ns)。例外:超大集群可能部署多个 ingressgateway(内/外网流量分开),但本集群 get svc -A 只有一个 → 共用模式。

# 验证:谁在门B 登记过?
sudo kubectl get gateway,virtualservice -A      # 各 ns 提交的"门牌"清单
sudo kubectl get svc -A | grep ingressgateway   # 全集群只有一个网关 Service → 共用

🔌 域名到底怎么找到 Pod?—— 域名选规则,规则选 Service,Service 选 Pod

两扇门殊途同归:域名匹配的是"路由规则",规则选中的是 Service;Pod 不是被域名直接选中的,而是 Service 用 label selector 挑出来的(Endpoints 的本质 = "这个 Service 名下有哪些 Pod"的名单)。

门A(nginx-ingress):
  请求(host+path) → Ingress 规则 → backend.service.name = 某 Service ──┐
                                                                     │
门B(Istio):                                                          ├─→ Service(label selector)
  请求(host) → Gateway(定义监听) + VirtualService(host+path 匹配)     │      → Endpoints → Pod
              → destination.host = 某 Service ───────────────────────┘
                              (两种门到这一步完全一样)
# 查门A 每条规则指向哪个 svc(SVC 列就是答案):
sudo kubectl get ingress -A -o custom-columns='NS:.metadata.namespace,HOST:.spec.rules[*].host,SVC:.spec.rules[*].http.paths[*].backend.service.name'

# 查门B 每条规则指向哪个 svc(DEST 列就是答案):
sudo kubectl get virtualservice -A -o custom-columns='NS:.metadata.namespace,HOSTS:.spec.hosts,DEST:.spec.http[*].route[*].destination.host'

# 再往下一层:Service 选中了哪些 Pod
sudo kubectl get ep <svc名> -n <ns>     # Endpoints 里的 IP 列表 = 后端 Pod 真实 IP
💡 澄清易混点:istio-ingressgateway 自己就是一个 Service(NodePort 30538,门本身);它"找哪个 svc"不是它自己决定的,而是看各 ns 提交的 VirtualService 规则里的 destination.host。Istio 特例:VS 也能直连 Pod 或 ServiceEntry(外部服务),但主流用法仍是走 Service。

实测数据(2026-10)

网关namespaceServiceNodePort(实测)适用流量
ingress-nginxkube-infranginx-ingress-nginx-controller80:30080 · 443:30443常规 Web / Ingress 规则
Istio 网关istio-systemistio-ingressgateway80:30538 · 443:30539 · 15021:30542网格内 / Knative 流量
# 实测命令(get svc -A | grep ingress 立大功):
sudo kubectl get svc -A | grep ingress
# istio-system  istio-ingressgateway            NodePort  10.100.189.102  15021:30542/TCP,80:30538/TCP,443:30539/TCP
# kube-infra    nginx-ingress-nginx-controller  NodePort  10.101.184.130  80:30080/TCP,443:30443/TCP
# kube-infra    nginx-ingress-nginx-controller-admission/metrics/defaultbackend(ClusterIP 配套件)
⚠️ 实测翻案记:第一次用 kubectl get pods,svc -n ingress-nginx 查到空,误判"线上没有 ingress-nginx"—— 其实它装在 kube-infra,不在默认的 ingress-nginx ns。教训:按 ns 查空 ≠ 资源不存在,跨 ns 搜 get svc -A | grep ingress 才是终审。外层 NGINX 转发目标也以此为据:30080/30443(ingress-nginx)或 30538/30539(Istio),具体走哪个待查外层配置。
# 在 fke 上看集群骨架
sudo kubectl get nodes -o wide                     # 节点清单/IP/角色
sudo kubectl get svc -A | grep ingress             # 双网关与端口(★比 -n 精准)
sudo kubectl get ingress -A                        # ingress-nginx 的路由规则
sudo kubectl get pods -n kube-infra -o wide        # ingress-nginx controller 本体

🔍 怎么确认外层 NGINX 走哪扇门?(在 nginx-master 上查)

⚠️ 实测踩坑:在外层 NGINX 配置里 grep 网关的 ClusterIP(10.100.189.102)永远搜不到 —— 不是没走它,而是 ClusterIP 只有集群内可达!外层 NGINX 在集群外,upstream 只能写节点 IP + NodePort(与 MySQL 文档 M5"宿主机 ping 不通 Pod IP"同一知识点)。
IP 类型示例谁能访问
ClusterIP10.100.189.102仅集群内(Pod/节点上) —— 外层 nginx 写了也连不通
NodePort节点IP:30080任何能连节点 IP 的机器 ← 外层 NGINX 只能用这个
# ① 终极命令:dump 全部生效配置再筛(比 grep conf.d 全,include 的其他路径一网打尽)
sudo nginx -T 2>/dev/null | grep -E "proxy_pass|server " | grep -v "#"

# ② 按端口号搜(不是搜 IP!)
grep -rn "30080\|30443" /etc/nginx/     # 命中 → 有流量走门A(nginx-ingress)
grep -rn "30538\|30539" /etc/nginx/     # 命中 → 有流量走门B(istio 网关)

# ③ 都搜不到的三个可能:a.配置不在 conf.d(用 nginx -T 确认 include 范围)
#   b.nginx-backup 那台也有配置(两台都看)  c.istio 流量不经这台 nginx(内网直连 NodePort 或另有入口)

# ④ 集群侧反查交叉验证:看门B 登记了哪些域名,再拿域名回 nginx 配置里 grep
sudo kubectl get virtualservice -A -o custom-columns='NS:.metadata.namespace,HOSTS:.spec.hosts'

✅ 实测结果(2026-10 · nginx-master 上 nginx -T)

大门upstream 位置节点池(实测)承载流量
门A nginx-ingressconf.d 主配置 upstream nginx-ingress6 节点 × 30080
(10.18.51.7/.8/.16/.17/.25/.26)
通用业务域名(多处 proxy_pass http://nginx-ingress)
门B istio-ingressistio-ingress-upstream.conf2 节点 × 30538
(10.18.51.8/.16)
目前仅 kubeflow 域名(kubeflow-new.*)

📋 门B 登记表(VirtualService 实测 · 2026-10)

sudo kubectl get virtualservice -A -o custom-columns='NS:.metadata.namespace,HOSTS:.spec.hosts,DEST:.spec.http[*].route[*].destination.host'
NS            HOSTS   DEST
auth          [*]     dex.auth.svc.cluster.local
kubeflow      [*]     centraldashboard.kubeflow.svc.cluster.local
kubeflow      [*]     jupyter-web-app-service.kubeflow.svc.cluster.local
kubeflow      [*]     katib-ui.kubeflow.svc.cluster.local
kubeflow      [*]     kserve-models-web-app.kubeflow.svc.cluster.local
kubeflow      [*]     metadata-envoy-service.kubeflow.svc.cluster.local
kubeflow      [*]     ml-pipeline-ui.kubeflow.svc.cluster.local
kubeflow      [*]     profiles-kfam.kubeflow.svc.cluster.local
kubeflow      [*]     tensorboards-web-app-service.kubeflow.svc.cluster.local
kubeflow      [*]     volumes-web-app-service.kubeflow.svc.cluster.local
oauth2-proxy  [*]     oauth2-proxy.oauth2-proxy.svc.cluster.local

疑问① 为什么有 9 行都是 kubeflow? 表里每行 = 一条独立的 VirtualService(一个组件一条),不是分组统计 —— kubeflow 平台有 9 个 Web 组件,各提交各的规则,NS 列自然出现 9 次(像班级名单 30 人都写同一个班名,不是写重了,是这个班 30 人)。

疑问② [*] 是什么? 方括号是 custom-columns 显示"数组字段"的格式,[*] = 数组里只有一个元素 *,Istio 通配符 = 匹配任意域名。那 9 条都是 * 怎么不打架?因为分流是分层的:域名分流在外层 NGINX 已完成(kubeflow-new.* → 30538 进门),进门后的流量不再看域名,改看路径 —— 请求 /jupyter 命中 jupyter 的 VS、/katib 命中 katib 的 VS。上面的命令没显示路径列,补一列就一目了然:

# 加上 MATCH 列:看每条 VS 靠什么路径分流(2026-10 实测输出如下)
sudo kubectl get vs -n kubeflow -o custom-columns='NAME:.metadata.name,MATCH:.spec.http[*].match[*].uri.prefix,DEST:.spec.http[*].route[*].destination.host'
NAME                                        MATCH                DEST
centraldashboard                            /                    centraldashboard.kubeflow.svc.cluster.local
jupyter-web-app-jupyter-web-app             /jupyter/            jupyter-web-app-service.kubeflow.svc.cluster.local
katib-ui                                    /katib/              katib-ui.kubeflow.svc.cluster.local
kserve-models-web-app                       /kserve-endpoints/   kserve-models-web-app.kubeflow.svc.cluster.local
metadata-grpc                               /ml_metadata         metadata-envoy-service.kubeflow.svc.cluster.local
ml-pipeline-ui                              /pipeline            ml-pipeline-ui.kubeflow.svc.cluster.local
profiles-kfam                               /kfam/               profiles-kfam.kubeflow.svc.cluster.local
tensorboards-web-app-tensorboards-web-app   /tensorboards/       tensorboards-web-app-service.kubeflow.svc.cluster.local
volumes-web-app-volumes-web-app             /volumes/            volumes-web-app-service.kubeflow.svc.cluster.local

实证落地:9 条 VS 9 个路径,各管一段 —— /jupyter/ 进笔记本、/katib/ 进调参、/pipeline 进流水线…其中 centraldashboard 匹配 /(根路径)= 兜底门户:没命中具体组件前缀的请求落到门户首页(Istio 按最长前缀优先匹配,/ 最宽所以天然垫底)。

⚠️ 易混点:不是"不同域名→不同路径",而是"同一个域名的不同路径→不同组件"。域名和路径是同一个 URL 的两半,分流是接力棒式的:

浏览器地址栏:  https://kubeflow-new.ergesanbaishou.com/jupyter/notebook1
               └──────────── 域名(host) ───────────┘└─ 路径(path)─┘

三棒接力(每棒只看自己那半):
① 公司 DNS     看"域名" → 解析到外层 NGINX 的 VIP
② 外层 NGINX   看"域名" → kubeflow-new.* → 30538 进门B(域名使命到此结束)
③ 门B 的 VS    看"路径" → /jupyter/ 命中 jupyter 那条 → jupyter-web-app-service

门B 里所有流量的域名都一样,变的只是路径:
  kubeflow-new.…/           → / (兜底)   → 门户首页
  kubeflow-new.…/jupyter/   → /jupyter/  → 笔记本
  kubeflow-new.…/katib/     → /katib/    → 调参
  kubeflow-new.…/pipeline   → /pipeline  → 流水线

"有相同的"解惑:HOSTS 列全 [*] 是真的全相同 —— 第③棒不看域名,通配一切;MATCH 列 9 个路径互不相同(都以 / 开头只是路径的标准写法),单独的 / 是最宽的兜底。比喻:域名决定去哪栋楼,路径决定进楼后去几号窗口。

💡 顺手的坑:缩写 vs 会触发 Warning —— 它还能匹配 volumesnapshots(存储快照)资源;kubectl 已自动选了高优先级的 virtualservices,确认意图即可,怕歧义可写全称 virtualservices。

05第④层:NS 分区地图(40+ namespace 全分类)

namespace 是 K8S 的"分区":资源隔离 + 权限边界 + 名字空间(同集群不同 ns 里可以有同名 Service)。线上 40+ 个 ns 按职能分成 12 类:

分区namespace干什么用
🏢 业务app / app-dev / app-uat / auth / on-premises / fke-profile业务应用三环境(dev/uat/prod)+ 认证 + 本地化服务
🗄️ 数据fke-db / fke-db-devMySQL 集群(mysql-operator InnoDB Cluster,community-server 8.4.7,每套库 3 实例起步)—— 详见 MySQL 文档 M1
🔌 中间件fke-middlewareMQ/缓存等通用中间件
🛠 CI/CDgitlab / jenkins-ci / argo / smart-ops-pipelines / code-server / pingcode代码托管、流水线、运维自动化
📦 镜像harbor私有镜像仓库 docker.ergesanbaishou.com(线上镜像都从这拉)—— 见 Harbor 文档
📊 可观测fke-monitor / fke-log监控(Prometheus 系)与日志采集
💾 存储longhorn-systemLonghorn 分布式块存储,业务 PVC 的底座(扩容实战见 问题总汇)
🕸 网格/入口istio-system / knative-serving / oauth2-proxy服务网格网关、serverless、统一认证
🤖 AI/MLkubeflow / kubeflow-components / datacollect-kubeflow / jobset-system / kubeflow-infra-ergesanbaishou-com机器学习平台、任务编排
🎥 音视频livekit / stunner / stunner-system实时音视频、WebRTC 打洞
⚙️ K8S 系统kube-system / kube-public / kube-node-lease / default / kube-infra / fke-infra-dev控制面与系统组件(别乱动)
🐄 Ranchercattle-system / cattle-impersonation-system / localRancher 管理面本体
💡 找东西的套路:不知道某服务在哪个 ns?—— sudo kubectl get svc -A | grep 关键字 一把梭;-A(all namespaces)是跨分区搜索的钥匙。

06逐层验证命令(fke 实操)

# ① DNS 层:域名解析到 VIP 了吗?
nslookup xxx.ergesanbaishou.com

# ② 入口层:NGINX 主备与 VIP(在 NGINX 机器上)
ip addr | grep <VIP>                    # VIP 当前漂在哪台(VIP 在谁身上谁就是 Master)
systemctl status nginx keepalived

# ③ 集群层:节点 / 双网关 / 路由
sudo kubectl get nodes -o wide
sudo kubectl get svc -A | grep ingress          # 双网关与 NodePort(ingress-nginx 在 kube-infra!)
sudo kubectl get ingress -A; sudo kubectl get gateway -A 2>/dev/null

# ④ NS 层:全景 / 定位服务 / 看某个分区
sudo kubectl get ns
sudo kubectl get svc -A | grep -i mysql        # 例:找所有数据库服务
sudo kubectl get pods,svc,deploy -n app        # 进业务区细看

# ⑤ 落到 Pod:与测试集群完全同款
sudo kubectl describe pod <pod名> -n <ns>
sudo kubectl logs <pod名> -n <ns> --tail=50
⚠ 权限与安全:线上命令都要 sudo,且只读优先。命令安全分级速查:
级别命令说明
🟢 随便跑(纯只读)get / describe / logs / top / get -o yaml / -A / custom-columns只查不改,连资源状态都不碰;custom-columns 只是控制"显示哪几列",零风险
🟡 谨慎(会触发行为)exec / port-forward / logs -f / 直连 curl 后端本质只读,但会连进 Pod/占端口;exec 里别敲重启类命令
🔴 必须先确认(写操作)apply / create / delete / edit / scale / patch / rollout / set直接改集群状态 —— 线上不是练手场,练手请回测试集群(qingfeng 单节点)

07测试环境 vs 线上 对照 & 待确认清单

维度测试(qingfeng 单节点)线上(fke)
集群形态1 节点,kubeadm 自建多节点,Rancher 管理
统一入口外层 NGINX 主从 + VIP外层 NGINX 主备 + VIP(同构)
七层网关ingress-nginx(NodePort 31588)双网关:ingress-nginx(kube-infra · 30080/30443)+ istio-gateway(30538/30539)
MySQLBitnami chart 1主1备(8.4.5)mysql-operator InnoDB Cluster(8.4.7,3 实例起步)
镜像源docker.io(bitnamilegacy 归档)私仓 docker.ergesanbaishou.com
存储本地默认 SCLonghorn 分布式存储
ns 数量个位数40+(12 类分区)
📋 待确认清单(确认后更新本文档):① VIP 值与 keepalived 配置(在 nginx-master 上 ip addr 可自查);② fke 完整节点清单与角色(已知节点 IP 段 10.18.51.x,至少 .2/.7/.8/.11/.16/.17/.20/.25/.26);③ DNS 服务器在哪管理。
✅ 已销项:入口网关走向(2026-10 实测)—— 门A 30080×6 节点(通用业务)+ 门B 30538×2 节点(仅 kubeflow),TLS 在外层终止,详见 04 节;原"入口是否 Istio"也已解决:双网关并存。