【问题标题】:Istio Egresses with Kubernetes Services使用 Kubernetes 服务的 Istio 出口
【发布时间】:2018-08-22 10:18:10
【问题描述】:

(使用 Istio 0.5.1,kubectl 1.9.1/1.9.0 用于客户端/服务器,minikube 0.25.0)

我正在尝试让 Istio EgressRules 与 Kubernetes 服务一起使用,但遇到了一些问题。

我尝试通过 3 种方式设置 EgressRules:

  1. 指向另一个域的 ExternalName 服务(如 www.google.com)
  2. 没有选择器但有关联的服务 端点对象(用于具有 IP 地址但没有 DNS 的服务 姓名)
  3. (用于比较)没有 Kubernetes 服务,只是一个 EgressRule

我想我可以将 kubernetes 服务的 FQDN 用作基于 HTTP 的 EgressRule 目标服务(如 ext-service.default.svc.cluster.local),这就是我为 ExternalName 服务以及没有选择器但只有一个关联的 Endpoints 对象。

对于前者,我创建了以下yaml 文件:

kind: Service
apiVersion: v1
metadata:
  name: ext-service
spec:
  type: ExternalName
  externalName: www.google.com
---
apiVersion: config.istio.io/v1alpha2
kind: EgressRule
metadata:
  name: ext-egress-rule
spec:
  destination:
    service: ext-service.default.svc.cluster.local
  ports:
    - port: 443
      protocol: https

对于后者,我创建了这个 yaml 文件(我只是 ping 了 google 并获取了 IP 地址):

kind: Endpoints
apiVersion: v1
metadata:
  name: ext-service
subsets:
  - addresses:
      - ip: 216.58.198.78
    ports:
      - port: 443
---
kind: Service
apiVersion: v1
metadata:
  name: ext-service
spec:
  ports:
  - protocol: TCP
    port: 443
    targetPort: 443
---
apiVersion: config.istio.io/v1alpha2
kind: EgressRule
metadata:
  name: ext-service-egress-rule
spec:
  destination:
    service: ext-service.default.svc.cluster.local
  ports:
    - port: 443
      protocol: https

在这两种情况下,在应用程序代码中,我访问:

http://ext-service.default.svc.cluster.local:443

我的假设是流量会像这样流动:

[[ app -> envoy proxy -> (tls origination) -> kubernetes service ]] -> external service

[[ ... ]] 是服务网格的边界(也是 Kubernetes 集群)

结果:

  • ExternalName 服务几乎按预期工作,但它把我带到了 Google 的 404 页面(有时响应似乎是空的,不知道如何具体复制一个或另一个)李>
  • 带有 Endpoint 对象的服务不起作用,而是打印此消息(通过 Golang 发出请求时,但我认为这并不重要):

    获取http://ext-service.default.svc.cluster.local:443:EOF

    这有时也会给出一个空的响应。

出于以下几个原因,我想使用 Kubernetes 服务(即使它用于外部流量):

  1. 您不能将 IP 地址用于 EgressRule 的目标服务。来自Egress Rules configuration:“出口规则的目的地......可以是完全限定域名或通配符域名”。
  2. 对于没有域名的外部服务(一些没有 DNS 名称的本地遗留/整体服务),我希望应用程序能够不通过 IP 地址而是通过 kube- dns(或与 Istio 相关的类似名称)名称。
  3. (与上一个相关)我喜欢 Kubernetes 服务提供的额外抽象层,因此我可以在不更改 EgressRule 的情况下更改底层目标(除非我弄错了,这不是构建这个的正确方法) . EgressRule 是否旨在完全取代外部流量的 Kubernetes 服务,而不创建额外的 Kubernetes 服务?

在应用程序代码中使用 https:// 不是一个选项,因为这样请求将不得不禁用 TLS 验证,因为 kube-dns 名称与证书上的任何名称都不匹配。它也不会被观察到。

