前言

Kubernetes 中,Ingress 是管理外部流量接入集群内部服务的核心组件,通过统一入口,依据主机名和 URL 路径将流量路由到不同 Service,简化外部访问复杂度。其功能实现依赖 Ingress 规则(定义路由策略)和 Ingress Controller(执行路由逻辑)的协同。

1 Igress 的概念

  • Ingress 是解决外部流量如何接入集群内部服务这一问题的核心组件之一
  • 作为统一流量入口,根据请求的 主机名(Host)URL 路径,将流量智能地路由到不同的 Service
  • 简化外部访问的复杂性

2 Igress 的组成

Ingress 的实现依赖于两个协同工作的部分:

  1. Ingress(规则定义)
    • YAML 配置的 API 对象,定义请求如何转发到 service 的规则
    • 能提供:外部 URL、负载均衡、SSL/TLS、基于域名的反向代理
    • 具体功能需 Ingress Controller 实现
  2. Ingress Controller(规则执行)
    • 接收外部流量,并根据 Ingress 规则进行负载均衡反向代理
    • 一个 Pod 内同时运行守护进程(监控集群并生成配置)与反向代理程序(如 Nginx)

3 Igress 的工作原理

  1. Ingress Controller 与 APIServer 交互,动态的去感知 Ingress 规则变化;
  2. 读取规则并按自定义模板生成配置文件(如 Nginx)
  3. 再写到nginx-ingress-controller的pod里,这个ingress-controller的pod里运行着一个Nginx服务,控制器会把生成的 nginx配置写入 /etc/nginx.conf文件中
  4. 执行 reload 使配置生效,实现按域名分流与动态更新。

4 部署 Ingress-Controller

以下示例以 ingress-nginx 为例,展示多种对外暴露方式。

4.1 准备与获取清单

mkdir -p /opt/ingress && cd /opt/ingress

# 官方:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.25.0/deploy/static/mandatory.yaml

# 国内镜像:
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.25.0/deploy/static/mandatory.yaml
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/mandatory.yaml

说明:mandatory.yaml文件中包含了很多资源的创建,包括namespace、ConfigMap、role,ServiceAccount等等所有部署ingress-controller需要的资源。。

4.2 修改 ClusterRole 资源配置

mandatory.yaml 中将 Ingress 资源权限加入 networking.k8s.io(0.25 版本开始):

vim mandatory.yaml
------------------------------------------------------------------------------------------------------------
# RBAC相关资源从1.17版本开始改用rbac.authorization.k8s.io/v1,rbac.authorization.k8s.io/v1beta1在1.22版本即将弃用
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: nginx-ingress-clusterrole
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - "extensions"
      - "networking.k8s.io"    # (0.25版本)增加 networking.k8s.io Ingress 资源的 api 
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
  - apiGroups:
      - "extensions"
      - "networking.k8s.io"   # (0.25版本)增加 networking.k8s.io/v1 Ingress 资源的 api 
    resources:
      - ingresses/status
    verbs:
      - update

5 Ingress 暴露服务的三种方式***

方式适用场景核心优势关键依赖
Deployment + LoadBalancer公有云生产环境、高可用需求云厂商托管负载均衡、自动容错云平台 LoadBalancer 支持
DaemonSet + HostNetwork + nodeSelector私有集群、高性能需求、边缘节点部署低延迟、网络路径短节点标签管理、端口独占
Deployment + NodePort测试环境、小规模集群、无负载均衡器通用兼容、部署简单节点网络可达性

5.1 数据流向

在这里插入图片描述

5.2 Deployment + LoadBalancer

  • 适合公有云:LB 自动创建并绑定公网;将域名解析指向该地址即可对外暴露。

    详细:如果要把ingress部署在公有云,那用这种方式比较合适。用Deployment部署ingress-controller,创建一个 type为 LoadBalancer 的 service 关联这组 pod。大部分公有云,都会为 LoadBalancer 的 service 自动创建一个负载均衡器,通常还绑定了公网地址。 只要把域名解析指向该地址,就实现了集群服务的对外暴露

5.3 DaemonSet + HostNetwork + nodeSelector

  • 特定节点DaemonSet 方式部署 Controller,并使用 HostNetwork 与宿主机网络打通;

  • 直接占用宿主机 80/443

  • 链路最短、性能最好;一个 node 仅能运行一个 Controller Pod;适合大并发生产

    详解:用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。 比较适合大并发的生产环境使用。
    
