Ingress

提示:
本文对 Ingress 进行基础性的介绍,更深入的细节请访问 Ingress 专题

Ingress 是提供了除 Service 之外的另一种从 Kubernetes 集群外部访问集群内部服务的解决方案。

Ingress 是 Kubernetes 集群中的一种 API 资源,只是一种资源配置,本身并不会提供服务。实际功能由 ingress-controller 提供,一般是以 hostNetwork 的方式部署运行,监听 80/443 端口,以域名的虚拟机方式对外提供7层的代理服务。常见的 ingress-controller 有 nginx-ingress-controlle 、Traefik-ingress-controller等。

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

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

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

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

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

Ingress Spec

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  rules:
  - host: test-ingress.mydomain.com
    http:
      paths: /test
      - backend:
          serviceName: test-ingress
          servicePort: 80

rules

spec.rules 定义了一个列表,每个列表项是一个包含一套相关访问规则配置。

  • rules.host : 定义服务的域名,和 nginx 的虚拟机主机功能类似,通过域名来区分后端的服务。
  • rules.http : 定义路由及后端资源。
  • rules.http.paths : 定义路由或 path,可以类比 nginx 的 Location 配置项。
  • rules.http.paths.backend : 定义路由转发的后端服务,详见 spec.backend

backend

  backend:
    serviceName: test-ingress
        servicePort: 80

spec.backend 定义当前 host 服务的后端。

  • serviceName 是 Kubernetes 的 Service 资源的名称,这里只是通过 Service 名称获取到后端的 Endpoints 列表,路由请求代理时是 Ingress-controller 直接转发给 Pod,而不是转发给 Service 的 ClusterIP。
  • servicePort: 服务端口,默认是80。该端口是由 Ingress-controller 启动参数配置的监听端口,其他未监听的端口配置是无效的。

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 加密从将客户端到 loadbalancer 的 channel:

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

如果配置 tls 的 Ingress 未指定具体 rules 时,这该 tls 是全局的,或者说是默认的。在有明确的 rules 时,会优先使用其ingress 中配置的 tls。

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

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

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

扩展阅读

术语

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

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

先决条件

在使用 Ingress resource之前,有必要先了解下面几件事情。Ingress是beta版本的resource,在kubernetes1.1之前还没有。你需要一个Ingress Controller来实现Ingress,单纯的创建一个Ingress没有任何意义。

GCE/GKE会在master节点上部署一个ingress controller。你可以在一个pod中部署任意个自定义的ingress controller。你必须正确地annotate每个ingress,比如 运行多个ingress controller 和 关闭glbc。

确定你已经阅读了Ingress controller的 beta版本限制。在非GCE/GKE的环境中,你需要在pod中部署一个controller

Ingress controllers

为了使 Ingress 正常工作,集群中必须运行 Ingress controller。 这与其他类型的控制器不同,其他类型的控制器通常作为kube-controller-manager 二进制文件的一部分运行,在集群启动时自动启动。 你需要选择最适合自己集群的Ingress controller或者自己实现一个。

在你开始前

以下文档描述了 Ingress 资源中公开的一组跨平台功能。 理想情况下,所有的 Ingress controller 都应该符合这个规范,但是我们还没有实现。 GCE 和 nginx 控制器的文档分别在这里这里。如果您使用 F5 BIG-IP controller, 请参看这里. 确保您查看控制器特定的文档,以便您了解每个文档的注意事项。

跨可用域故障

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

未来计划

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

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

替代方案

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

基于名称的虚拟主机

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

Ingress类型

单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 的地址。

更新Ingress

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

注意: 更新 Ingress 配置不需要重启 Ingress-controller,Ingress-controller 会 watch 配置的变化自动重载配置文件。

$ 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 命令一样可以达到同样的效果。

参考