Ingress官方文档(译)

308 阅读7分钟

定义

官方定义:管理外部请求(如典型的Http)对集群内服务访问的API对象

Ingress提供了负载均衡、SSL中断以及虚拟域名的服务

什么是Ingress

Ingress对外暴露Http和Https的路由,使得外部服务能够访问集群内的服务。路由规则则可以被定义Ingress的资源中。

Ingress流量转发示意图

Ingress能够为集群内服务提供外部可达的URLs,负载均衡控制,SSL/TSL的终端,以及基于名字的虚拟域名。而Ingress Controller则负责Ingress的实现,通常采用一种负载均衡器来实现,但也能够被用于配置边缘路由(edge router)或者前端路由。

Ingress不会暴露任意的端口和协议,通常情况下,在暴露除Http和Https协议外的服务时候往往采用类型为NodePort或者LoadBalancer的服务。

Ingress资源

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80

上面的代码块为Ingress的一个最小化实现,可以看到一共由apiVersion、kind、metadata、spec组成。此外,Ingress的名字必须为一个合法的DNS子域名。Ingress采用annotation来打通Ingress Controller,一般的配置都写在annotation中被Ingress Controller解读。如上述代码的"nginx.ingress.kubernetes.io/rewrite-target: /",但是不同的Ingress Controller支持的annotation也不尽相同。

Ingress的spec部分包含了所有随负载均衡器或者代理服务器的配置薪资。最重要的是该部分规定了外部请求的路由规则。Ingress资源仅仅支持Http或Https的直接流量。

如果ingressClassName缺失了,则会采用默认的Ingress Class。

此外一些Ingress Controller能够在不定义默认IngressClass的情况下工作。如Ingress-Nginx支持一个叫做--watch-ingress-without-class的盘配置。尽管如此,官方仍然建议还是定义一个默认的IngressClass。

Ingress Rules

一条Http(s)的路由规则包含以下三类配置:

  • 可供的域名。当不配置域名时,rule将对所有访问Ingress IP的Http(s)请求生效,而当配置了域名(如*.abc.com),rule将匹配请求域名。
  • 一个路径列表,当配置了host和路径时,需要路径和host同时被满足,才能请求到该规则对应的后端服务。此外要注意的是,Ingress采用的匹配逻辑是最长匹配。当请求路径为/test/abc/,而有rule1 路径为/ ,rule2路径为/test,此时该请求会被转发到rule2对应的后端服务。
  • 后端服务,该处需要填写服务名称以及端口。

通常情况下Ingress还会配置一个defaultBackend,用来处理那些没有匹配上任何规则的请求。

Path Types

pathType顾名思义为路径匹配的类型,当前Ingress支持以下三种pathType:

  • ImplementationSpecific:该类型的路径匹配取决于IngressClass的实现,其实现可能为前缀匹配,亦可能为精准匹配。
  • Exact:精准匹配。
  • Prefix:前缀匹配,要注意Ingress采用最长匹配原则。

域名通配符

Ingress支持域名以通配符的形式进行匹配,譬如*.abc.com,当请求域名为test.abc.com, good.abc.com都符合上述通配。但是foo.bar.abc.com,这是因为Ingress的*通配符只能够单个DNS标签,即被.分割的一个单词。

Ingress Class

通常情况下,IngressClass的实现和配置取决于不同的Ingress Controller。每一个Ingress都应该指定一个对IngressClass资源的引用,IngressClass资源则定义了用于实现IngressClass的IngressController的名称。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb
spec:
  controller: example.com/ingress-controller
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: external-lb

其中.spec.parameters引用了另外资源,该资源被用来配置IngressClass

而.spec.contoller则指定了用于实现IngressClass的IngressController的名称

一般情况下IngressClass的作用域为集群级别,但IngressClass也可以指定作用域为某个命名空间。在使用命名空间为作用域的IngressClass时候,需要在.spec.parameters.scope处配置作用域为Namespace,并且在spec.parameters.namespace处填入具体命名空间。

命名空间级别的IngressClass的好处

  • 每个团队只用关系自己命名空间下的IngressClass的配置
  • 可以使用kubernetes的RBAC进行管控,实现精细化的权限控制
