41.Ingress

Ingress

Ingress是从Kubernetes集群外部访问集群内部服务的入口,是将Kubernetes集群内部服务暴露到外界的几种方式之一。本文将为你详细介绍Ingress资源对象。

术语

在本篇文章中你将会看到一些在其他地方被交叉使用的术语,为了防止产生歧义,我们首先来澄清下。

  • 节点:Kubernetes集群中的一台物理机或者虚拟机。
  • 集群:位于Internet防火墙后的节点,这是Kubernetes管理的主要计算资源。
  • 边界路由器:为集群强制执行防火墙策略的路由器。这可能是由云提供商或物理硬件管理的网关。
  • 集群网络:一组逻辑或物理链接,可根据Kubernetes 网络模型 实现集群内的通信。集群网络的实现包括Overlay模型的 flannel 和基于SDNOVS
  • 服务:使用标签选择器标识一组pod成为的Kubernetes 服务。除非另有说明,否则服务假定在集群网络内仅可通过虚拟IP访问。

什么是Ingress

通常情况下,servicepod仅可在集群内部网络中通过IP地址访问。所有到达边界路由器的流量或被丢弃或被转发到其他地方。从概念上讲,可能像下面这样:

    internet
        |
  ------------
  [Services]

Ingress是授权入站连接到达集群服务的规则集合。

    internet
        |
   [Ingress]
   --|-----|--
   [Services]

你可以给Ingress配置提供外部可访问的URL、负载均衡、SSL、基于名称的虚拟主机等。用户通过POST Ingress资源到API server的方式来请求ingressIngress controller 负责实现Ingress,通常使用负载均衡器,它还可以配置边界路由和其他前端,这有助于以高可用的方式处理流量。

先决条件

在使用Ingress资源之前,有必要先了解下面几件事情。

  • 你需要一个 Ingress Controller 来实现 Ingress,单纯的创建一个 Ingress 没有任何意义。
  • GCE/GKE会在master节点上部署一个ingress controller。你可以在一个pod中部署任意个自定义的ingress controller。你必须正确地注解每个ingress,比如运行多个ingress controller和关闭glbc
  • 在非GCE/GKE的环境中,你需要在pod中部署一个controller,例如 Nginx Ingress Controller

Ingress资源

最简化的Ingress配置如下。

1: apiVersion: extensions/v1beta1
2: kind: Ingress
3: metadata:
4:   name: test-ingress
5: spec:
6:   rules:
7:   - http:
8:       paths:
9:       - path: /testpath
10:        backend:
11:           serviceName: test
12:           servicePort: 80

如果你没有配置Ingress controller就将其POSTAPI server不会有任何用处。

配置说明

1-4:跟Kubernetes的其他配置一样,ingress的配置也需要 apiVersionkindmetadata 字段。配置文件的详细说明请查看 部署应用配置容器 和使用资源。

5-7: Ingress spec中包含配置一个loadbalancerproxy server的所有信息。最重要的是,它包含了一个匹配所有入站请求的规则列表。目前ingress只支持http规则。

