使用Kubernetes服务进行出口

时间:2018-03-14 01:17:50

标签: kubernetes istio

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

我试图让Istio EgressRules与Kubernetes Services合作,但遇到了一些麻烦。

我试图以3种方式设置EgressRules:

  1. 指向另一个域的ExternalName服务(如 www.google.com)
  2. 没有选择器但关联的服务 端点对象(适用于具有IP地址但没有DNS的服务 名)
  3. (作比较)没有Kubernetes服务,只是一个EgressRule
  4. 我想我可以使用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. 您无法为EgressRule的目标服务使用IP地址。来自Egress Rules configuration:"出口规则的目的地......可以是完全限定的或通配符域名"。
    2. 对于没有域名的外部服务(一些没有DNS名称的本地传统/整体服务),我希望应用程序能够访问它们而不是通过IP地址访问它们通过kube-dns(或与Istio相关的类似名称)。
    3. (与之前相关)我喜欢Kubernetes服务提供的额外抽象层,所以我可以在不改变EgressRule的情况下更改基础目的地(除非我错了,这不是正确的方法建筑师这个)。 EgressRule是否意味着完全取代Kubernetes服务以获得外部流量,而无需创建额外的Kubernetes服务?
    4. 在应用代码中使用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块指定。"。

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

      任何帮助获得Kubernetes服务作为"目的地服务"一个EgressRule(或帮助理解为什么这不是必要的,如果是这种情况)被赞赏。谢谢!

1 个答案:

答案 0 :(得分:1)

解决方案是:

  1. 定义Kubernetes ExternalName服务以指向www.google.com
  2. 不要定义任何EgressRules
  3. 创建RouteRule以设置主机标头。
  4. 在您的情况下,使用端口和协议定义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重写路由规则以设置主机头:

    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,主机标头为ext-service。由于google.com没有这样的虚拟主机,因此Web服务器不知道转发此类请求的位置。这就是你所经历的:

      

    它将我带到了Google的404页面