5.3.1 选择指定节点运行
# 给 node 打标签,仅在 node02 运行
kubectl label node node02 ingress=true
kubectl get nodes --show-labels
5.3.2 设置配置
  1. 命名空间:创建了独立的 ingress-nginx 命名空间,隔离 Ingress 相关资源

  2. 配置存储:ConfigMap 管理核心配置文件

  3. 权限控制:绑定 ClusterRole 和 Role 授予控制器访问集群资源(如 Ingress、Service、Pod 等)的权限

  4. 控制器部署

    • DaemonSet 确保每个节点运行一个控制器(若指定,则仅在该指定节点上添加控制器)

    • 开启 hostNetwork: true,直接使用宿主机网络,便于接收外部流量。

    • 通过 nodeSelector: ingress: "true" 限制仅在标记为 ingress: true 的节点上运行

vim mandatory.yaml
------------------------------------------------------------------------------------------------------------
...
apiVersion: apps/v1
# 修改 kind
# kind: Deployment
kind: DaemonSet
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
# 删除Replicas
# replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
    spec:
      # 使用主机网络
      hostNetwork: true
      # 选择节点运行
      nodeSelector:
        ingress: "true"
      serviceAccountName: nginx-ingress-serviceaccount
......
5.3.3 加载镜像
# 在所有 node 上传镜像并加载
cd /opt/ingress

# 假设已有压缩包 ingree.contro.tar.gz
tar zxvf ingree.contro.tar.gz
docker load -i ingree.contro.tar
5.3.4 启动 Ingress Controller
# 创建配置
kubectl apply -f mandatory.yaml

# 查看
kubectl get pod -n ingress-nginx -o wide
kubectl get cm,daemonset -n ingress-nginx -o wide
netstat -lntp | grep nginx
# 期望监听:80 / 443 / 8181 / 10254

说明:8181 为默认 backend 端口(未匹配到规则时流量进入此处)。若需高可用,可在多节点部署,并在前面加 LVS + keepalived 做负载均衡。

5.3.5 部署服务
# 创建一个 Deployment 和 svc
vim service-nginx.yaml
------------------------------------------------------------------------------------------------------------
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-app-svc
spec:
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  selector:
    app: nginx
5.3.6 创建 Ingress 规则
vim ingress-app.yaml
------------------------------------------------------------------------------------------------------------
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-app-ingress
spec:
  rules:
  - host: www.benet.com
    http:
      paths:
      - path: /
        pathType: Prefix  # 也可使用 Exact
        backend:
          service:
            name: nginx-app-svc
            port:
              number: 80

路径匹配:

  • Prefix:基于前缀匹配,如 /ky37 可匹配 /ky37/ky37/xyk/ky37/xyk/xz
  • Exact:完全匹配,如 /ky39 只能匹配 /ky39
5.3.7 测试
kubectl apply -f service-nginx.yaml
kubectl apply -f ingress-app.yaml
kubectl get ingress
# /etc/hosts 添加解析:
# 192.168.10.21 www.benet.com
curl www.benet.com

可进入 Controller Pod 查看生成的 /etc/nginx/nginx.conf,确认 server www.benet.com 段落

5.4 Deployment + NodePort

  • 以 Deployment 部署 Controller,并创建 NodePort Service 暴露
  • 由于 NodePort 是随机端口,通常前置一层负载均衡
  • 多一层 NAT,大流量场景可能影响性能
5.4.1 设置配置
  1. 命名空间:创建了独立的 ingress-nginx 命名空间,隔离 Ingress 相关资源
  2. 配置存储:ConfigMap 管理核心配置文件
  3. 权限控制:绑定 ClusterRole 和 Role 授予控制器访问集群资源(如 Ingress、Service、Pod 等)的权限
  4. 控制器部署:通过 Deployment 控制器来控制 Ingress-Controller
# 创建目录
mkdir -p /opt/ingress-nodeport && cd /opt/ingress-nodeport

# 清单获取
// 官方下载地址:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

# 或国内镜像:
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/mandatory.yaml
wget https://gitee.com/mirrors/ingress-nginx/raw/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

# 在所有 node 节点上传镜像包 ingress-controller-0.30.0.tar 到 /opt/ingress-nodeport 目录,并加载镜像
docker load -i ingress-controller-0.30.0.tar

# 启动 Controller 与 NodePort Service
kubectl apply -f mandatory.yaml
kubectl apply -f service-nodeport.yaml

------------------------------------------------------------------------------------------------------------
#如果K8S Pod 调度失败,在 kubectl describe pod资源时显示:
# Warning  FailedScheduling  ...  didn't match node selector
# 解决:

