K8s 系列 | 第 11 天:Ingress 与 Ingress Controller:外部流量接入全攻略


title: “K8s 系列 | 第 11 天:Ingress 与 Ingress Controller:外部流量接入全攻略”
tags:
– Kubernetes
– K8s系列
– DevOps
– Ingress
– 网络
– 负载均衡
– Nginx


第 11/30 天

引言

前几篇文章中,我们学习了 Service 的三种类型——ClusterIP、NodePort 和 LoadBalancer,它们分别解决了集群内部通信、节点端口暴露和云负载均衡的问题。然而在实际生产环境中,我们面对的是更复杂的场景:多个服务需要共用同一个公网入口需要基于域名和路径做流量分发需要 HTTPS 终止和 TLS 证书管理

这时候,Ingress 就登场了。

Ingress 是 Kubernetes 中一个至关重要的 API 资源,它充当着集群的「交通指挥中心」——所有来自外部的请求首先到达 Ingress,然后由它根据规则路由到对应的后端 Service。从一个朴实的企业站到日活千万的电商平台,Ingress 是 K8s 网络栈中不可或缺的一环。

本文将带你从零掌握 Ingress 的核心机制,通过实战部署 Nginx Ingress Controller,并覆盖 HTTPS、路径重写、速率限制等生产场景配置。

核心概念

什么是 Ingress?

Ingress 是 Kubernetes 的一层 API 资源,定义了从集群外部到内部服务的 HTTP(S) 路由规则。它本质上是一个第 7 层(应用层)负载均衡器——这意味着它能理解 HTTP 请求的域名、路径、Header 等信息,并据此做出路由决策。

Ingress vs Service(NodePort / LoadBalancer)

特性 NodePort LoadBalancer Ingress
层级 第 4 层(传输层) 第 4 层 第 7 层(应用层)
域名路由
路径路由
HTTPS 终止 ❌(需额外组件) ❌(需额外组件) ✅ 内置
多服务共享端口 ❌(每服务一个端口) ❌(每服务一个 LB) ✅(统一 80/443)
成本 低(需节点端口) 高(每个 LB 收费) 低(共享 Ingress Controller)

一句话总结:NodePort 和 LoadBalancer 让你「连得上」,Ingress 让你「连得对」。

Ingress Controller 的作用

Ingress 资源本身只是一个声明式规则——它描述了「什么域名/路径应该路由到哪个 Service」。真正执行这些规则的是 Ingress Controller ——一个运行在集群中的 Pod,负责监听 Ingress 资源的变化,并动态配置底层的反向代理(如 Nginx、Traefik、HAProxy 等)。

[Internet]
    │
    ▼
┌─────────────────────┐
│  Ingress Controller │  ← 监听 Ingress 资源,动态配置反向代理
│  (e.g., Nginx)      │
└────────┬────────────┘
         │
    ┌────┴────┐
    ▼         ▼
┌──────┐  ┌──────┐
│Svc A │  │Svc B │
│:8080 │  │:3000 │
└──────┘  └──────┘

主流 Ingress Controller 选型

产品 特点 适用场景
ingress-nginx 社区最成熟,功能全面,性能稳定 通用首选,中小规模集群
Traefik 自动发现服务,支持多种协议,Dashboard 可视化 微服务 + Service Mesh 场景
Kong 插件生态丰富(认证、限流、日志) API 网关需求强的企业
HAProxy 极致性能,内存占用低 高并发入口层(十万级 QPS)
ALB Ingress AWS 原生 LB,直接走云网络 AWS 全托管集群
APISIX 云原生 API 网关,低延迟 大规模微服务网关

对于大多数场景,ingress-nginx 是最稳妥的选择——它的社区最活跃、文档最完善、功能覆盖最全面。

实战步骤

1. 部署 Nginx Ingress Controller

使用官方 Helm Chart 部署是最推荐的方式:

# 添加 Helm 仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# 部署到 ingress-nginx 命名空间
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx 
  --namespace ingress-nginx --create-namespace 
  --set controller.service.type=NodePort 
  --set controller.service.nodePorts.http=30080 
  --set controller.service.nodePorts.https=30443

如果你没有 Helm,也可以直接用 YAML 文件部署:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.1/deploy/static/provider/baremetal/deploy.yaml

验证部署状态:

kubectl get pod -n ingress-nginx -w
# 等待所有 Pod 处于 Running 状态

kubectl get svc -n ingress-nginx
# NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
# ingress-nginx-controller             NodePort    10.96.123.45    <none>        80:30080/TCP,443:30443/TCP
# ingress-nginx-controller-admission   ClusterIP  10.96.67.89     <none>        443/TCP

2. 创建一个测试应用

我们先部署一个简单的 Web 应用来测试 Ingress 路由功能:

# web-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: web-app-svc
  namespace: default
spec:
  selector:
    app: web-app
  ports:
  - port: 80
    targetPort: 80
