暴露 Istio Service Mesh 中的 Gateway


使用 Envoy 作为 Ingress Gateway 的前端代理

暴露 Istio Service Mesh 中的 Gateway

使用 Envoy 作为 Ingress Gateway 的前端代理

  • Kubernetes 知识图谱
  • 云原生导航
  • 谷歌搜索
  • Raft 协议动画演示
  • 搬瓦工

    在之前的文章 Istio 服务网格中的网关 中,我已经介绍了简单的暴露 Ingress Gateway 的方案。当时的方案只是用于临时测试,不适合在大规模场景下使用,本文将探讨更加优化的暴露 Ingress Gateway 的方案。

    HostNetwork


    第一种方法比较简单,可以直接使用 HostNetwork 模式运行 Ingress Gateway。但你会发现无法启动 ingressgateway 的 Pod,因为如果 Pod 设置了 HostNetwork=true,则 dnsPolicy 就会从 ClusterFirst 被强制转换成 Default。而 Ingress Gateway 启动过程中需要通过 DNS 域名连接 pilot 等其他组件,所以无法启动。

    我们可以通过强制将 dnsPolicy 的值设置为 ClusterFirstWithHostNet 来解决这个问题,详情参考:Kubernetes DNS 高阶指南

    修改后的 ingressgateway deployment 配置文件如下:

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: istio-ingressgateway
      namespace: istio-system
      ...
    spec:
      ...
      template:
        metadata:
        ...
        spec:
          affinity:
            nodeAffinity:
              ...
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: kubernetes.io/hostname
                    operator: In
                    values:
                    - 192.168.123.248   # 比如你想调度到这台主机上
          ...
          dnsPolicy: ClusterFirstWithHostNet
          hostNetwork: true
          restartPolicy: Always
          ...
    

    接下来我们就可以在浏览器中通过 Gateway 的 URL 来访问服务网格中的服务了。

    但是作为服务网格的流量接入层,Ingress Gateway 的高可靠性显得尤为重要,高可靠性首先要解决的就是单点故障问题,一般常用的是采用多副本部署的方式。而上述方案只适用于单实例(Deployment 的副本数为 1)的情况,为了适应多节点部署架构,需要寻求更好的暴露方案。

    使用 Envoy 作为前端代理


    我们已经知道,Ingress Gateway 实际上内部运行的是 Envoy 代理,我们可以在 Ingress Gateway 前面再加一层代理,这样就解决了高可用问题,你可以将 Ingress Gateway 的副本数扩展为多个,前端代理只需要通过 Service Name 来连接后端的 Gateway 就行了。同时建议采用独占节点的方式部署前端代理,以避免业务应用与前端代理服务发生资源争抢。

    前端代理可以使用一般的负载均衡软件(如 HaproxyNginx 等),也可以使用 Envoy。由于 Envoy 是 Istio Service Mesh 中默认的 data plane,所以这里推荐使用 Envoy。

    Envoy 官方提供了一组 Envoy 的用例,我们只需要用到其中的 Dockerfile。首先克隆 Envoy 的代码仓库并转到 examples/front-proxy 目录:

    $ git clone https://github.com/envoyproxy/envoy
    $ cd envoy/examples/front-proxy
    

    修改 front-envoy.yaml 配置文件,修改后的内容如下:

    static_resources:
      listeners:
      - address:
          socket_address:
            address: 0.0.0.0
            port_value: 80
        filter_chains:
        - filters:
          - name: envoy.tcp_proxy  ①
            config:
              stat_prefix: ingress_tcp
              cluster: ingressgateway
              access_log:
                - name: envoy.file_access_log
                  config:
                    path: /dev/stdout
      - address:
          socket_address:
            address: 0.0.0.0
            port_value: 443
        filter_chains:
        - filters:
          - name: envoy.tcp_proxy
            config:
              stat_prefix: ingress_tcp
              cluster: ingressgateway_tls
              access_log:
                - name: envoy.file_access_log
                  config:
                    path: /dev/stdout
      clusters:
      - name: ingressgateway
        connect_timeout: 0.25s
        type: strict_dns
        lb_policy: round_robin
        http2_protocol_options: {}
        hosts:
        - socket_address:
            address: istio-ingressgateway.istio-system  ②
            port_value: 80
      - name: ingressgateway_tls
        connect_timeout: 0.25s
        type: strict_dns
        lb_policy: round_robin
        http2_protocol_options: {}
        hosts:
        - socket_address:
            address: istio-ingressgateway.istio-system
            port_value: 443
    admin:
      access_log_path: "/dev/null"
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 8001
    
    • envoy.tcp_proxy 表示要实例化的过滤器的名称。该名称必须与内置支持的过滤器匹配,也就是说,该字段的值不可随意填写,必须使用指定的几个值。这里 envoy.tcp_proxy 表示使用 TCP 代理。详情参考:listener.Filter
    • istio-ingressgateway.istio-system 表示 Ingress Gateway 在集群内部的 DNS 域名。

    其他配置解析请参考:Envoy 的架构与基本术语

    接下来通过 Dockerfile-frontenvoyfront-envoy.yaml 来构建 Docker 镜像,我们来看下该 Dockerfile 的内容。

    FROM envoyproxy/envoy:latest
    
    RUN apt-get update && apt-get -q install -y \
        curl
    CMD /usr/local/bin/envoy -c /etc/front-envoy.yaml --service-cluster front-proxy
    

    其中 /etc/front-envoy.yaml 是本地的 front-envoy.yaml 挂载进去的。在 Kubernetes 中可以通过 ConfigMap 来挂载,所以我们还要创建一个 ConfigMap:

    $ kubectl -n istio-system create cm front-envoy --from-file=front-envoy.yaml
    

    你可以将构建好的镜像 push 到私有镜像仓库中或者公共仓库中,也可以使用我已经上传好的镜像。

    最后我们就可以通过该镜像来部署前端代理了,需要创建一个 Deployment,配置文件 front-envoy-deploy.yaml 内容如下:

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: front-envoy
    spec:
      replicas: 1
      template:
        metadata:
          labels:
            app: front-envoy
        spec:
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: kubernetes.io/hostname
                    operator: In
                    values:
                    - 192.168.123.248 # 比如你想调度到这台主机上
          containers:
          - name: front-envoy
            image: yangchuansheng/front-envoy
            ports:
            - containerPort: 80
            volumeMounts:
            - name: front-envoy
              mountPath: /etc/front-envoy.yaml
              subPath: front-envoy.yaml
          hostNetwork: true
          volumes:
            - name: front-envoy
              configMap:
                name: front-envoy
    

    你可以将镜像换成你自己的镜像,然后通过该 yaml 文件来部署:

    $ kubectl -n istio-system create -f front-envoy-deploy.yaml
    

    接下来我们就可以在浏览器中通过前端代理所在节点的 URL 来访问服务网格中的服务了。

    更一般的场景,我们还可以配置前端代理的高可用。对于 Kubernetes 集群以外只暴露一个访问入口,可以使用 keepalived 排除单节点问题。具体实现方式与 Ingress 的高可用类似,可以参考 Ingress 的高可用方案。


    https://hugo-picture.oss-cn-beijing.aliyuncs.com/images/wechat.gif
    扫一扫关注微信公众号


    -------他日江湖相逢 再当杯酒言欢-------

    「真诚赞赏,手留余香」

    米开朗基杨

    真诚赞赏,手留余香

    使用微信扫描二维码完成支付


    相关推荐