👤 浏览器 → ① 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
公司统一域名后缀 *.ergesanbaishou.com(如私仓 docker.ergesanbaishou.com)。域名并不直接指向 K8S 节点,而是指向外层 NGINX 的 VIP —— 这样 K8S 集群怎么扩缩、节点 IP 怎么变,域名永远不用改。
# 在办公网任一机器上验证解析
nslookup xxx.ergesanbaishou.com # 返回的 IP 应是 NGINX 的 VIP,而不是节点 IP
# 入口类 *.ergesanbaishou.com 域名通常都指向同一个 VIP —— 这就是"统一入口"的特征
两台 NGINX(一主一备)通过 keepalived 共享一个 VIP(虚拟 IP):平时 VIP 在 Master 上,Master 挂了 VIP 自动漂到 Backup,客户端无感知不断流。所有进入 K8S 的 HTTP(S) 流量先到这里,再 proxy_pass 转发到 K8S 节点的入口端口。
| 组件 | 职责 | 关键点 |
|---|---|---|
| NGINX-Master | 承接 VIP,反代到 K8S | keepalived 心跳互探;VIP 漂移秒级完成 |
| NGINX-Backup | 热备,Master 挂则接管 VIP | |
| VIP | 对外的"稳定 IP" | 域名解析到它,后端随便换 |
nginx -T 里还有大量直连物理机后端(192.168.3.x、10.18.x 各端口)的 proxy_pass,K8S 只是其后端之一;进 K8S 的流量统一走"节点 IP + NodePort"(30080/30538 两扇门),绝不会写 ClusterIP。完整实测见 04 节。proxy_set_header Host $host; —— 不透传域名,后端路由必 404。入口网关 = 集群的大门保安。外部流量不能随便打进某个 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 资源)
实测全集群只有一个 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 → 共用
两扇门殊途同归:域名匹配的是"路由规则",规则选中的是 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
destination.host。Istio 特例:VS 也能直连 Pod 或 ServiceEntry(外部服务),但主流用法仍是走 Service。fke-m1 …),登录跳板即 ssh fourier@fke-m1 后 sudo kubectl ...。cattle-system)—— 集群的"4S 店",网页化管理多集群。kube-infra 里的 nginx-ingress-nginx-controller(ingress-nginx,NodePort 30080/30443)—— 传统 Ingress 路由,与测试集群同款;istio-system 里的 istio-ingressgateway(NodePort 30538/30539,健康检查 15021:30542)—— 服务网格入口(Gateway/VirtualService),另有 knative(serverless)、oauth2-proxy(统一认证)辅助。| 网关 | namespace | Service | NodePort(实测) | 适用流量 |
|---|---|---|---|---|
| ingress-nginx | kube-infra | nginx-ingress-nginx-controller | 80:30080 · 443:30443 | 常规 Web / Ingress 规则 |
| Istio 网关 | istio-system | istio-ingressgateway | 80: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 本体
| IP 类型 | 示例 | 谁能访问 |
|---|---|---|
| ClusterIP | 10.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'
| 大门 | upstream 位置 | 节点池(实测) | 承载流量 |
|---|---|---|---|
| 门A nginx-ingress | conf.d 主配置 upstream nginx-ingress | 6 节点 × 30080 (10.18.51.7/.8/.16/.17/.25/.26) | 通用业务域名(多处 proxy_pass http://nginx-ingress) |
| 门B istio-ingress | istio-ingress-upstream.conf | 2 节点 × 30538 (10.18.51.8/.16) | 目前仅 kubeflow 域名(kubeflow-new.*) |
max_fails=3 fail_timeout=30s 被动摘除故障节点;门A 6 节点池比门B 2 节点池更抗节点故障。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。<Service名>.<ns>.svc.cluster.local 标准长格式(与 MySQL 文档 M5 的 DNS 公式同一套)。oauth2-proxy(统一认证代理)+ dex(OIDC 身份源)也在门B —— 外部请求先过认证链再到 kubeflow 各组件,这就是 oauth2-proxy / auth 两个 ns 的真实角色。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-dev | MySQL 集群(mysql-operator InnoDB Cluster,community-server 8.4.7,每套库 3 实例起步)—— 详见 MySQL 文档 M1 |
| 🔌 中间件 | fke-middleware | MQ/缓存等通用中间件 |
| 🛠 CI/CD | gitlab / jenkins-ci / argo / smart-ops-pipelines / code-server / pingcode | 代码托管、流水线、运维自动化 |
| 📦 镜像 | harbor | 私有镜像仓库 docker.ergesanbaishou.com(线上镜像都从这拉)—— 见 Harbor 文档 |
| 📊 可观测 | fke-monitor / fke-log | 监控(Prometheus 系)与日志采集 |
| 💾 存储 | longhorn-system | Longhorn 分布式块存储,业务 PVC 的底座(扩容实战见 问题总汇) |
| 🕸 网格/入口 | istio-system / knative-serving / oauth2-proxy | 服务网格网关、serverless、统一认证 |
| 🤖 AI/ML | kubeflow / 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 | 控制面与系统组件(别乱动) |
| 🐄 Rancher | cattle-system / cattle-impersonation-system / local | Rancher 管理面本体 |
sudo kubectl get svc -A | grep 关键字 一把梭;-A(all namespaces)是跨分区搜索的钥匙。# ① 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 单节点) |
| 维度 | 测试(qingfeng 单节点) | 线上(fke) |
|---|---|---|
| 集群形态 | 1 节点,kubeadm 自建 | 多节点,Rancher 管理 |
| 统一入口 | 外层 NGINX 主从 + VIP | 外层 NGINX 主备 + VIP(同构) |
| 七层网关 | ingress-nginx(NodePort 31588) | 双网关:ingress-nginx(kube-infra · 30080/30443)+ istio-gateway(30538/30539) |
| MySQL | Bitnami chart 1主1备(8.4.5) | mysql-operator InnoDB Cluster(8.4.7,3 实例起步) |
| 镜像源 | docker.io(bitnamilegacy 归档) | 私仓 docker.ergesanbaishou.com |
| 存储 | 本地默认 SC | Longhorn 分布式存储 |
| ns 数量 | 个位数 | 40+(12 类分区) |
ip addr 可自查);② fke 完整节点清单与角色(已知节点 IP 段 10.18.51.x,至少 .2/.7/.8/.11/.16/.17/.20/.25/.26);③ DNS 服务器在哪管理。