K8s 服务太多?一个 Ingress 全搞定 一、你肯定遇到过这个场景线上跑了 5 个微服务每个都要对外暴露。如果用 NodePort就需要给每个服务分配一个 30000 的端口前端配了一堆端口号运维在防火墙上开端口开到崩溃。再配上 TLS 证书每个服务单独配一遍重复劳动。说白了Service 的 NodePort 只解决**四层TCP/UDP**访问没有应用层路由能力。NodePort 范围固定在 30000-32767服务多了端口就不够用如果用 LoadBalancer云上每个 Service 都要买一个 CLB成本直线上升。这时候你需要的不是更多端口而是Ingress——K8s 里统一流量入口的七层负载均衡一个入口搞定所有微服务的域名路由、路径分发、TLS 终止。二、三个概念。1.概念很多人一开始把 Ingress、Ingress Controller、IngressClass 当成一回事其实三层分工明确概念是什么类比Ingress规则文件YAML定义哪个域名走哪个 Service菜单Ingress Controller真正干活的 Pod读取 Ingress 规则并执行厨师IngressClass标记这条规则给哪个 Controller 处理厨房编号核心逻辑你写 Ingress YAML → Ingress Controller 读到规则 → 更新内部 Nginx/Envoy 配置 → 流量按规则转发。2.常见的 Controller 选型Controller适用场景ingress-nginxk8s社区版最通用生态最全nginx-ingressNginx公司版需要商业支持Traefik自动发现、自带 DashboardIstio Gateway服务网格场景新手用 ingress-nginx 就够了。等等Ingress 是不是 K8s 自带的不是。Ingress 不是 Kubernetes 核心组件它是一个可选的 API 资源对象需要单独安装 Controller 才能工作。把它想象成集群的「智能路由器」或「门户守卫」——根据规则主机名、路径将请求分发到不同的后端 Service。只创建 Ingress YAML 不管用必须配合 Controller 一起部署。3.Ingress 和 Service 对比Ingress 和 Service 到底什么关系很多人一开始也迷糊看这张表就清楚了特性IngressService工作层七层HTTP/HTTPS四层TCP/UDP/SCTP路由能力按域名、路径、Header 匹配仅按端口和 ClusterIP协议支持HTTP、HTTPS、gRPC任意 TCP/UDP实现方式依赖 Ingress Controller Podkube-proxyiptables/IPVS或云 LB主要目的外部 HTTP 流量入口统一管理集群内部服务发现与负载均衡简单理解Service 负责把流量送进集群Ingress 负责把流量送到正确的 Service。两者是配合关系不是替代关系。三、从零搭一个 Ingress1. 安装 ingress-nginx Controller1.1 kubectl一键部署#先下载官方完整 YAMLwgethttps://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml-Onginx-deploy.yaml#修改部署nginx-deploy.yaml YAML 中的 image 字段registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.10.0 registry.aliyuncs.com/google_containers/kube-webhook-certgen:v1.4.0#修改service类型为 NodePort# type: LoadBalancertype: NodePort#修改deploy使用宿主机端口kind: Deployment... ports: - containerPort:80name: http hostPort:80protocol: TCP - containerPort:443name: https hostPort:443protocol: TCP#部署kubectl apply-fnginx-deploy.yaml部署文件里都装了些什么除了 Controller Deployment官方 YAML 还自动创建了 Namespace、ServiceAccount、Role/ClusterRole、ValidatingWebhook 等资源。其中 RBAC 权限是 Controller 能正常工作的前提——它需要通过 API Server 监听 Ingress 资源的变化# Controller 需要的完整 RBAC 权限官方 deploy.yaml 自动创建rules:# 监听 Ingress/IngressClass 变化- apiGroups:[networking.k8s.io]resources:[ingresses,ingressclasses]verbs:[get,list,watch]# 更新 Ingress 状态ADDRESS 字段- apiGroups:[networking.k8s.io]resources:[ingresses/status]verbs:[update]# 读取 Service/Endpoints/ConfigMap/Secret/Pod构建 upstream- apiGroups:[]resources:[services,endpoints,configmaps,pods,secrets,namespaces]verbs:[get,list,watch]这些权限覆盖了 Controller 的全部工作流发现 Ingress 规则 → 读取后端 Service/Endpoints → 更新 Nginx 配置 → 回写 Ingress 状态。如果权限不足Controller 日志会报forbiddenIngress 规则不会生效。1.2 使用 Helm 部署便于后续升级和回滚生产推荐添加仓库、拉取代码# 添加仓库 更新helm repoaddingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update#拉取代码[rootmaster-1 ingress]# helm pull ingress-nginx/ingress-nginx#内网环境可直接从外网下载https://github.com/kubernetes/ingress-nginx/releases/download/helm-chart-4.12.3/ingress-nginx-4.12.3.tgz修改关键配置# values.yaml 关键修改国内环境[rootmaster-1 ingress-nginx]# vim values.yamlglobal: image: registry: registry.aliyuncs.com controller: image: image: google_containers/nginx-ingress-controller tag:v1.10.0admissionWebhooks: patch: image: image: google_containers/kube-webhook-certgen tag: v1.4.0 hostPort: enabled:trueports: http:80https:443service: type: NodePort部署[rootmaster-1 ingress-nginx]# cd ../#部署ingress-nginx[rootmaster-1 ingress]# helm install ingress-nginx ingress-nginx -n ingress-nginx --create-namespace -f ingress-nginx/values.yaml#查看[rootmaster-1 ingress]# helm list -n ingress-nginxNAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION ingress-nginx ingress-nginx12025-07-0114:42:20.362166146 0800 CST deployed ingress-nginx-4.12.31.12.3如下图所示我们已经部署好了ingress controller补充helm常用命令#搜索ingress-nginx[rootmaster-1 ingress]# helm search repo ingress-nginxNAME CHART VERSION APP VERSION DESCRIPTION ingress-nginx/ingress-nginx4.12.31.12.3 Ingress controllerforKubernetes using NGINX a...# 下载ingress-nginx[rootmaster-1 ingress]# helm pull ingress-nginx/ingress-nginx#安装 ingress-nginx ingress-nginx 第一个是为ingress服务取名称为ingress-nginx第二个是目录名[rootmaster-1 ingress]# helm install ingress-nginx ingress-nginx -n ingress-nginx --create-namespace -f ingress-nginx/values.yaml#卸载 ingress-ngin[rootmaster-1 ingress]# helm uninstall ingress-nginx -n ingress-nginx⚠️部署前必查hostPort会占用宿主机的 80 和 443 端口。如果宿主机上已经跑了原生 Nginx、Apache 或其他 Web 服务Ingress Controller 会因端口冲突启动失败。先用ss -tlnp | grep -E :80 |:443 确认端口空闲再部署。2. 部署nginx应用# nginx.yamlapiVersion: apps/v1 kind: Deployment metadata: name: nginx-v1 spec: replicas:2#基于标签关联pod会关联envtest或者envprod的podselector: matchExpressions: - key:envvalues: -test-prodoperator: In template: metadata:#为pod设置了两个标签labels: app: nginx-v1 env:testspec: containers: - name: nginx-v1 image: nginx:1.22.1 imagePullPolicy: IfNotPresent --- apiVersion: v1 kind: Service metadata: name: nginx-service-v1 spec:# 指定svc的类型为NodePort也就是在默认的ClusterIP基础之上多监听所有worker节点的端口而已。type: NodePort# 基于标签选择器关联Podselector: app: nginx-v1# 配置端口映射ports:# 指定Service服务本身的端口号- port:80# 后端Pod提供服务的端口号targetPort:80同样方式部署nginx-v2标签和名称换成nginx-v2。3. 写 Ingress 规则# ingress.yamlapiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:my-ingressannotations:nginx.ingress.kubernetes.io/rewrite-target:/spec:ingressClassName:nginxrules:-host:nginx.liux.comhttp:paths:-path:/v1pathType:Prefixbackend:service:name:nginx-service-v1port:number:80-path:/v2pathType:Prefixbackend:service:name:nginx-service-v2port:number:80#ingressClassName: nginx 可以通过以下方式查看[rootmaster-1 ~]# kubectl get ingressclassesNAME CONTROLLER PARAMETERS AGE nginx k8s.io/ingress-nginx none31m#部署[rootmaster-1 ~]# kubectl apply -f nginx-route.yaml关键字段解释ingressClassName: nginx— 指定用 nginx Controller 处理host: nginx.liux.com— 只处理这个域名的请求path: /v1pathType: Prefix— 前缀匹配/v1/xxx全部命中rewrite-target: /— 去掉路径前缀再转发/v1/hello→/hello4. 验证# 查看 Ingress 状态kubectl get ingress# NAME CLASS HOSTS ADDRESS PORTS# my-ingress nginx app.example.com 192.168.1.x 80# 本地测试加 hosts 后curlhttp://nginx.liux.com/v1浏览器验证在本地/etc/hostsLinux/Mac或C:\Windows\System32\drivers\etc\hostsWindows中添加NodeIP nginx.liux.com浏览器访问http://nginx.liux.com/v1即可看到对应服务的返回页面。curl 能通但浏览器不通时优先检查本地 hosts 是否配置正确。四、三个进阶配置1.配置 TLSspec:#https相关tls:-hosts:-nginx.liux.comsecretName:liux-tls没有现成证书快速生成自签证书用于测试# 生成 365 天有效期的自签证书openssl req-x509-newkeyrsa:2048-nodes-keyouttls.key-outtls.crt-days365-subj/CNnginx.liux.com# 证书存入 Secretkubectl create secret tls liux-tls--certtls.crt--keytls.key# 确认 Secret 已创建kubectl get secret|grepliux-tls liux-tls kubernetes.io/tls254s完整 HTTPS 实战示例[rootmaster-1 nginx]# cat nginx-route.yaml# ingress.yamlapiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:my-ingressannotations:nginx.ingress.kubernetes.io/rewrite-target:/spec:ingressClassName:nginxrules:-host:nginx.liux.comhttp:paths:-path:/v1pathType:Prefixbackend:service:name:nginx-service-v1port:number:80-path:/v2pathType:Prefixbackend:service:name:nginx-service-v2port:number:80#https相关tls:-hosts:-nginx.liux.comsecretName:liux-tlskubectl apply-fnginx-route.yaml# 查看 Ingress确认同时暴露了 80 和 443 端口kubectl get ingress ingress-https浏览器访问https://nginx.liux.com/v1验证。如果浏览器提示证书不安全属于自签证书正常现象点击「继续访问」即可。4.2 路径重写最实用annotations:nginx.ingress.kubernetes.io/rewrite-target:/$2spec:rules:-host:nginx.liux.comhttp:paths:-path:/api(/|$)(.*)pathType:ImplementationSpecificbackend:service:name:user-serviceport:number:80效果/api/user→ 转发到 user-service 的/user。4.3 多域名分流rules:-host:nginx.liux.comhttp:paths:-path:/pathType:Prefixbackend:service:name:nginx-serviceport:number:80-host:api.liux.comhttp:paths:-path:/pathType:Prefixbackend:service:name:api-serviceport:number:80一个 Ingress 搞定多域名不用多开端口。五、实战场景微服务统一入口假设有一个典型的 web 应用架构前端页面Nginx 静态资源、后端 APIJava 服务、管理后台Admin三个服务架构图如下用户请求 │ ├─ app.liux.com/ → frontend (前端页面) ├─ app.liux.com/api → api (后端接口) └─ admin.liux.com/ → admin (管理后台)5.1 部署服务# 1. 部署前端kubectl create deployment frontend--imagenginx:1.22.1--replicas2kubectl expose deployment frontend--port80# 2. 部署后端 API 示例kubectl create deployment api--imageealen/echo-server--replicas1kubectl expose deployment api--port80# 3. 部署管理后台kubectl create deployment admin--imagenginx:1.22.1--replicas1kubectl expose deployment admin--port805.2 配置Ingress规则 统一接入# common-ingress.yamlapiVersion:networking.k8s.io/v1kind:Ingressmetadata:name:common-ingressannotations:# /api 路径转发时去掉 /api 前缀nginx.ingress.kubernetes.io/rewrite-target:/$2spec:ingressClassName:nginxrules:# 主域名前端 API-host:app.liux.comhttp:paths:-path:/pathType:Prefixbackend:service:name:frontendport:number:80-path:/api(/|$)(.*)pathType:ImplementationSpecificbackend:service:name:apiport:number:80# 子域名管理后台-host:admin.liux.comhttp:paths:-path:/pathType:Prefixbackend:service:name:adminport:number:80#部署kubectl apply-f common-ingress.yaml5.3 验证入口是否生效# 检查 Ingress ADDRESS 是否分配kubectl get ingress common-ingress NAME CLASS HOSTS ADDRESS PORTS AGE common-ingress nginx app.liux.com,admin.liux.com10.0.0.1458019s# 本地测试先配 hosts: nodeport app.example.com admin.example.comcurlhttp://app.liux.com/# → frontendcurlhttp://app.liux.com/api/users# → api转发为 /users# 重点验证路径重写# 请求 /api/users → api service 收到的是 /users# 或者直接看 Controller 日志kubectl logs-ningress-nginx deployment/ingress-nginx-controller--tail10可以看到三个微服务、两个域名、不同路径全部通过一个 Ingress 入口搞定不用暴露额外端口不用单独配负载均衡器。六、常见排坑坑1Ingress 配置了但访问 404# 先确认 Controller 是否在跑kubectl get pods-ningress-nginx# 检查 Ingress 规则是否被正确读取kubectl describe ingress my-ingress90% 的情况是pathType写错了Prefix和Exact行为完全不同。不确定就用Prefix。坑2rewrite-target 没生效确认注解写的是nginx.ingress.kubernetes.io/rewrite-target不是nginx.org/rewrite-target。两个是不同 Nginx 版本的前缀混用不生效。坑3TLS 证书配了但不生效# 检查 Secret 是否存在kubectl get secret app-tls-secret# 检查 Ingress 引用是否正确kubectl get ingress my-ingress-oyaml|grepsecretName另注意Secret 必须在同一个 namespace下才能被 Ingress 引用。坑4多个 Controller 互相抢流量如果集群里装了多个 Ingress Controller比如同时装了 nginx 和 traefik必须用ingressClassName明确指定不然流量随机跑到某个 Controller 上。七、总结回到最初的问题线上跑了 N 个微服务每个都要对外暴露怎么办Ingress 本质就是 K8s 的七层反向代理规则——你写规则Controller 执行。一个入口搞定域名路由、路径分发、TLS 终止不用给每个服务开端口、买负载均衡器。1.速查回顾环节关键操作一句话选型Ingress规则 Controller执行 Class标记新手直接ingress-nginx部署kubectl apply -f deploy.yaml或helm install提前确认 80/443 端口不冲突规则hostpathbackend.service写 YAML 绑定域名和路径到 ServiceTLStls.secretName引用 Secret测试用自签证书生产用 cert-managerrewriteannotationrewrite-target/api/xxx → /xxx注意/$2写法多域名同一 Ingress 写多条rules不同 host 走不同 Service验证curlkubectl logs看 Controller 日志路径不对先用ealen/echo-server照镜子2.落地清单装 Controller推荐ingress-nginxHelm 部署方便后续升级回滚部署业务确保 Pod Service 就绪后再建 Ingress写 Ingress 规则绑定域名和路径指定ingressClassName配置 TLS测试用openssl自签 →kubectl create secret tls→ Ingress 引用验证生效配好 hostscurl测试 → 浏览器确认 → 查 Controller 日志排坑优先级404 → 查pathTyperewrite 不生效 → 查 annotation 前缀TLS 不生效 → 查 Secret 是否同 namespace