8-9:每条http规则包含以下信息:一个 host 配置项(比如for.bar.com,在这个例子中默认是*path 列表(比如:/testpath,每个path都关联一个backend(比如test:80)。在loadbalancer将流量转发到backend之前,所有的入站请求都要先匹配hostpath

10-12:正如 services doc 中描述的那样,backend是一个 service:port 的组合。Ingress的流量被转发到它所匹配的backend

全局参数:为了简单起见,Ingress示例中没有全局参数,请参阅资源完整定义的 API参考。在所有请求都不能跟spec中的path匹配的情况下,请求被发送到Ingress controller的默认后端,可以指定全局缺省backend

IngressClass

Ingress可以由不同的控制器实现,通常使用不同的配置。每个Ingress应当指定一个类,也就是一个对IngressClass资源的引用。IngressClass资源包含额外的配置,其中包括应当实现该类的控制器名称。下面是一个IngressClass示例。

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

IngressClass中的 .spec.parameters 字段可用于引用其他资源以提供额外的相关配置。

参数(parameters)的具体类型取决于你在 .spec.controller 字段中指定的Ingress控制器。

IngressClass的作用域

IngressClass的作用域取决于你的Ingress控制器,可以使用集群范围也可以是某个命名空间。

IngressClass的默认作用于是集群级别,关于IngressClass作用域的详细使用说明请见 Ingress文档

默认IngressClass

你可以将一个特定的IngressClass标记为集群默认IngressClass。将一个IngressClass资源的 ingressclass.kubernetes.io/is-default-class 注解设置为 true 将确保新的未指定 ingressClassName 字段的Ingress能够分配为这个默认的IngressClass。集群中最多只能有一个IngressClass被标记为默认。

kubernetes.io/ingress.class 注解

Kubernetes 1.18版本引入IngressClass资源和 ingressClassName 字段之前,Ingress类是通过Ingress中的一个 kubernetes.io/ingress.class 注解来指定的。这个注解从未被正式定义过,但是得到了 Ingress控制器的广泛支持。

ingressClassName 配置项是该注解的替代品,但并不完全等价。该注解通常用于引用实现该Ingress的控制器的名称,而这个新的字段则是对一个包含额外Ingress配置的IngressClass资源的引用,包括Ingress控制器的名称。

Ingress类型

以下文档描述了Ingress资源中公开的一组跨平台功能。理想情况下,所有的Ingress controller都应该符合这个规范,但是目前还没有实现。

注意

确保您查看控制器特定的文档,以便您了解每个文档的注意事项。

Service Ingress

Kubernetes中已经存在一些概念可以暴露单个service(查看 替代方案,但是你仍然可以通过Ingress来实现,通过指定一个没有rule的默认backend的方式。

ingress.yaml定义文件:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  backend:
    serviceName: testsvc
    servicePort: 80

使用kubectl create -f命令创建,然后查看ingress

$ kubectl get ing
NAME                RULE          BACKEND        ADDRESS
test-ingress        -             testsvc:80     107.178.254.228

107.178.254.228 就是Ingress controller为了实现Ingress而分配的IP地址。RULE 列表示所有发送给该IP的流量都被转发到了 BACKEND 所列的Kubernetes service上。

简单展开

如前面描述的那样,kubernetes pod中的IP只在集群网络内部可见,我们需要在边界设置一个东西,让它能够接收ingress的流量并将它们转发到正确的端点上。这个东西一般是高可用的loadbalancer。使用Ingress能够允许你将loadbalancer的个数降低到最少,例如,假如你想要创建这样的一个设置:

foo.bar.com -> 178.91.123.132 -> /foo    s1:80
                                 /bar    s2:80

你需要一个这样的ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  rules:
    - host: foo.bar.com
      http:
        paths:
          - path: /foo
            backend:
              serviceName: s1
              servicePort: 80
          - path: /bar
            backend:
              serviceName: s2
              servicePort: 80

使用 kubectl create -f 创建完ingress后:

$ kubectl get ing
NAME      RULE          BACKEND   ADDRESS
test      -
					foo.bar.com
					/foo          s1:80
					/bar          s2:80

只要服务(s1,s2)存在,Ingress controller就会将提供一个满足该Ingress的特定loadbalancer实现。这一步完成后,您将在Ingress的最后一列看到loadbalancer的地址。

基于名称的虚拟主机

Name-based的虚拟主机在同一个IP地址下拥有多个主机名。

foo.bar.com --|                 |-> foo.bar.com s1:80
              | 178.91.123.132  |
bar.foo.com --|                 |-> bar.foo.com s2:80

下面这个ingress说明基于 Host header 的后端loadbalancer的路由请求:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  rules:
    - host: foo.bar.com
      http:
        paths:
          - backend:
              serviceName: s1
              servicePort: 80
    - host: bar.foo.com
      http:
        paths:
          - backend:
              serviceName: s2
              servicePort: 80

默认backend:一个没有ruleingress,如前面章节中所示,所有流量都将发送到一个默认backend。你可以用该技巧通知loadbalancer如何找到你网站的404页面,通过制定一些列rule和一个默认backend的方式。如果请求header中的host不能跟ingress中的host匹配,并且/或请求的URL不能与任何一个path匹配,则流量将路由到你的默认backend

TLS

你可以通过指定包含TLS私钥和证书的 secret 来加密Ingress。目前,Ingress仅支持单个TLS端口443,并假定TLS termination。如果Ingress中的TLS配置部分指定了不同的主机,则它们将根据通过SNI TLS扩展指定的主机名(假如Ingress controller支持SNI)在多个相同端口上进行复用。TLS secret中必须包含名为 tls.crttls.key 的密钥,这里面包含了用于TLS的证书和私钥,例如:

apiVersion: v1
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
kind: Secret
metadata:
  name: testsecret
  namespace: default
type: Opaque

Ingress中引用这个secret将通知Ingress controller使用TLS加密从将客户端到loadbalancerchannel

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: no-rules-map
spec:
  tls:
    - secretName: testsecret
  backend:
    serviceName: s1
    servicePort: 80

请注意,各种Ingress controller支持的TLS功能之间存在差距。请参阅有关 nginxGCE 或任何其他平台特定Ingress controller的文档,以了解TLS在你的环境中的工作原理。

Ingress controller启动时附带一些适用于所有Ingress的负载平衡策略设置,例如负载均衡算法,后端权重方案等。更高级的负载平衡概念(例如持久会话,动态权重)尚未在Ingress中公开。你仍然可以通过service loadbalancer获取这些功能。随着时间的推移,我们计划将适用于跨平台的负载平衡模式加入到Ingress资源中。

还值得注意的是,尽管健康检查不直接通过Ingress公开,但Kubernetes中存在并行概念,例如 准备探查,可以使你达成相同的最终结果。请查看特定控制器的文档,以了解他们如何处理健康检查(nginxGCE

更新Ingress

假如你想要向已有的ingress中增加一个新的Host,你可以编辑和更新该ingress

$ kubectl get ing
NAME      RULE          BACKEND   ADDRESS
test      -                       178.91.123.132
          foo.bar.com
          /foo          s1:80
$ kubectl edit ing test

这会弹出一个包含已有的yaml文件的编辑器,修改它,增加新的Host配置。

spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          serviceName: s1
          servicePort: 80
        path: /foo
  - host: bar.baz.com
    http:
      paths:
      - backend:
          serviceName: s2
          servicePort: 80
        path: /foo
..

保存它会更新API server中的资源,这会触发ingress controller重新配置loadbalancer

$ kubectl get ing
NAME      RULE          BACKEND   ADDRESS
test      -                       178.91.123.132
          foo.bar.com
          /foo          s1:80
          bar.baz.com
          /foo          s2:80

在一个修改过的ingress yaml文件上调用kubectl replace -f 命令一样可以达到同样的效果。

跨可用域故障

在不同云供应商之间,跨故障域的流量传播技术有所不同。有关详细信息,请查看相关Ingress controller的文档。有关在federation集群中部署Ingress的详细信息,请参阅federation文档。

未来计划

  • 多样化的HTTPS/TLS模型支持(如SNI,re-encryption)
  • 通过声明来请求IP或者主机名
  • 结合L4L7 Ingress
  • 更多的Ingress controller

请跟踪 L7Ingressproposal,了解有关资源演进的更多细节,以及 Ingress repository,了解有关各种Ingress controller演进的更多详细信息。

替代方案

你可以通过很多种方式暴露service而不必直接使用ingress

参考

上一页
下一页