2-Ingress

1、ingress概述

  • 通常情况下, Service和Pod仅可在集群内部网络中通过IP地址访问,Ingress是建立在Service之上的7层访问入口,它支持通过URL的方式将Service暴露到k8s集群外
  • 通过配置,Ingress 可为 Service 提供外部可访问的 URL、对其流量作负载均衡、 终止 SSL/TLS,以及基于名称的虚拟托管等能力。 Ingress 控制器 负责完成 Ingress 的工作,具体实现上通常会使用某个负载均衡器, 不过也可以配置边缘路由器或其他前端来帮助处理流量。
  • Ingress 不会随意公开端口或协议。 将 HTTP 和 HTTPS 以外的服务开放到 Internet 时,通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 类型的 Service。
  • ingress需要和service在同一个命名空间

image

Ingress应用场景

  • 作为集群的单一入口点,实现负载均衡和路由
  • 假设有一个 Kubernetes 集群运行着多个微服务,包括前端 Web 应用、API 服务和后端数据库。通过创建一个 Ingress 资源,可以统一管理这些服务的外部访问,将所有流量路由到适当的后端服务。
  • 对于基于HTTP的服务来说,不同的URL地址经常对应到不同的后端服务或者虚拟服务器(Virtual Host),这些应用层的转发机制仅通过Kubernetes的Service机制是无法实现的。从Kubernetes 1.1版本开始新增Ingress资源对象,用于将不同URL的请求转发到后端不同的Service,以实现HTTP层的业务路由机制。
  • 在实际生产中,一个网站的服务往往是由不同的Service提供服务的。而每个Service通常又采用LoadBalance的方式提供服务,这就需要为每个Service提供自己的负载均衡器,以及独有的公网IP。使用Ingress只需要一个公网IP就能为许多服务提供访问,当客户端向Ingress发送请求时,Ingress会根据请求的主机名和路径决定请求转发到的Service

Ingress 工作原理

  • ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化,然后读取它,按照ingress中自定义的规则,规则写明了哪个域名对应哪个service,生成一段nginx配置,再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中,然后reload一下使配置生效。以此达到域名分配置和动态更新的问题。

ingressclass

  • ingressclass用于在集群内有多个ingress controller时候,区分ingress由谁处理

2、实现ingress

  • 使用Ingress实现一个完整的七层负载均衡器,需要两步:
    • 安装Ingress Controller。
    • 定义一个Ingress资源对象,用来关联需要暴露出去的Pod的Service。
  • 必须有一个Ingress Controller才能满足Ingress的要求。仅创建Ingress资源本身没有任何效果。
    • ingress controller:使用ingress resources提供的规则将客户端请求转发。默认是nginx
    • ingress resources:Ingress资源对象,用来关联需要暴露出去的Pod的Service

2.1、安装ingress controller

  • 在定义Ingress策略之前,需要先部署Ingress Controller,以实现为所有后端Service都提供一个统一的入口。
       - Ingress Controller需要实现基于不同HTTP URL向后转发请求,并可以灵活设置7层负载分发策略。
       - 如果公有云服务商能够提供该类型的HTTP路由LoadBalancer,则也可设置其为Ingress Controller。
  • 在Kubernetes中,Ingress Controller将以Pod的形式运行,监控API Server的/ingress接口后端的backend services,如果Service发生变化,则Ingress Controller应自动更新其转发规则。
  • ingress controller就是一个或一组拥有七层代理能力或调度能力的应用程序的pod。
  • 要安装的Ingress Controller是ingress-nginx-controller。

1、下载ingress-nginx-controller

官网:https://github.com/kubernetes/ingress-nginx
下载并解压 ingress-nginx-controller-v1.0.4.zip ,获取yaml文件
ingress-nginx-controller-v1.0.4\deploy\static\provider\baremetal\deploy.yaml
修改相应配置,省略

2、安装ingress-nginx-controller

kubectl apply -f ingress-nginx-controller-v1.0.4.yaml
kubectl get pods -o wide -A
kubectl get svc -o wide -A

3、访问ingress-nginx-controller

  • 四个请求的返回值是一样的,都是404,因为还没有后端服务。
// 通过serviceIP访问
curl http://10.20.234.166:80
curl -k https://10.20.234.166:443

// 通过nodeIP访问
curl http://10.1.1.11:32080
curl -k https://10.1.1.11:32443

2.2、创建Ingress

  • 创建一个单一规则的Ingress