集群级别IngressClass
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-1
spec:
  controller: example.com/ingress-controller
  parameters:
    # The parameters for this IngressClass are specified in a
    # ClusterIngressParameter (API group k8s.example.net) named
    # "external-config-1". This definition tells Kubernetes to
    # look for a cluster-scoped parameter resource.
    scope: Cluster
    apiGroup: k8s.example.net
    kind: ClusterIngressParameter
    name: external-config-1
 
命名级别IngressClass   
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-2
spec:
  controller: example.com/ingress-controller
  parameters:
    # The parameters for this IngressClass are specified in an
    # IngressParameter (API group k8s.example.com) named "external-config",
    # that's in the "external-configuration" namespace.
    scope: Namespace
    apiGroup: k8s.example.com
    kind: IngressParameter
    namespace: external-configuration
    name: external-config

Ingress的类型

单服务的Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  defaultBackend:
    service:
      name: test
      port:
        number: 80

如上的Ingres实际上绑定了一个服务名为service,端口为80的后端服务。通过kubectl apply -f可以创建该Ingress

NAME           CLASS         HOSTS   ADDRESS         PORTS   AGE
test-ingress   external-lb   *       203.0.113.123   80      59s

其中203.0.113.123为Ingress Contoler用于实现该Ingress的IP。

简单的多播(Simple fanout)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 4200
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 8080

上面的配置为上面的图片的实现,可以看到这里配置两个路径规则,满足前缀为/foo的将被转发到service1的4200端口,满足前缀为/bar的将被转发到service2的8080端口。

通过执行

kuberctl describe ingress simple-fanout-example

可以看到

Name:             simple-fanout-example
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:4200 (10.8.0.90:4200)
               /bar   service2:8080 (10.8.0.91:8080)
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     22s                loadbalancer-controller  default/test

只要service1和service2存在且合法,IngressController就会为这个Ingress创建一个负载均衡器来实现该资。

基于名字的虚拟域名(name based virtual hosting)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: bar.foo.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

根据上述配置,Ingress将会根据请求的域名来讲流量转发到对应后端。

此外当存在如下配置,service3对应rule没有配置域名,当请求同时不满足serice1和service2对应的rule是,service3的rule才生效。也就是当请求的host不为first.bar.com和second.bar.com时,流量才被转发到service3。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress-no-third-host
spec:
  rules:
  - host: first.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: second.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80
  - http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service3
            port:
              number: 80

TLS

在启用Ingress的TLS套件前,需要先创建一下的Secret用于保存证书。此外Ingress资源只支持端口为443的TLS端口,并Ingress为Https的终点(即服务到pod的流量是明文的)。如果Ingress中的TLS配置部分指定了不同的主机,则根据通过SNI TLS扩展指定的主机名(前提是Ingress控制器支持SNI),这些主机将在同一端口上多路传输。TLS机密必须包含名为TLS.crt和TLS.key的密钥,它们包含用于TLS的证书和私钥。例如:

apiVersion: v1
kind: Secret
metadata:
  name: testsecret-tls
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: kubernetes.io/tls

一个典型的启用了TLS的Ingress资源定义如下

为了确保TLS的生效,在tls部分配置的域名需要尽可能覆盖rule中配置的域名,即rule中的域名尽量是tls hosts中的域名或者子域名

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example-ingress
spec:
  tls:
  - hosts:
      - https-example.foo.com
    secretName: testsecret-tls
  rules:
  - host: https-example.foo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80

此外,每个IngressController的TLS实现细节也存在一定差异,需要在使用时候详细了解

负载均衡

Ingress控制器使用一些应用于所有Ingress的负载平衡策略设置进行引导,例如负载平衡算法、后端权重方案等。更高级的负载平衡概念(例如,持久会话、动态权重)尚未通过Ingress公开。相反,您可以通过用于服务的负载均衡器来获得这些功能。

同样值得注意的是,尽管健康检查不是直接通过Ingress公开的,但Kubernetes中存在类似的概念,如就绪探针,可以实现相同的最终结果。请查看控制器特定的文档,了解它们如何处理健康检查(例如:nginx或GCE)。