# api-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-app
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api-app
  template:
    metadata:
      labels:
        app: api-app
    spec:
      containers:
      - name: api
        image: hashicorp/http-echo:latest
        args:
        - "-text=Hello from API Service"
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: api-app-svc
  namespace: default
spec:
  selector:
    app: api-app
  ports:
  - port: 80
    targetPort: 5678

部署应用:

kubectl apply -f web-app.yaml
kubectl apply -f api-app.yaml

3. 创建 Ingress 规则——基于路径的路由

现在我们来创建第一个 Ingress 资源:根据请求路径 /web/api 分别路由到不同的后端服务:

# ingress-path.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-based-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /   # 路径重写
spec:
  ingressClassName: nginx
  rules:
  - host: k8s-demo.local
    http:
      paths:
      - path: /web
        pathType: Prefix
        backend:
          service:
            name: web-app-svc
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-app-svc
            port:
              number: 80
kubectl apply -f ingress-path.yaml

验证 Ingress 状态:

kubectl get ingress
# NAME                 CLASS   HOSTS             ADDRESS          PORTS   AGE
# path-based-ingress   nginx   k8s-demo.local    <ingress-ip>     80      10s

测试路由(假设 Ingress Controller 运行在 node-1 的 30080 端口):

# 测试 /web 路径 -> 应返回 Nginx 默认页面
curl -H "Host: k8s-demo.local" http://node-1-ip:30080/web

# 测试 /api 路径 -> 应返回 "Hello from API Service"
curl -H "Host: k8s-demo.local" http://node-1-ip:30080/api

4. 基于域名的路由

在同一集群中,你可能需要为不同的域名提供不同的服务。下面示范基于域名 app.example.comapi.example.com 的路由:

# ingress-host.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: host-based-ingress
  namespace: default
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-app-svc
            port:
              number: 80
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-app-svc
            port:
              number: 80
kubectl apply -f ingress-host.yaml

测试:

curl -H "Host: app.example.com" http://node-1-ip:30080/
# -> Nginx 默认页面

curl -H "Host: api.example.com" http://node-1-ip:30080/
# -> "Hello from API Service"

5. 配置 HTTPS(TLS 终止)

生产环境必不可少的一步——为 Ingress 配置证书,实现 HTTPS 访问。这里我们使用自签名证书做演示,生产环境请使用 Let’s Encrypt + cert-manager 自动签发。

# 生成自签名证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048 
  -keyout tls.key -out tls.crt 
  -subj "/CN=k8s-demo.local/O=K8s Demo"

# 创建 Secret
kubectl create secret tls k8s-demo-tls 
  --cert=tls.crt --key=tls.key 
  -n default

# 验证
kubectl get secret k8s-demo-tls -n default

创建带 TLS 的 Ingress:

# ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - k8s-demo.local
    secretName: k8s-demo-tls
  rules:
  - host: k8s-demo.local
    http:
      paths:
      - path: /web
        pathType: Prefix
        backend:
          service:
            name: web-app-svc
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-app-svc
            port:
              number: 80
kubectl apply -f ingress-tls.yaml

# 测试 HTTPS
curl -k -H "Host: k8s-demo.local" https://node-1-ip:30443/web
# -k 表示忽略自签名证书警告

6. 高级配置:速率限制与白名单

Nginx Ingress Controller 提供了丰富的 Annotation 来控制流量行为:

# ingress-advanced.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: advanced-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    # 速率限制:每分钟 10 个请求
    nginx.ingress.kubernetes.io/limit-rpm: "10"
    # 请求体最大 10M
    nginx.ingress.kubernetes.io/proxy-body-size: 10m
    # 允许的源 IP(白名单)
    nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,192.168.0.0/16"
    # 启用 CORS
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
    # 连接超时
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: app-tls
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-app-svc
            port:
              number: 80

常见问题

1. Ingress 创建后没有生效(404)

现象:创建 Ingress 后访问返回 404,或 kubectl get ingress 的 ADDRESS 字段为空。

排查步骤

# 1. 确认 Ingress Controller Pod 是否运行
kubectl get pod -n ingress-nginx

# 2. 查看 Ingress Controller 日志
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx

# 3. 检查 Ingress 事件
kubectl describe ingress path-based-ingress

# 4. 确认 ingressClassName 是否正确匹配
kubectl get ingressclass