cat <<EOF>> my-ingress.yaml
apiVersion: networking.k8s.io/v1  # 替换为稳定版 API
kind: Ingress
metadata:
  name: my-ingress
  # 可选:如果使用 NGINX Ingress Controller,可添加注解(根据需要调整)
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /  # 路径重写(根路径可省略)
spec:
  rules:
  - host: ingress.example.com  # 映射的域名(需确保DNS解析到Ingress Controller的IP)
    http:
      paths:
      - path: /                # 匹配的请求路径
        pathType: Prefix       # 路径匹配类型(Prefix=前缀匹配,Exact=精确匹配)
        backend:
          service:             # v1版本用service替代旧的backend结构
            name: my-service   # 目标Service名称
            port:
              number: 80       # 目标Service端口号
  # 可选:如果需要默认后端(无匹配host时),可添加
  # defaultBackend:
  #   service:
  #     name: default-service
  #     port:
  #       number: 80
EOF

kubectl apply -f my-ingress.yaml
  • 通过http://ingress.example.com访问服务,需要确保域名解析为Ingress控制器的IP
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    # 启用日志记录
    nginx.ingress.kubernetes.io/enable-access-log: "true"
    nginx.ingress.kubernetes.io/access-log-path: /var/log/nginx/access.log
    # 配置CORS允许的来源
    nginx.ingress.kubernetes.io/cors-allow-origin: "http://example.com"
    # 配置自定义错误页面
    nginx.ingress.kubernetes.io/custom-http-errors: "404,503"
    nginx.ingress.kubernetes.io/custom-http-errors-404: /errors/404.html
    nginx.ingress.kubernetes.io/custom-http-errors-503: /errors/503.html
spec:
  # 定义Ingress规则
  rules:
    # 单一入口点
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
    # 路径和域名路由
  - host: example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
    # 负载均衡
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: backend-service
            port:
              number: 80
  # 配置TLS/SSL终结
  tls:
  - hosts:
    - example.com
    secretName: tls-secret
  # 配置自定义错误页面
  - http:
      paths:
      - path: /oldpath
        pathType: Prefix
        backend:
          service:
            name: redirect-service
            port:
              number: 80
  # 基于主机名的虚拟主机
  - host: subdomain.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: subdomain-service
            port:
              number: 80
  # 认证和授权
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: auth-service
            port:
              number: 80

4、Ingress规则

kubectl explain ingress.spec.rules
  • 每个rules都包含以下字段

host字段

  • host可以是精确匹配(例如 “foo.bar.com”)或者使用通配符来匹配 (例如 “*.foo.com”)。
  • 精确匹配要求 HTTP host 头部字段与 host 字段值完全匹配。 通配符匹配则要求 HTTP host 头部字段与通配符规则中的后缀部分相同。
  • 图片示例

image

  • yaml示例
  • ingress.spec.rules.host没有下级结构了,和http是平级
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
              number: 80

http字段

  • 可以不指定host字段,这时相当于通过指定IP地址接收所有HTTP的请求。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
spec:
  ingressClassName: nginx-example
  rules:
  - http:        # 没有指定host,直接使用http
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80

5、ingress路径

  • ingress.rules.http.paths 结构下有以下几个字段:backend、path、pathType

5.1、backend

  • backend有2种类型,resource和service
  • resource和service不能同时指定
kubectl explain ingress.spec.rules.http.paths.backend

1、resource

  • resouce的一个使用场景是Ingress 规则复用 / 分层管理
  • 比如集群中有多个子服务,每个子服务都有自己的 Ingress 规则(如 service-a-ingress、service-b-ingress)。你想做一个「总入口 Ingress」,把不同路径的请求转发到对应的子 Ingress,而非直接转发到 Service,这样可以分层管理规则,避免单个 Ingress 配置过于复杂。
ingress规则复用示例
# 子 Ingress:api-ingress(负责/api路径转发到api-service)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  namespace: default
spec:
  rules:
  - http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port: { number: 80 }

---
# 总 Ingress:root-ingress(通过Resource后端转发到api-ingress)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: root-ingress
  namespace: default
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          # Resource 后端(替代原来的 service 后端)
          resource:
            apiGroup: networking.k8s.io  # Ingress 所属的 API 组
            kind: Ingress                # 目标资源类型是 Ingress
            name: api-ingress            # 目标资源名称(同命名空间的子 Ingress)

2、service

  • 引用一个Service作为后端。与Resource互斥。有以下字段可以设置
       - name:被引用的Service名称。该Service必须与Ingress对象在同一个名称空间中。
       - port:被引用Service的端口号。

5.2、path

  • ingress.spec.rules.http.paths.path
                path:与请求的路径相匹配。路径必须以“/”开头。当未指定时,将匹配来自传入请求的所有路径。