如果我使用以下 EgressRule(没有任何 Kubernetes 服务),通过 http://www.google.com:443 访问 Google 可以正常工作,获得我期望的准确 html 表示:

apiVersion: config.istio.io/v1alpha2
kind: EgressRule
metadata:
  name: google-egress-rule
spec:
  destination:
    service: www.google.com
  ports:
    - port: 443
      protocol: https

我看到有一个 TCP EgressRule,但我宁愿不必为每个 IP 块指定规则。来自TCP Egress:“在 TCP 出口规则中,与基于 HTTP 的出口规则相反,目的地由 IP 或 CIDR 表示法中的 IP 块指定。”。

另外,我仍然希望来自 L7 而不是 L4 的基于 HTTP 的可观察性,所以我更喜欢基于 HTTP 的出口。 (使用 TCP Egresses,“应用程序产生的 HTTPS 流量将被 Istio 视为不透明 TCP”)。

感谢任何帮助将 Kubernetes 服务作为 EgressRule 的“目标服务”(或帮助理解为什么在这种情况下不需要这样做)。谢谢!

【问题讨论】:

    标签: kubernetes istio


    【解决方案1】:

    解决办法是:

    1. 定义一个 Kubernetes ExternalName 服务以指向 www.google.com
    2. 不要定义任何 EgressRules
    3. 创建一个 RouteRule 来设置 Host 标头。

    在您的情况下,使用端口和协议定义一个 ExternalName 服务:

    kind: Service
    apiVersion: v1
    metadata:
      name: ext-service
    spec:
      type: ExternalName
      externalName: www.google.com
       ports:
       - port: 80
       # important to set protocol name
       name: http
    ---
    

    定义一个 HTTP 重写路由规则来设置 Host 头:

    apiVersion: config.istio.io/v1alpha2
    kind: RouteRule
    metadata:
      name: externalgoogle-rewrite-rule
      #namespace: default
    spec:
      destination:
        name: ext-service
      rewrite:
        authority: www.google.com
    ---
    

    然后用curl访问它,例如:curl ext-service

    如果没有路由规则,请求将到达 google.com,Host 标头为 ext-service。由于 google.com 没有这样的虚拟主机,因此 Web 服务器不知道将此类请求转发到何处。这就是你所经历的:

    它把我带到了 Google 的 404 页面

    【讨论】:

    • 这是有用的信息,但它仍然无法单独使用 ExternalName 访问 google。 curl 返回一个 404,类似于 Envoy 代理阻止请求时发生的情况。这似乎也发生在存在 RouteRule 的情况下。
    • 我检查了这个,两点。 1)你不能传递主机头,它不起作用,我的错误。您必须定义路由规则。 2) 您必须定义 ExternalName 服务的端口和协议。我已经更新了我的答案。
    • 好的,在将authority: google.com 更改为authority: www.google.com 后,我能够访问它,但似乎 envoy 代理不执行 TLS 发起,它只是通过 HTTP 进行连接。将 ExternalName 服务的端口更改为 443 并将其命名为 https 再次返回 404s。有什么方法可以通过 http 进行调用但让 Envoy 启动 TLS?感谢您的帮助
    • 对于 TLS 发起,您当前需要一个 Egress Rule。但它不适用于 Kubernetes ExternalName Service,因为证书不匹配。您描述的相同问题“在应用程序代码中使用 https:// 不是一个选项,因为这样请求将不得不禁用 TLS 验证,因为 kube-dns 名称与证书上的任何名称都不匹配。”你可以在github.com/istio/issues 上打开一个问题吗?我们之前有此功能,但已将其删除。
    • 另一种选择 - 您可以使用 IP 地址(不是 CIDR 块)作为 HTTP/HTTPS 出口规则的目标(应该改进文档)。但是你将无法通过路由规则重写权限头。
    猜你喜欢
    • 2018-11-16
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    相关资源
    最近更新 更多