常见原因
– Ingress Controller 未部署或启动中
ingressClassName 不匹配(默认类名可能是 nginx 而非 nginx-ingress
– Ingress 所在 Namespace 没有对应的后端 Service

2. 路径重写规则不生效

现象/web 请求到达后端变成了 /web/index.html,而非预期的 /index.html

解决方案:正确使用 rewrite-target annotation。当 path: /webrewrite-target: / 时,请求路径中的 /web 前缀会被剥离:

metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /

如果需要更复杂的重写,可以用 use-regex + 正则捕获组:

metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /api(/|$)(.*)
        pathType: ImplementationSpecific

3. HTTPS 配置后证书不生效

现象:配置了 TLS Secret 后仍跳转到不安全的页面。

排查

# 检查 Secret 是否存在且格式正确
kubectl describe secret k8s-demo-tls -n default

# 检查 Ingress 的 TLS 配置
kubectl get ingress tls-ingress -o yaml | grep -A 10 tls

# 强制 HTTP → HTTPS 重定向
# 添加 annotation:
# nginx.ingress.kubernetes.io/ssl-redirect: "true"

4. 生产环境如何自动管理证书?

手动管理证书显然不可持续。最佳实践是使用 cert-manager + Let’s Encrypt 实现自动签发和续期:

# 安装 cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.0/cert-manager.yaml

# 创建 ClusterIssuer(全局证书签发者)
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
    - http01:
        ingress:
          class: nginx
EOF

# 在 Ingress 中添加 cert-manager annotation 即可自动签发
# cert-manager.io/cluster-issuer: "letsencrypt-prod"

总结

在本文中,我们深入探讨了 Ingress 的核心概念和在 Kubernetes 中管理外部流量的完整工作流:

知识点 要点
Ingress 是什么 第 7 层路由规则,按域名/路径分发流量
Ingress Controller 真正执行路由规则的组件,ingress-nginx 是最主流的选择
路由方式 基于路径(Prefix/Exact)和基于域名(Host)
HTTPS 配置 通过 TLS Secret 实现 SSL 终止
高级功能 速率限制、CORS、白名单、路径重写
生产实践 cert-manager 自动签发证书、Helm 部署管理

Ingress 让你的 K8s 集群拥有了一个「智能入口」——它不仅是流量路由的工具,更是安全策略、访问控制和流量治理的统一控制面。掌握 Ingress,意味着你已经从「能用 K8s 跑应用」进阶到了「能构建生产级入口架构」。


下期预告

第 12 天:NetworkPolicy:K8s 网络安全策略与微隔离

学习了 External → Cluster 的入口控制后,下一篇文章将转向集群内部的「微隔离」——NetworkPolicy 如何用声明式的方式定义 Pod 之间的网络访问规则,实现真正的零信任网络安全模型。


📚 系列目录(持续更新中)**

天数 标题 状态
第 1 天 Kubernetes 是什么?核心概念与架构全景解析 ✅ 已发布
第 2 天 手把手搭建你的第一个 K8s 集群(kubeadm 实战) ✅ 已发布
第 3 天 Pod 详解:K8s 最小的调度单元与生命周期管理 ✅ 已发布
第 4 天 Deployment 与 ReplicaSet:声明式应用管理 ✅ 已发布
第 5 天 Service 与网络基础:ClusterIP、NodePort、LoadBalancer 详解 ✅ 已发布
第 6 天 Namespace 与资源配额:多租户隔离基础 ✅ 已发布
第 7 天 ConfigMap 与 Secret:配置管理最佳实践 ✅ 已发布
第 8 天 Volume 与 PersistentVolume:存储抽象层的核心机制 ✅ 已发布
第 9 天 StorageClass 与动态存储供给实战 ✅ 已发布
第 10 天 StatefulSet:有状态应用的部署与管理 ✅ 已发布
第 11 天 Ingress 与 Ingress Controller:外部流量接入全攻略 📝 本文
第 12 天 NetworkPolicy:K8s 网络安全策略与微隔离 🔜 即将发布
第 13 天 Headless Service 与服务发现机制深度解析 🔜 即将发布
第 14 天 CSI 存储插件与生产存储选型指南 🔜 即将发布
第 15 天 污点与容忍度:掌控 Pod 调度 🔜 即将发布
第 16 天 Node Affinity 与 Pod Affinity:精细化调度策略实战 🔜 即将发布
第 17 天 HPA 水平自动扩缩:基于 CPU/内存/自定义指标的弹性伸缩 🔜 即将发布
第 18 天 VPA 与 Cluster Autoscaler:资源与集群层的自动扩缩 🔜 即将发布
第 19 天 Job 与 CronJob:批处理与定时任务实战 🔜 即将发布
第 20 天 PriorityClass 与抢占式调度机制 🔜 即将发布
第 21 天 资源配额与 LimitRange:多租户资源管控 🔜 即将发布
第 22 天 监控体系搭建:Prometheus + Grafana + Kube-state-metrics 🔜 即将发布
第 23 天 日志收集实战:EFK/ELK 栈在 K8s 中部署 🔜 即将发布
第 24 天 RBAC 权限控制:ServiceAccount、Role、ClusterRole 深度解析 🔜 即将发布
第 25 天 Helm Charts:包管理器使用与 Chart 开发实战 🔜 即将发布
第 26 天 集群备份与恢复:etcd 快照 + Velero 方案 🔜 即将发布
第 27 天 滚动更新与回滚策略:实现零停机发布 🔜 即将发布
第 28 天 集群升级最佳实践:Control Plane 与 Node 升级步骤 🔜 即将发布
第 29 天 多集群管理:Federation / Cluster API / 多集群服务网格 🔜 即将发布
第 30 天 K8s 生产环境踩坑实录:性能调优、故障排查与最佳实践 🔜 即将发布
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容