5.3、pathType

  • ingress.spec.rules.http.paths.pathType
  • 支持的路径类型有三种:ImplementationSpecific、Exact和Prefix。
  • 精确匹配的规则优先于前缀匹配

ImplementationSpecific

  • 了解

Exact

  • 精确匹配 URL 路径,且区分大小写
  • 这个例子中,只会匹配/login路径,即使是/login/也不会匹配
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: exact-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /login
        pathType: Exact  # 仅匹配 /login
        backend:
          service:
            name: login-service
            port: { number: 80 }

Prefix

  • 基于以 / 分隔的 URL 路径前缀匹配。匹配区分大小写
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: prefix-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /api
        pathType: Prefix  # 匹配 /api、/api/user、/api/order 等
        backend:
          service:
            name: api-service
            port: { number: 80 }

6、默认后端

  • ingress.spec.defaultBackend
  • 一个没有设置rules的Ingress会将所有的请求发送到defaultbackend定义的默认后端。
  • defaultBackend通常是Ingress控制器的一个配置选项,不会在Ingress资源中指定。
  • 如果没有指定.spec.rules,则必须指定.spec.defaultbackend。如果defaultBackend没有设置,不匹配任何规则的请求的处理将由入口控制器。
  • 如果所有主机或路径都不匹配Ingress对象中的HTTP请求,流量将被路由到默认后端

7、ingress class

  • IngressClass 是 Kubernetes 中用于定义 Ingress 控制器类型的资源对象。
  • 它的核心作用是用于声明某个 Ingress 资源应该由哪个 Ingress Controller 处理。
  • 在 Kubernetes 早期版本中,指定控制器方式是通过 annotation,这种方式在k8s1.28中仍然兼容,但是不推荐使用
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  • 但是这种方式存在问题:非结构化(annotation 不受 schema 管理),不利于多控制器场景,不符合 API 规范化设计。所以从 Kubernetes 1.18 开始引入IngressClass 资源 + ingress.spec.ingressClassName 字段正式替代 annotation。
  • 一个集群可以同时运行 nginx、istio、 alb的ingress,每个都创建自己的 IngressClass,不同 Ingress 指向不同 class。

7.1、IngressClass 资源结构

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx   # Ingress 中 spec.ingressClassName 必须引用这个 name
spec:
  controller: k8s.io/ingress-nginx
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: example
  • spec.controller:格式通常为<domain>/<controller-name>
  • 这个字段决定哪个控制器监听并处理该 IngressClass
    • 例如:
    • Nginx Ingress控制器:k8s.io/ingress-nginx
    • Istio控制器:istio.io/ingress-controller

  • spec.parameters:让 IngressClass 关联一个自定义 CRD,不同 ingressclass 可以使用不同配置模板,多租户隔离场景常用

7.2、IngressClass 与 Ingress 的关系

  • 流程:Ingress → ingressClassName → IngressClass → controller → 对应控制器处理
  • ingress的yaml文件中指定了ingressclassname,通过这个name可以找到对应的ingressclass,class中spec.controller指定了控制器的名称,由该控制器处理路由规则
  • Ingress Controller 启动时,会监听特定 spec.controller 字段,只处理匹配该 controller 的 IngressClass,再处理关联的 Ingress 资源

7.3、默认 IngressClass

  • 可以这样设置一个默认 class:
metadata:
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
  • 作用:当 Ingress 未指定 ingressClassName,自动使用默认 IngressClass
  • 只能有一个默认 class,否则会冲突。

ingressclass 与 Istio 的关系

如果使用 Istio 的 ingresscontroller

  • ingressclass
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: istio
spec:
  controller: istio.io/ingress-controller
  • ingress
spec:
  ingressClassName: istio   # 与ingressclass的name一致
  • 这样,流量会交给 Istio ingress gateway 处理。
  • Istio 现在推荐使用Gateway API。而不是传统 Ingress。但 IngressClass 仍然支持。
  • ingress使用IngressClass,路由对象是ingress。gateway api使用GatewayClass,路由对象是HTTPRoute。后者在扩展能力和多租户支持方面更强

故障排查

常用排查命令

# 查看所有 class
kubectl get ingressclass

# 查看详情
kubectl describe ingressclass nginx

# 查看 Ingress 是否绑定
kubectl get ingress -o wide

Ingress 不生效的可能原因

  • gress没有指定ingressClassName
  • 不存在指定的IngressClass
  • ingressclass的spec.controller没有匹配控制器
  • 指定了多个默认 class
  • 同时指定了annotation 与 ingressClassName 冲突
posted @ 2024-05-10 10:26  立勋  阅读(29)  评论(0)    收藏  举报