# 1) 按 YAML 中的 nodeSelector 给节点加标签
kubectl label nodes <node_name> kubernetes.io/os=linux

# 2) 或删除 YAML 中的 nodeSelector
kubectl get pod,svc -n ingress-nginx
5.4.2 部署服务 和 制定ingress规则
vim ingress-nginx.yaml
------------------------------------------------------------------------------------------------------------
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
spec:
  replicas: 2
  selector:
    matchLabels:
      name: nginx
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    name: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-test
spec:
  rules:
  - host: www.benet.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-svc
            port:
              number: 80

部署与测试:

kubectl apply -f ingress-nginx.yaml
kubectl get svc -n ingress-nginx
# 假设 NodePort 为 80:32383/TCP
# hosts 添加:192.168.10.21 www.benet.com
curl http://www.benet.com:32383

可以在两个 Pod 内修改 index.html 以区分返回:this is web1/web2

5.4.3 示例:HTTPS 代理访问
# 创建目录
mkdir -p /opt/ingress-nodeport/https && cd /opt/ingress-nodeport/https

# 生成自签证书
openssl req -x509 -sha256 -nodes -days 365 \
  -newkey rsa:2048 -keyout tls.key -out tls.crt \
  -subj "/CN=nginxsvc/O=nginxsvc"

# 创建 secret
kubectl create secret tls tls-secret --key tls.key --cert tls.crt

# 以 yaml 格式查看
kubectl get secret tls-secret -o yaml

vim ingress-https.yaml
------------------------------------------------------------------------------------------------------------
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
spec:
  replicas: 2
  selector:
    matchLabels:
      name: nginx
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc-01
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  selector:
    name: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-https
spec:
  tls:
    - hosts:
      - www3.benet.com
      secretName: tls-secret
  rules:
    - host: www3.benet.com
      http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: nginx-svc-01
              port:
                number: 80
 
kubectl apply -f ingress-https.yaml

kubectl get svc -n ingress-nginx
NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.96.67.119   <none>        80:32383/TCP,443:32133/TCP   3h41m

测试:

# NodePort 假设 443:32133
# hosts 添加:192.168.10.21 www3.benet.com
# 浏览器访问:https://www3.benet.com:32133

示例:BasicAuth 认证

# 创建目录
mkdir -p /opt/ingress-nodeport/basic-auth && cd /opt/ingress-nodeport/basic-auth

# 生成 basic auth 文件(文件名需为 auth)
yum -y install httpd
htpasswd -c auth zhangsan

# 存为 secret
kubectl create secret generic basic-auth --from-file=auth

vim ingress-auth.yaml
------------------------------------------------------------------------------------------------------------
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-auth
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - zhangsan'
spec:
  rules:
  - host: auth.benet.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-svc
            port:
              number: 80

参考:https://kubernetes.github.io/ingress-nginx/examples/auth/basic/

示例:重写(Rewrite)

  • 常用注解:
    • nginx.ingress.kubernetes.io/rewrite-target: <字符串>:重定向目标 URI(必填)
    • nginx.ingress.kubernetes.io/ssl-redirect: <bool>:是否仅允许 SSL(Ingress 含证书时默认 true
    • nginx.ingress.kubernetes.io/force-ssl-redirect: <bool>:即使未启用 TLS 也强制跳转 HTTPS
    • nginx.ingress.kubernetes.io/app-root: <字符串>:定义应用根路径重定向
    • nginx.ingress.kubernetes.io/use-regex: <bool>:路径是否使用正则
vim ingress-rewrite.yaml
------------------------------------------------------------------------------------------------------------
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-rewrite
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: http://www1.benet.com:32383
spec:
  rules:
  - host: re.benet.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          # 仅用于跳转,svc 名可随意
          service:
            name: nginx-svc
            port:
              number: 80

测试:

# hosts 添加:192.168.10.21 re.benet.com
# 浏览器访问:http://re.benet.com:32383

6 总结

Ingress 作为 K8s 流量网关,通过规则与控制器协作,实现外部流量的统一接入、分流和负载均衡。
三种部署方式各有适用场景:

  • Deployment + LoadBalancer:适合公有云生产环境,依赖云厂商负载均衡服务,高可用且易维护。
  • DaemonSet + HostNetwork + nodeSelector:适用于私有集群或高性能需求场景,链路短、性能好,需节点标签管理。
  • Deployment + NodePort:适合测试或小规模集群,部署简单,大流量场景可能影响性能,通常需前置负载均衡。

此外,Ingress 还支持 HTTPS 配置、身份认证、路径重写等实用功能,满足多样化流量管理需求。

更多推荐