UP | HOME

Ingress

Table of Contents

Ingress 是从 Kubernetes 集群外部 访问 集群内部服务 的入口。先澄清几个术语:

接下来还会讲到使用 Traefik 来做 Ingress controller,并给出了几个相关链接

定义

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

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

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

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

可以给 Ingress 配置提供外部可访问的 URL负载均衡SSL基于名称的虚拟主机 等:

  • 用户通过 POST Ingress 资源到 API server 的方式来请求 ingress
  • Ingress controller 负责实现 Ingress,通常使用 负载均衡器
    • 还可以配置边界路由和其他前端,这有助于以高可用的方式处理流量

前提

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

  • Ingress 资源对象在 Kubernetes 1.1 之前还没有
  • 需要一个 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
  • 1-4 行 :跟 Kubernetes 的其他配置一样,ingress 的配置也需要 apiVersion,kind 和 metadata 字段
  • 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 行 :backend 是一个 service:port 的组合。Ingress 的流量被转发到它所匹配的 backend
如果没有配置 Ingress controller 就将其 POST 到 API server 不会有任何用处

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

Ingress controller

为了使 Ingress 正常工作,集群中必须运行 Ingress controller:

  • Kubernetes 当前支持并维护 GCE 和 nginx 两种 controller
  • F5 公司 支持并维护 F5 BIG-IP Controller for Kubernetes
  • Kong 同时支持并维护 社区版 与 企业版 的 Kong Ingress Controller for Kubernetes
  • Traefik 是功能齐全的 ingress controller (Let’s Encrypt, secrets, http2, websocket…), Containous 也对其提供商业支持
  • Istio 使用 CRD Gateway 来 控制 Ingress 流量
这与其他类型的控制器不同,其他类型的控制器通常作为 kube-controller-manager 二进制文件的一部分运行,在集群启动时自动启动

用户需要选择最适合自己集群的 Ingress controller 或者自己实现一个

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

Ingress 类型

单 Service Ingress

Kubernetes 中已经存在一些概念可以暴露单个 service,但是仍然可以通过 Ingress 来实现

通过指定一个 没有 rule 的默认 backend 的方式:

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:一个没有 rule 的 ingress

如前面所示,所有流量都将发送到一个默认 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 扩展指定的主机名在多个相同端口上进行复用
  • 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
    

    请注意:

    • 各种 Ingress controller 支持的 TLS 功能之间存在差距
    • Ingress controller 启动时附带一些适用于所有 Ingress 的负载平衡策略设置,例如负载均衡算法,后端权重方案等

      更高级的负载平衡概念(例如持久会话,动态权重)尚未在 Ingress 中公开,只能通过 service loadbalancer 获取这些功能
      
      随着时间的推移,计划将适用于跨平台的负载平衡模式加入到 Ingress 资源中
      
    • 尽管健康检查不直接通过 Ingress 公开

      Kubernetes 中存在类似概念,例如 可用性探针,可以达成相同的最终结果
      

更新

假如想要向已有的 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 或者主机名
  • 结合 L4 和 L7 Ingress
  • 更多的 Ingress controller

替代方案

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

  • 使用 Service.Type=LoadBalancer
  • 使用 Service.Type=NodePort
  • 使用 Port Proxy
  • 部署一个 Service loadbalancer 这允许在多个 service 之间共享单个 IP,并通过 Service Annotations 实现更高级的负载平衡

Traefik

如果部署了 Traefik 作为 Ingress Controller,集群外部直接访问 Kubenetes 内部服务的话,可以直接创建 Ingress 如下所示:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: traefik-ingress
  namespace: default
spec:
  rules:
  - host: traefik.nginx.io
    http:
      paths:
      - path: /
	backend:
	  serviceName: my-nginx
	  servicePort: 80

与nginx 共存

当处于迁移应用到 Kubernetes 上的阶段时,可能有部分服务实例不在 Kubernetes上,服务的路由使用 Nginx 配置,这时处于 nginx 和 ingress 共存的状态。参考下面的配置:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: td-ingress
  namespace: default
  annotations:
    traefik.frontend.rule.type: PathPrefixStrip
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: "*.jimmysong.io"
    http:
      paths:
      - path: /docGenerate
	backend:
	  serviceName: td-sdmk-docgenerate
	  servicePort: 80

annotation 的配置:

  • traefik.frontend.rule.type: PathPrefixStrip 表示将截掉 URL 中的 path
  • kubernetes.io/ingress.class:traefik 表示使用的 ingress 类型

在 Nginx 中增加配置:

upstream docGenerate {
       server 172.20.0.119:80;
       keepalive 200;
}

172.20.0.119边缘节点的 VIP

Next: Service API Previous:拓扑感知路由 Home:服务发现和路由